earningscall 0.0.10__py3-none-any.whl → 0.0.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- earningscall/__init__.py +2 -0
- earningscall/api.py +8 -6
- earningscall/company.py +16 -16
- earningscall/errors.py +1 -2
- earningscall/event.py +3 -2
- earningscall/exports.py +4 -4
- earningscall/sectors.py +5 -8
- earningscall/symbols.py +32 -19
- {earningscall-0.0.10.dist-info → earningscall-0.0.13.dist-info}/METADATA +3 -5
- earningscall-0.0.13.dist-info/RECORD +14 -0
- earningscall-0.0.10.dist-info/RECORD +0 -14
- {earningscall-0.0.10.dist-info → earningscall-0.0.13.dist-info}/WHEEL +0 -0
- {earningscall-0.0.10.dist-info → earningscall-0.0.13.dist-info}/licenses/LICENSE +0 -0
earningscall/__init__.py
CHANGED
earningscall/api.py
CHANGED
@@ -27,8 +27,7 @@ def is_demo_account():
|
|
27
27
|
return get_api_key() == "demo"
|
28
28
|
|
29
29
|
|
30
|
-
def get_events(exchange: str,
|
31
|
-
symbol: str):
|
30
|
+
def get_events(exchange: str, symbol: str):
|
32
31
|
|
33
32
|
log.debug(f"get_events exchange: {exchange} symbol: {symbol}")
|
34
33
|
params = {
|
@@ -42,10 +41,7 @@ def get_events(exchange: str,
|
|
42
41
|
return response.json()
|
43
42
|
|
44
43
|
|
45
|
-
def get_transcript(exchange: str,
|
46
|
-
symbol: str,
|
47
|
-
year: int,
|
48
|
-
quarter: int) -> Optional[str]:
|
44
|
+
def get_transcript(exchange: str, symbol: str, year: int, quarter: int) -> Optional[str]:
|
49
45
|
|
50
46
|
log.debug(f"get_transcript year: {year} quarter: {quarter}")
|
51
47
|
params = {
|
@@ -80,3 +76,9 @@ def get_sp500_companies_txt_file():
|
|
80
76
|
if response.status_code != 200:
|
81
77
|
return None
|
82
78
|
return response.text
|
79
|
+
|
80
|
+
|
81
|
+
# def do_something():
|
82
|
+
# session = CachedSession('demo_cache', cache_control=True)
|
83
|
+
#
|
84
|
+
# # CachedSession()
|
earningscall/company.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
from typing import Optional
|
2
|
+
from typing import Optional, List
|
3
3
|
|
4
4
|
from earningscall import api
|
5
5
|
from earningscall.event import EarningsEvent
|
@@ -12,8 +12,8 @@ log = logging.getLogger(__file__)
|
|
12
12
|
class Company:
|
13
13
|
|
14
14
|
company_info: CompanyInfo
|
15
|
-
name: str
|
16
|
-
_events: [EarningsEvent]
|
15
|
+
name: Optional[str]
|
16
|
+
_events: Optional[List[EarningsEvent]]
|
17
17
|
|
18
18
|
def __init__(self, company_info: CompanyInfo):
|
19
19
|
if not company_info:
|
@@ -25,31 +25,31 @@ class Company:
|
|
25
25
|
def __str__(self):
|
26
26
|
return str(self.name)
|
27
27
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
def _get_events(self):
|
28
|
+
def _get_events(self) -> List[EarningsEvent]:
|
29
|
+
if not self.company_info.exchange or not self.company_info.symbol:
|
30
|
+
return []
|
32
31
|
raw_response = api.get_events(self.company_info.exchange, self.company_info.symbol)
|
33
32
|
if not raw_response:
|
34
33
|
return []
|
35
|
-
return [EarningsEvent.from_dict(event) for event in raw_response["events"]]
|
34
|
+
return [EarningsEvent.from_dict(event) for event in raw_response["events"]] # type: ignore
|
36
35
|
|
37
|
-
def events(self) -> [EarningsEvent]:
|
36
|
+
def events(self) -> List[EarningsEvent]:
|
38
37
|
if not self._events:
|
39
38
|
self._events = self._get_events()
|
40
39
|
return self._events
|
41
40
|
|
42
|
-
def get_transcript(
|
43
|
-
|
44
|
-
|
45
|
-
event: Optional[EarningsEvent] = None) -> Optional[Transcript]:
|
41
|
+
def get_transcript(
|
42
|
+
self, year: Optional[int] = None, quarter: Optional[int] = None, event: Optional[EarningsEvent] = None
|
43
|
+
) -> Optional[Transcript]:
|
46
44
|
|
45
|
+
if not self.company_info.exchange or not self.company_info.symbol:
|
46
|
+
return None
|
47
47
|
if (not year or not quarter) and event:
|
48
48
|
year = event.year
|
49
49
|
quarter = event.quarter
|
50
|
-
|
50
|
+
if (not year or not quarter) and not event:
|
51
51
|
raise ValueError("Must specify either event or year and quarter")
|
52
|
-
resp = api.get_transcript(self.company_info.exchange, self.company_info.symbol, year, quarter)
|
52
|
+
resp = api.get_transcript(self.company_info.exchange, self.company_info.symbol, year, quarter) # type: ignore
|
53
53
|
if not resp:
|
54
54
|
return None
|
55
|
-
return Transcript.from_dict(resp)
|
55
|
+
return Transcript.from_dict(resp) # type: ignore
|
earningscall/errors.py
CHANGED
earningscall/event.py
CHANGED
@@ -16,6 +16,7 @@ class EarningsEvent:
|
|
16
16
|
"""
|
17
17
|
EarningsEvent
|
18
18
|
"""
|
19
|
+
|
19
20
|
year: int
|
20
21
|
quarter: int
|
21
22
|
conference_date: Optional[datetime] = field(
|
@@ -23,6 +24,6 @@ class EarningsEvent:
|
|
23
24
|
metadata=config(
|
24
25
|
encoder=lambda date: date.isoformat() if date else None,
|
25
26
|
decoder=lambda date: datetime.fromisoformat(date) if date else None,
|
26
|
-
mm_field=fields.DateTime(format="iso")
|
27
|
-
)
|
27
|
+
mm_field=fields.DateTime(format="iso"),
|
28
|
+
),
|
28
29
|
)
|
earningscall/exports.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import Optional
|
1
|
+
from typing import Optional, Iterator
|
2
2
|
|
3
3
|
from earningscall.api import get_sp500_companies_txt_file
|
4
4
|
from earningscall.company import Company
|
@@ -12,15 +12,15 @@ def get_company(symbol: str) -> Optional[Company]:
|
|
12
12
|
return None
|
13
13
|
|
14
14
|
|
15
|
-
def get_all_companies() -> [Company]:
|
15
|
+
def get_all_companies() -> Iterator[Company]:
|
16
16
|
for company_info in get_symbols().get_all():
|
17
17
|
yield Company(company_info=company_info)
|
18
18
|
|
19
19
|
|
20
|
-
def get_sp500_companies() -> [Company]:
|
20
|
+
def get_sp500_companies() -> Iterator[Company]:
|
21
21
|
resp = get_sp500_companies_txt_file()
|
22
22
|
if not resp:
|
23
|
-
return
|
23
|
+
return
|
24
24
|
for ticker_symbol in resp.split("\n"):
|
25
25
|
company_info = get_symbols().lookup_company(ticker_symbol)
|
26
26
|
if company_info:
|
earningscall/sectors.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import logging
|
3
|
-
|
3
|
+
from typing import Optional
|
4
4
|
|
5
5
|
log = logging.getLogger(__file__)
|
6
6
|
sectors_file_name = "sectors.json"
|
@@ -17,7 +17,7 @@ SECTORS_IN_ORDER = [
|
|
17
17
|
'Industrials',
|
18
18
|
'Real Estate',
|
19
19
|
'Technology',
|
20
|
-
'Utilities'
|
20
|
+
'Utilities',
|
21
21
|
]
|
22
22
|
|
23
23
|
|
@@ -166,7 +166,7 @@ INDUSTRIES_IN_ORDER = [
|
|
166
166
|
'Utilities - Regulated Gas',
|
167
167
|
'Utilities - Regulated Water',
|
168
168
|
'Utilities - Renewable',
|
169
|
-
'Waste Management'
|
169
|
+
'Waste Management',
|
170
170
|
]
|
171
171
|
|
172
172
|
|
@@ -198,9 +198,7 @@ def industry_to_index(_industry: str) -> int:
|
|
198
198
|
|
199
199
|
class Sectors:
|
200
200
|
|
201
|
-
def __init__(self,
|
202
|
-
sectors: set = None,
|
203
|
-
industries: set = None):
|
201
|
+
def __init__(self, sectors: Optional[set] = None, industries: Optional[set] = None):
|
204
202
|
if sectors:
|
205
203
|
self.sectors = sectors
|
206
204
|
else:
|
@@ -218,7 +216,7 @@ class Sectors:
|
|
218
216
|
if industry is not None:
|
219
217
|
self.industries.add(industry)
|
220
218
|
|
221
|
-
def to_dicts(self) ->
|
219
|
+
def to_dicts(self) -> dict:
|
222
220
|
return {
|
223
221
|
"sectors": list(self.sectors),
|
224
222
|
"industries": list(self.industries),
|
@@ -231,4 +229,3 @@ class Sectors:
|
|
231
229
|
def from_json(json_str):
|
232
230
|
data = json.loads(json_str)
|
233
231
|
return Sectors(set(data["sectors"]), set(data["industries"]))
|
234
|
-
|
earningscall/symbols.py
CHANGED
@@ -2,7 +2,7 @@ import json
|
|
2
2
|
import logging
|
3
3
|
import re
|
4
4
|
from collections import defaultdict
|
5
|
-
from typing import Optional
|
5
|
+
from typing import Optional, Iterator, List
|
6
6
|
|
7
7
|
from earningscall.api import get_symbols_v2, is_demo_account
|
8
8
|
from earningscall.errors import InsufficientApiAccessError
|
@@ -14,7 +14,9 @@ EXCHANGES_IN_ORDER = ["NYSE", "NASDAQ", "AMEX", "TSX", "TSXV", "OTC"]
|
|
14
14
|
log = logging.getLogger(__file__)
|
15
15
|
|
16
16
|
|
17
|
-
def exchange_to_index(_exchange: str) -> int:
|
17
|
+
def exchange_to_index(_exchange: Optional[str]) -> int:
|
18
|
+
if not _exchange:
|
19
|
+
return -1
|
18
20
|
try:
|
19
21
|
return EXCHANGES_IN_ORDER.index(_exchange)
|
20
22
|
except ValueError:
|
@@ -110,7 +112,7 @@ class Symbols:
|
|
110
112
|
if len(self.by_exchange_and_sym) == size_before:
|
111
113
|
log.debug(f"Duplicate: {_sym}")
|
112
114
|
|
113
|
-
def get_all(self) -> [CompanyInfo]:
|
115
|
+
def get_all(self) -> Iterator[CompanyInfo]:
|
114
116
|
for _exchange_symbol, _symbol in self.by_exchange_and_sym.items():
|
115
117
|
yield _symbol
|
116
118
|
|
@@ -129,8 +131,10 @@ class Symbols:
|
|
129
131
|
except KeyError:
|
130
132
|
pass
|
131
133
|
if is_demo_account():
|
132
|
-
raise InsufficientApiAccessError(
|
133
|
-
|
134
|
+
raise InsufficientApiAccessError(
|
135
|
+
f"\"{symbol}\" requires an API Key for access. To get your API Key,"
|
136
|
+
f" see: https://earningscall.biz/api-pricing"
|
137
|
+
)
|
134
138
|
return None
|
135
139
|
|
136
140
|
def remove_exchange_symbol(self, exchange_symbol: str):
|
@@ -142,11 +146,13 @@ class Symbols:
|
|
142
146
|
def remove_keys(symbol_as_dict: dict, keys_to_remove: set):
|
143
147
|
return {key: value for key, value in symbol_as_dict.items() if key not in keys_to_remove}
|
144
148
|
|
145
|
-
def without_security_names(self) -> [dict]:
|
146
|
-
return [
|
147
|
-
|
149
|
+
def without_security_names(self) -> List[dict]:
|
150
|
+
return [
|
151
|
+
self.remove_keys(symbol_as_dict, {"security_name", "sector", "industry"})
|
152
|
+
for symbol_as_dict in self.to_dicts()
|
153
|
+
]
|
148
154
|
|
149
|
-
def to_dicts(self) -> [dict]:
|
155
|
+
def to_dicts(self) -> List[dict]:
|
150
156
|
return [__symbol.__dict__ for __symbol in self.get_all()]
|
151
157
|
|
152
158
|
def to_json(self, remove_security_names: bool = False) -> str:
|
@@ -154,9 +160,14 @@ class Symbols:
|
|
154
160
|
return json.dumps(self.without_security_names())
|
155
161
|
return json.dumps(self.to_dicts())
|
156
162
|
|
157
|
-
|
158
|
-
|
159
|
-
|
163
|
+
# TODO: Test this
|
164
|
+
# def to_json_v2(self) -> str:
|
165
|
+
# return json.dumps(
|
166
|
+
# [
|
167
|
+
# [exchange_to_index(__symbol.exchange), __symbol.company_info, __symbol.name]
|
168
|
+
# for __symbol in self.get_all()
|
169
|
+
# ]
|
170
|
+
# )
|
160
171
|
|
161
172
|
def to_txt(self) -> str:
|
162
173
|
exchange_symbol_names = [__symbol.to_txt_row() for __symbol in self.get_all()]
|
@@ -195,13 +206,15 @@ class Symbols:
|
|
195
206
|
__symbols = Symbols()
|
196
207
|
for line in txt_str.split("\n"):
|
197
208
|
_exchange_index, _symbol, _name, _sector_index, _industry_index = line.split("\t")
|
198
|
-
__symbols.add(
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
209
|
+
__symbols.add(
|
210
|
+
CompanyInfo(
|
211
|
+
exchange=index_to_exchange(int(_exchange_index)),
|
212
|
+
symbol=_symbol,
|
213
|
+
name=_name,
|
214
|
+
sector=index_to_sector(int(_sector_index)),
|
215
|
+
industry=index_to_industry(int(_industry_index)),
|
216
|
+
)
|
217
|
+
)
|
205
218
|
return __symbols
|
206
219
|
|
207
220
|
@staticmethod
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: earningscall
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.13
|
4
4
|
Summary: The EarningsCall Python library.
|
5
5
|
Project-URL: Homepage, https://earningscall.biz
|
6
6
|
Project-URL: Documentation, https://github.com/EarningsCall/earningscall-python
|
@@ -34,6 +34,7 @@ License-File: LICENSE
|
|
34
34
|
Requires-Python: >=3.8
|
35
35
|
Requires-Dist: dataclasses-json>=0.6.4
|
36
36
|
Requires-Dist: dataclasses>=0.6
|
37
|
+
Requires-Dist: requests-cache>=1.2.0
|
37
38
|
Requires-Dist: requests>=2.30.0
|
38
39
|
Description-Content-Type: text/markdown
|
39
40
|
|
@@ -58,7 +59,7 @@ pip install --upgrade earningscall
|
|
58
59
|
|
59
60
|
# Requirements
|
60
61
|
|
61
|
-
* Python 3.8+
|
62
|
+
* Python 3.8+
|
62
63
|
|
63
64
|
## Get Transcript for a Single Quarter
|
64
65
|
|
@@ -129,10 +130,8 @@ To gain access to 5,000+ companies please [signup here](https://earningscall.biz
|
|
129
130
|
Once you have access to your API key, you can set the API Key like this:
|
130
131
|
|
131
132
|
```python
|
132
|
-
|
133
133
|
import earningscall
|
134
134
|
|
135
|
-
|
136
135
|
earningscall.api_key = "YOUR SECRET API KEY GOES HERE"
|
137
136
|
```
|
138
137
|
|
@@ -151,4 +150,3 @@ from earningscall import get_sp500_companies
|
|
151
150
|
for company in get_sp500_companies():
|
152
151
|
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
153
152
|
```
|
154
|
-
|
@@ -0,0 +1,14 @@
|
|
1
|
+
earningscall/__init__.py,sha256=NX9f2et-q3p8BRGvJB0enRSLlSGecSAwspPxhDsL95Y,298
|
2
|
+
earningscall/api.py,sha256=eK43JazoBNI9YF0OMi5c0DrYv0tVzyOy2ycNyX63y8s,2000
|
3
|
+
earningscall/company.py,sha256=ZNF75htXg37oXtNzwrHH8DoTdyFJ3PBB9qSNBp_vo8c,1943
|
4
|
+
earningscall/errors.py,sha256=EA-d6qIYgQs9csp8JptQiAaYoM0M9HhCGJgKA9GAWPg,440
|
5
|
+
earningscall/event.py,sha256=O7KAE2wO3mBhlEWIFA1choMNGRthYd0gBIvVQOmVALs,692
|
6
|
+
earningscall/exports.py,sha256=i9UWHY6Lq1OzZTZX_1SdNzrNd_PSlPwpB337lGMK4oM,837
|
7
|
+
earningscall/sectors.py,sha256=9kAwTtJEDbWah6lz5io88qRwvCtmGgjQ-MU7rayTmVI,5962
|
8
|
+
earningscall/symbols.py,sha256=EXSPUMr50zZz-Cw9CimrRbVd7F71PB9McgsFC7yJ5S4,7980
|
9
|
+
earningscall/transcript.py,sha256=rLH2bGrrgUmS8XZGAPUP7msiIcL7f4ABmbnVJWXI28c,329
|
10
|
+
earningscall/utils.py,sha256=Qx8KhlumUdzyBSZRKMS6vpWlb8MGZpLKA4OffJaMdCE,1032
|
11
|
+
earningscall-0.0.13.dist-info/METADATA,sha256=6Ia7fToq94wm-BnrlBVkHccy04De-xFgGcjWlDu1T2s,5696
|
12
|
+
earningscall-0.0.13.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
13
|
+
earningscall-0.0.13.dist-info/licenses/LICENSE,sha256=ktEB_UcRMg2cQlX9wiDs544xWncWizwS9mEZuGsCLrM,1069
|
14
|
+
earningscall-0.0.13.dist-info/RECORD,,
|
@@ -1,14 +0,0 @@
|
|
1
|
-
earningscall/__init__.py,sha256=LvXzPzsPyckMUVggfB5sklTAaswKsSG1IJ8ImC-fvTc,200
|
2
|
-
earningscall/api.py,sha256=-nqxFGrTinCFCj8_wA-fkyrqr-WfDS50sMAh2UGdBR0,1958
|
3
|
-
earningscall/company.py,sha256=VyiHOajDBAx-G6dgWrPBUwWKjDpBvb0moZIpULPmiKA,1765
|
4
|
-
earningscall/errors.py,sha256=_m8CvAcyWQprdyTNzYjdoCX5nUZpEP7rG4c5-eLmxno,441
|
5
|
-
earningscall/event.py,sha256=Gdda4829tWlrlFn38r8KOaI-IJzf-ambiNojKyr9XtY,689
|
6
|
-
earningscall/exports.py,sha256=wA6d4-AJyT-0Wz8g_j-3rFHHhnXHx5V1GCsaPJMatFc,814
|
7
|
-
earningscall/sectors.py,sha256=9aw14krRzdLJSTFC72Nwk3MQaXAIgkTBk5S-KTiki3U,5946
|
8
|
-
earningscall/symbols.py,sha256=StqRc_C2hFdlhCMEKpytfUmsruCSHY0WPQQIVIejF9k,7748
|
9
|
-
earningscall/transcript.py,sha256=rLH2bGrrgUmS8XZGAPUP7msiIcL7f4ABmbnVJWXI28c,329
|
10
|
-
earningscall/utils.py,sha256=Qx8KhlumUdzyBSZRKMS6vpWlb8MGZpLKA4OffJaMdCE,1032
|
11
|
-
earningscall-0.0.10.dist-info/METADATA,sha256=kfOIWa_oFRM35njNOeUIQHKxs23dS_9omh4nt3ieke8,5679
|
12
|
-
earningscall-0.0.10.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
13
|
-
earningscall-0.0.10.dist-info/licenses/LICENSE,sha256=ktEB_UcRMg2cQlX9wiDs544xWncWizwS9mEZuGsCLrM,1069
|
14
|
-
earningscall-0.0.10.dist-info/RECORD,,
|
File without changes
|
File without changes
|