Skip to content

Commit

Permalink
Pass API key through to API call.
Browse files Browse the repository at this point in the history
Show helpful error message in the case the user doesn't have sufficient
API access to read from a non-demo company.
  • Loading branch information
EarningsCall committed May 27, 2024
1 parent 66c73c2 commit 10b8ae8
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 25 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,19 @@ By default, this library grants you access to only two companies, Apple Inc. and

To gain access 5,000+ companies please [signup here](https://earningscall.biz/api-pricing) to get your API key.

Once you have access to your API key.
Once you have access to your API key, you can set the API Key like this:

```python

import earningscall


earningscall.api_key = "YOUR SECRET API KEY GOES HERE"
```
```

Alternatively, you can pass in your API key as an environment variable:

```sh
export ECALL_API_KEY="YOUR SECRET API KEY GOES HERE"
python your-python-script.py
```
11 changes: 9 additions & 2 deletions earningscall/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def get_api_key():
return api_key


def is_demo_account():
return get_api_key() == "demo"


def get_events(exchange: str,
symbol: str):

Expand All @@ -41,7 +45,7 @@ def get_transcript(exchange: str,

log.debug(f"get_transcript year: {year} quarter: {quarter}")
params = {
"apikey": "demo",
"apikey": get_api_key(),
"exchange": exchange,
"symbol": symbol,
"year": str(year),
Expand All @@ -61,7 +65,10 @@ def get_symbols_v1():


def get_symbols_v2():
response = requests.get(f"{API_BASE}/symbols-v2.txt")
params = {
"apikey": get_api_key(),
}
response = requests.get(f"{API_BASE}/symbols-v2.txt", params=params)
if response.status_code != 200:
return None
return response.text
4 changes: 3 additions & 1 deletion earningscall/company.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ class Company:
name: str
_events: [EarningsEvent]

def __init__(self, company_info):
def __init__(self, company_info: CompanyInfo):
if not company_info:
raise ValueError("company_info must be present.")
self.company_info = company_info
self.name = company_info.name
self._events = None
Expand Down
6 changes: 5 additions & 1 deletion earningscall/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,9 @@ class ClientError(BaseError):
status: int = 400 # https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400


class MissingApiKeyError(ClientError):
class InsufficientApiAccessError(ClientError):
pass


class CompanyNotFound(ClientError):
pass
9 changes: 7 additions & 2 deletions earningscall/exports.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
from typing import Optional

from earningscall.symbols import get_symbols

from earningscall.company import Company


def get_company(symbol: str) -> Company:
return Company(company_info=get_symbols().lookup_company(symbol))
def get_company(symbol: str) -> Optional[Company]:
company_info = get_symbols().lookup_company(symbol)
if company_info:
return Company(company_info=company_info)
return None


def get_all_companies() -> [Company]:
Expand Down
11 changes: 10 additions & 1 deletion earningscall/symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from collections import defaultdict
from typing import Optional

from earningscall.api import get_symbols_v2
from earningscall.api import get_symbols_v2, is_demo_account
from earningscall.errors import InsufficientApiAccessError
from earningscall.sectors import sector_to_index, industry_to_index, index_to_sector, index_to_industry

# WARNING: Add new indexes to the *END* of this list
Expand Down Expand Up @@ -127,6 +128,9 @@ def lookup_company(self, symbol: str) -> Optional[CompanyInfo]:
return _symbol
except KeyError:
pass
if is_demo_account():
raise InsufficientApiAccessError(f"For full access, please get an API Key. See: "
f"https://earningscall.biz/api-pricing")
return None

def remove_exchange_symbol(self, exchange_symbol: str):
Expand Down Expand Up @@ -224,3 +228,8 @@ def get_symbols() -> Symbols:
if not _symbols:
_symbols = load_symbols()
return _symbols


def clear_symbols():
global _symbols
_symbols = None
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "earningscall"
version = "0.0.4"
version = "0.0.5"
description = "The EarningsCall Python library."
readme = "README.md"
authors = [
Expand Down
8 changes: 8 additions & 0 deletions tests/data/demo-symbols-v2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
responses:
- response:
auto_calculate_content_length: false
body: "1\tAAPL\tApple Inc.\t9\t30\n1\tMSFT\tMicrosoft Corporation\t-1\t-1"
content_type: text/plain
method: GET
status: 200
url: https://v2.api.earningscall.biz/symbols-v2.txt?apikey=demo
37 changes: 25 additions & 12 deletions tests/test_get_transcript.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import pytest
import responses

from earningscall import get_company
from earningscall.errors import InsufficientApiAccessError
from earningscall.symbols import clear_symbols
from earningscall.utils import data_path


# Uncomment following code to generate msft-transcript-response.yaml file
# Uncomment and run following code to generate msft-transcript-response.yaml file
#
# from responses import _recorder
# @_recorder.record(file_path="msft-transcript-response.yaml")
Expand All @@ -15,6 +18,7 @@
@responses.activate
def test_get_demo_company():
##
clear_symbols()
responses._add_from_file(file_path=data_path("symbols-v2.yaml"))
responses._add_from_file(file_path=data_path("msft-transcript-response.yaml"))
##
Expand All @@ -25,14 +29,23 @@ def test_get_demo_company():
'Conference Call. At ')


# @responses.activate
# def test_get_non_demo_company():
# ##
# responses._add_from_file(file_path=data_path("symbols-v2.yaml"))
# # responses._add_from_file(file_path=data_path("msft-transcript-response.yaml"))
# ##
# company = get_company("nvda")
# ##
# transcript = company.get_transcript(year=2023, quarter=1)
# assert transcript.text[:100] == ('Greetings, and welcome to the Microsoft Fiscal Year 2023 First Quarter Earnings '
# 'Conference Call. At ')
# Uncomment and run following code to generate demo-symbols-v2.yaml file
#
# import requests
#
# from responses import _recorder
#
#
# @_recorder.record(file_path="demo-symbols-v2.yaml")
# def test_save_symbols_v1():
# requests.get("https://v2.api.earningscall.biz/symbols-v2.txt?apikey=demo")


@responses.activate
def test_get_non_demo_company():
##
clear_symbols()
responses._add_from_file(file_path=data_path("demo-symbols-v2.yaml"))
##
with pytest.raises(InsufficientApiAccessError):
get_company("nvda")
4 changes: 1 addition & 3 deletions tests/test_symbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
def test_load_symbols_txt_v2():
##
responses.patch(API_BASE)
print("symbols path")
print(data_path("symbols-v2.yaml"))
responses._add_from_file(file_path=data_path("symbols-v2.yaml"))
##
symbols = Symbols.load_txt_v2()
Expand All @@ -22,7 +20,7 @@ def test_load_symbols_txt_v2():
assert _symbol.sector == "Technology"
assert _symbol.industry == "Consumer Electronics"
assert len(responses.calls) == 1
assert responses.calls[0].request.url == "https://v2.api.earningscall.biz/symbols-v2.txt"
assert responses.calls[0].request.url == "https://v2.api.earningscall.biz/symbols-v2.txt?apikey=demo"


def test_symbols_serialization_to_text_v2():
Expand Down

0 comments on commit 10b8ae8

Please sign in to comment.