earningscall 0.0.9__tar.gz → 0.0.12__tar.gz
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-0.0.9 → earningscall-0.0.12}/.github/workflows/release.yml +40 -35
- earningscall-0.0.12/.github/workflows/test.yml +63 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/.gitignore +5 -1
- {earningscall-0.0.9 → earningscall-0.0.12}/DEVELOPMENT.md +23 -3
- {earningscall-0.0.9 → earningscall-0.0.12}/PKG-INFO +33 -14
- {earningscall-0.0.9 → earningscall-0.0.12}/README.md +10 -13
- earningscall-0.0.12/earningscall/__init__.py +8 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/api.py +8 -6
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/company.py +16 -16
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/errors.py +1 -2
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/event.py +3 -2
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/exports.py +4 -4
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/sectors.py +5 -8
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/symbols.py +32 -19
- earningscall-0.0.12/hatch.toml +46 -0
- earningscall-0.0.12/pyproject.toml +127 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/scripts/get_all_company_transcripts.py +1 -1
- {earningscall-0.0.9 → earningscall-0.0.12}/scripts/list_companies.py +1 -2
- earningscall-0.0.12/setup.cfg +2 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/test_earnings_event.py +7 -5
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/test_get_transcript.py +6 -4
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/test_symbols.py +27 -6
- earningscall-0.0.9/earningscall/__init__.py +0 -6
- earningscall-0.0.9/pyproject.toml +0 -73
- earningscall-0.0.9/requirements-dev.lock +0 -46
- earningscall-0.0.9/requirements.lock +0 -35
- {earningscall-0.0.9 → earningscall-0.0.12}/.python-version +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/CHANGELOG.md +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/LICENSE +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/TODO.md +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/transcript.py +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/earningscall/utils.py +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/scripts/get_single_transcript.py +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/demo-symbols-v2-alpha.yaml +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/demo-symbols-v2.yaml +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/msft-transcript-response.yaml +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/symbols-v2.yaml +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/symbols.txt +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/data/symbols.yaml +0 -0
- {earningscall-0.0.9 → earningscall-0.0.12}/tests/test_helper.py +0 -0
@@ -1,9 +1,18 @@
|
|
1
1
|
# https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
|
2
|
-
name: Build
|
2
|
+
name: Build
|
3
3
|
|
4
|
-
on:
|
4
|
+
on:
|
5
|
+
push:
|
6
|
+
tags:
|
7
|
+
- v*
|
8
|
+
branches:
|
9
|
+
- master
|
10
|
+
pull_request:
|
11
|
+
branches:
|
12
|
+
- master
|
5
13
|
|
6
14
|
jobs:
|
15
|
+
|
7
16
|
build:
|
8
17
|
name: Build distribution 📦
|
9
18
|
runs-on: ubuntu-latest
|
@@ -20,22 +29,16 @@ jobs:
|
|
20
29
|
pip install
|
21
30
|
build
|
22
31
|
--user
|
23
|
-
- name:
|
24
|
-
run:
|
25
|
-
curl -sSf https://rye.astral.sh/get | RYE_NO_AUTO_INSTALL=1 RYE_INSTALL_OPTION="--yes" bash
|
26
|
-
# $(HOME)/.rye/shims/rye pin $(PYTHON_VERSION)
|
27
|
-
# $(HOME)/.rye/shims/rye sync --no-lock
|
28
|
-
# https://rye.astral.sh/guide/publish/
|
32
|
+
- name: Build
|
33
|
+
run: python -m build
|
29
34
|
- name: Build a binary wheel and sdist
|
30
|
-
run:
|
31
|
-
source ~/.rye/env
|
32
|
-
rye sync
|
33
|
-
rye build
|
35
|
+
run: python -m build
|
34
36
|
- name: Store the distribution packages
|
35
37
|
uses: actions/upload-artifact@v3
|
36
38
|
with:
|
37
39
|
name: python-package-distributions
|
38
40
|
path: dist/
|
41
|
+
if-no-files-found: error
|
39
42
|
|
40
43
|
publish-to-pypi:
|
41
44
|
name: >-
|
@@ -102,26 +105,28 @@ jobs:
|
|
102
105
|
'${{ github.ref_name }}' dist/**
|
103
106
|
--repo '${{ github.repository }}'
|
104
107
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
108
|
+
# For now, don't publish to TestPyPI (as it needs a unique version each time).
|
109
|
+
# Is there a solution for this?
|
110
|
+
# publish-to-testpypi:
|
111
|
+
# name: Publish Python 🐍 distribution 📦 to TestPyPI
|
112
|
+
# needs:
|
113
|
+
# - build
|
114
|
+
# runs-on: ubuntu-latest
|
115
|
+
#
|
116
|
+
# environment:
|
117
|
+
# name: testpypi
|
118
|
+
# url: https://test.pypi.org/p/earningscall
|
119
|
+
#
|
120
|
+
# permissions:
|
121
|
+
# id-token: write # IMPORTANT: mandatory for trusted publishing
|
122
|
+
#
|
123
|
+
# steps:
|
124
|
+
# - name: Download all the dists
|
125
|
+
# uses: actions/download-artifact@v3
|
126
|
+
# with:
|
127
|
+
# name: python-package-distributions
|
128
|
+
# path: dist/
|
129
|
+
# - name: Publish distribution 📦 to TestPyPI
|
130
|
+
# uses: pypa/gh-action-pypi-publish@release/v1
|
131
|
+
# with:
|
132
|
+
# repository-url: https://test.pypi.org/legacy/
|
@@ -0,0 +1,63 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- master
|
10
|
+
|
11
|
+
concurrency:
|
12
|
+
group: test-${{ github.head_ref }}
|
13
|
+
cancel-in-progress: true
|
14
|
+
|
15
|
+
env:
|
16
|
+
PYTHONUNBUFFERED: "1"
|
17
|
+
FORCE_COLOR: "1"
|
18
|
+
|
19
|
+
jobs:
|
20
|
+
run:
|
21
|
+
name: Python ${{ matrix.python-version }} on ${{ startsWith(matrix.os, 'macos-') && 'macOS' || startsWith(matrix.os, 'windows-') && 'Windows' || 'Linux' }}
|
22
|
+
runs-on: ${{ matrix.os }}
|
23
|
+
strategy:
|
24
|
+
fail-fast: false
|
25
|
+
matrix:
|
26
|
+
os: [ubuntu-latest]
|
27
|
+
python-version: ['3.9']
|
28
|
+
|
29
|
+
steps:
|
30
|
+
- uses: actions/checkout@v3
|
31
|
+
|
32
|
+
- name: Set up Python ${{ matrix.python-version }}
|
33
|
+
uses: actions/setup-python@v4
|
34
|
+
with:
|
35
|
+
python-version: ${{ matrix.python-version }}
|
36
|
+
|
37
|
+
- name: Install Hatch
|
38
|
+
run: pip install --upgrade hatch
|
39
|
+
|
40
|
+
- if: matrix.python-version == '3.9' && runner.os == 'Linux'
|
41
|
+
name: Lint
|
42
|
+
run: hatch run lint:all
|
43
|
+
|
44
|
+
- name: Run tests and track code coverage
|
45
|
+
run: hatch run cov
|
46
|
+
|
47
|
+
run-container-matrix:
|
48
|
+
name: Container matrix on Linux
|
49
|
+
runs-on: ubuntu-latest
|
50
|
+
|
51
|
+
steps:
|
52
|
+
- uses: actions/checkout@v3
|
53
|
+
|
54
|
+
- name: Set up Python 3.10
|
55
|
+
uses: actions/setup-python@v4
|
56
|
+
with:
|
57
|
+
python-version: '3.10'
|
58
|
+
|
59
|
+
- name: Install Hatch
|
60
|
+
run: pip install --upgrade hatch hatch-containers
|
61
|
+
|
62
|
+
- name: Run tests in container matrix
|
63
|
+
run: hatch run all:test
|
@@ -1,8 +1,6 @@
|
|
1
1
|
# Development
|
2
2
|
|
3
|
-
TODO: Add
|
4
|
-
|
5
|
-
This project uses Rye: https://rye.astral.sh/
|
3
|
+
TODO: Add hatch installation instructions.
|
6
4
|
|
7
5
|
|
8
6
|
### Saving Server-Side Responses for a Mocked Unit test
|
@@ -35,3 +33,25 @@ git commit -a
|
|
35
33
|
git tag v0.0.7
|
36
34
|
git push --atomic origin master v0.0.7
|
37
35
|
```
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
### Manually Running Scripts
|
40
|
+
|
41
|
+
Use the library to get a single transcript from the API:
|
42
|
+
|
43
|
+
```shell
|
44
|
+
python -m scripts.get_single_transcript
|
45
|
+
```
|
46
|
+
|
47
|
+
Get all transcripts for a company:
|
48
|
+
|
49
|
+
```shell
|
50
|
+
python -m scripts.get_all_company_transcripts
|
51
|
+
```
|
52
|
+
|
53
|
+
List all companies:
|
54
|
+
|
55
|
+
```shell
|
56
|
+
python -m scripts.list_companies
|
57
|
+
```
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: earningscall
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.12
|
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
|
@@ -9,10 +9,32 @@ Project-URL: Issues, https://github.com/EarningsCall/earningscall-python/issues
|
|
9
9
|
Project-URL: Source, https://github.com/EarningsCall/earningscall-python
|
10
10
|
Project-URL: Changelog, https://github.com/EarningsCall/earningscall-python/blob/master/CHANGELOG.md
|
11
11
|
Author-email: EarningsCall <dev@earningscall.biz>
|
12
|
+
License: MIT License
|
13
|
+
|
14
|
+
Copyright (c) 2024 EarningsCall
|
15
|
+
|
16
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
17
|
+
of this software and associated documentation files (the "Software"), to deal
|
18
|
+
in the Software without restriction, including without limitation the rights
|
19
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
20
|
+
copies of the Software, and to permit persons to whom the Software is
|
21
|
+
furnished to do so, subject to the following conditions:
|
22
|
+
|
23
|
+
The above copyright notice and this permission notice shall be included in all
|
24
|
+
copies or substantial portions of the Software.
|
25
|
+
|
26
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
27
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
28
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
29
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
30
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
31
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
32
|
+
SOFTWARE.
|
12
33
|
License-File: LICENSE
|
13
34
|
Requires-Python: >=3.8
|
14
35
|
Requires-Dist: dataclasses-json>=0.6.4
|
15
36
|
Requires-Dist: dataclasses>=0.6
|
37
|
+
Requires-Dist: requests-cache>=1.2.0
|
16
38
|
Requires-Dist: requests>=2.30.0
|
17
39
|
Description-Content-Type: text/markdown
|
18
40
|
|
@@ -92,8 +114,6 @@ Getting all transcripts for: Apple Inc...
|
|
92
114
|
...
|
93
115
|
```
|
94
116
|
|
95
|
-
|
96
|
-
|
97
117
|
## List All Companies
|
98
118
|
|
99
119
|
```python
|
@@ -103,15 +123,6 @@ for company in get_all_companies():
|
|
103
123
|
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
104
124
|
```
|
105
125
|
|
106
|
-
## List S&P 500 Companies
|
107
|
-
|
108
|
-
```python
|
109
|
-
from earningscall import get_all_companies
|
110
|
-
|
111
|
-
for company in get_all_companies():
|
112
|
-
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
113
|
-
```
|
114
|
-
|
115
126
|
By default, this library grants you access to only two companies, Apple Inc. and Microsoft, Inc.
|
116
127
|
|
117
128
|
To gain access to 5,000+ companies please [signup here](https://earningscall.biz/api-pricing) to get your API key.
|
@@ -119,10 +130,8 @@ To gain access to 5,000+ companies please [signup here](https://earningscall.biz
|
|
119
130
|
Once you have access to your API key, you can set the API Key like this:
|
120
131
|
|
121
132
|
```python
|
122
|
-
|
123
133
|
import earningscall
|
124
134
|
|
125
|
-
|
126
135
|
earningscall.api_key = "YOUR SECRET API KEY GOES HERE"
|
127
136
|
```
|
128
137
|
|
@@ -132,3 +141,13 @@ Alternatively, you can pass in your API key as an environment variable:
|
|
132
141
|
export ECALL_API_KEY="YOUR SECRET API KEY GOES HERE"
|
133
142
|
python your-python-script.py
|
134
143
|
```
|
144
|
+
|
145
|
+
## List S&P 500 Companies
|
146
|
+
|
147
|
+
```python
|
148
|
+
from earningscall import get_sp500_companies
|
149
|
+
|
150
|
+
for company in get_sp500_companies():
|
151
|
+
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
152
|
+
```
|
153
|
+
|
@@ -74,8 +74,6 @@ Getting all transcripts for: Apple Inc...
|
|
74
74
|
...
|
75
75
|
```
|
76
76
|
|
77
|
-
|
78
|
-
|
79
77
|
## List All Companies
|
80
78
|
|
81
79
|
```python
|
@@ -85,15 +83,6 @@ for company in get_all_companies():
|
|
85
83
|
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
86
84
|
```
|
87
85
|
|
88
|
-
## List S&P 500 Companies
|
89
|
-
|
90
|
-
```python
|
91
|
-
from earningscall import get_all_companies
|
92
|
-
|
93
|
-
for company in get_all_companies():
|
94
|
-
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
95
|
-
```
|
96
|
-
|
97
86
|
By default, this library grants you access to only two companies, Apple Inc. and Microsoft, Inc.
|
98
87
|
|
99
88
|
To gain access to 5,000+ companies please [signup here](https://earningscall.biz/api-pricing) to get your API key.
|
@@ -101,10 +90,8 @@ To gain access to 5,000+ companies please [signup here](https://earningscall.biz
|
|
101
90
|
Once you have access to your API key, you can set the API Key like this:
|
102
91
|
|
103
92
|
```python
|
104
|
-
|
105
93
|
import earningscall
|
106
94
|
|
107
|
-
|
108
95
|
earningscall.api_key = "YOUR SECRET API KEY GOES HERE"
|
109
96
|
```
|
110
97
|
|
@@ -114,3 +101,13 @@ Alternatively, you can pass in your API key as an environment variable:
|
|
114
101
|
export ECALL_API_KEY="YOUR SECRET API KEY GOES HERE"
|
115
102
|
python your-python-script.py
|
116
103
|
```
|
104
|
+
|
105
|
+
## List S&P 500 Companies
|
106
|
+
|
107
|
+
```python
|
108
|
+
from earningscall import get_sp500_companies
|
109
|
+
|
110
|
+
for company in get_sp500_companies():
|
111
|
+
print(f"{company.company_info} -- {company.company_info.sector} -- {company.company_info.industry}")
|
112
|
+
```
|
113
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
from typing import Optional
|
2
|
+
|
3
|
+
from earningscall.exports import get_company, get_all_companies, get_sp500_companies
|
4
|
+
from earningscall.symbols import Symbols, load_symbols
|
5
|
+
|
6
|
+
api_key: Optional[str] = None
|
7
|
+
|
8
|
+
__all__ = ["get_company", "get_all_companies", "get_sp500_companies", "Symbols", "load_symbols"]
|
@@ -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()
|
@@ -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
|
@@ -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
|
)
|
@@ -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:
|
@@ -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
|
-
|
@@ -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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
[envs.default]
|
2
|
+
dependencies = [
|
3
|
+
"coverage[toml]>=6.5",
|
4
|
+
"pytest",
|
5
|
+
"responses",
|
6
|
+
]
|
7
|
+
[envs.default.scripts]
|
8
|
+
test = "pytest {args:tests}"
|
9
|
+
test-cov = "coverage run -m pytest {args:tests}"
|
10
|
+
cov-report = [
|
11
|
+
"- coverage combine",
|
12
|
+
"coverage report --show-missing",
|
13
|
+
]
|
14
|
+
cov = [
|
15
|
+
"test-cov",
|
16
|
+
"cov-report",
|
17
|
+
]
|
18
|
+
|
19
|
+
[envs.all]
|
20
|
+
type = "container"
|
21
|
+
|
22
|
+
[[envs.all.matrix]]
|
23
|
+
python = ["3.8", "3.9", "3.10", "3.11"]
|
24
|
+
|
25
|
+
[envs.lint]
|
26
|
+
detached = true
|
27
|
+
dependencies = [
|
28
|
+
"black>=22.10.0",
|
29
|
+
"mypy>=0.991",
|
30
|
+
"ruff>=0.0.166",
|
31
|
+
]
|
32
|
+
[envs.lint.scripts]
|
33
|
+
typing = "mypy --install-types --non-interactive {args:earningscall tests}"
|
34
|
+
style = [
|
35
|
+
"ruff {args:.}",
|
36
|
+
"black --check --diff {args:.}",
|
37
|
+
]
|
38
|
+
fmt = [
|
39
|
+
"black {args:.}",
|
40
|
+
"ruff --fix {args:.}",
|
41
|
+
"style",
|
42
|
+
]
|
43
|
+
all = [
|
44
|
+
"style",
|
45
|
+
"typing",
|
46
|
+
]
|
@@ -0,0 +1,127 @@
|
|
1
|
+
[project]
|
2
|
+
name = "earningscall"
|
3
|
+
version = "0.0.12"
|
4
|
+
description = "The EarningsCall Python library."
|
5
|
+
readme = "README.md"
|
6
|
+
authors = [
|
7
|
+
{name = "EarningsCall", email = "dev@earningscall.biz"},
|
8
|
+
]
|
9
|
+
requires-python = ">= 3.8"
|
10
|
+
dependencies = [
|
11
|
+
"dataclasses>=0.6",
|
12
|
+
"dataclasses-json>=0.6.4",
|
13
|
+
"requests>=2.30.0",
|
14
|
+
"requests-cache>=1.2.0",
|
15
|
+
]
|
16
|
+
license = { file = "LICENSE" }
|
17
|
+
|
18
|
+
[project.urls]
|
19
|
+
Homepage = "https://earningscall.biz"
|
20
|
+
Documentation = "https://github.com/EarningsCall/earningscall-python"
|
21
|
+
Repository = "https://github.com/EarningsCall/earningscall-python"
|
22
|
+
Issues = "https://github.com/EarningsCall/earningscall-python/issues"
|
23
|
+
Source = "https://github.com/EarningsCall/earningscall-python"
|
24
|
+
Changelog = "https://github.com/EarningsCall/earningscall-python/blob/master/CHANGELOG.md"
|
25
|
+
|
26
|
+
[build-system]
|
27
|
+
requires = ["hatchling"]
|
28
|
+
build-backend = "hatchling.build"
|
29
|
+
|
30
|
+
|
31
|
+
[tool.hatch.metadata]
|
32
|
+
allow-direct-references = true
|
33
|
+
|
34
|
+
|
35
|
+
[tool.hatch.build.targets.wheel]
|
36
|
+
packages = ["earningscall"]
|
37
|
+
|
38
|
+
[tool.hatch.version]
|
39
|
+
path = "hatch_init/__about__.py"
|
40
|
+
|
41
|
+
[tool.hatch.envs.default]
|
42
|
+
dependencies = [
|
43
|
+
"pytest",
|
44
|
+
"pytest-cov",
|
45
|
+
]
|
46
|
+
[tool.hatch.envs.default.scripts]
|
47
|
+
cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=hatch_init --cov=tests"
|
48
|
+
no-cov = "cov --no-cov"
|
49
|
+
|
50
|
+
[[tool.hatch.envs.test.matrix]]
|
51
|
+
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
52
|
+
|
53
|
+
|
54
|
+
[tool.hatch.build.targets.wheel.hooks.mypyc]
|
55
|
+
enable-by-default = false
|
56
|
+
dependencies = ["hatch-mypyc>=0.14.1"]
|
57
|
+
require-runtime-dependencies = true
|
58
|
+
mypy-args = [
|
59
|
+
"--no-warn-unused-ignores",
|
60
|
+
]
|
61
|
+
|
62
|
+
[tool.mypy]
|
63
|
+
disallow_untyped_defs = false
|
64
|
+
follow_imports = "normal"
|
65
|
+
ignore_missing_imports = true
|
66
|
+
pretty = true
|
67
|
+
show_column_numbers = true
|
68
|
+
warn_no_return = false
|
69
|
+
warn_unused_ignores = true
|
70
|
+
|
71
|
+
|
72
|
+
[tool.black]
|
73
|
+
target-version = ["py37"]
|
74
|
+
line-length = 120
|
75
|
+
skip-string-normalization = true
|
76
|
+
|
77
|
+
[tool.ruff]
|
78
|
+
target-version = "py37"
|
79
|
+
|
80
|
+
[tool.ruff.lint]
|
81
|
+
ignore = [
|
82
|
+
# Allow non-abstract empty methods in abstract base classes
|
83
|
+
"B027",
|
84
|
+
# Allow boolean positional values in function calls, like `dict.get(... True)`
|
85
|
+
"FBT003",
|
86
|
+
# Ignore checks for possible passwords
|
87
|
+
# Ignore complexity
|
88
|
+
"C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915",
|
89
|
+
"PLC1901", # empty string comparisons
|
90
|
+
"PLW2901", # `for` loop variable overwritten
|
91
|
+
"SIM114", # Combine `if` branches using logical `or` operator
|
92
|
+
]
|
93
|
+
unfixable = [
|
94
|
+
# Don't touch unused imports
|
95
|
+
"F401",
|
96
|
+
]
|
97
|
+
|
98
|
+
[tool.ruff.lint.flake8-quotes]
|
99
|
+
inline-quotes = "single"
|
100
|
+
|
101
|
+
[tool.ruff.lint.isort]
|
102
|
+
known-first-party = ["earningscall"]
|
103
|
+
|
104
|
+
|
105
|
+
[tool.ruff.lint.flake8-tidy-imports]
|
106
|
+
ban-relative-imports = "all"
|
107
|
+
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
109
|
+
# Tests can use relative imports and assertions
|
110
|
+
"tests/**/*" = ["TID252", "S101"]
|
111
|
+
|
112
|
+
[tool.coverage.run]
|
113
|
+
source_pkgs = ["earningscall", "tests"]
|
114
|
+
branch = true
|
115
|
+
parallel = true
|
116
|
+
omit = []
|
117
|
+
|
118
|
+
[tool.coverage.paths]
|
119
|
+
earningscall = ["earningscall"]
|
120
|
+
tests = ["tests"]
|
121
|
+
|
122
|
+
[tool.coverage.report]
|
123
|
+
exclude_lines = [
|
124
|
+
"no cov",
|
125
|
+
"if __name__ == .__main__.:",
|
126
|
+
"if TYPE_CHECKING:",
|
127
|
+
]
|
@@ -26,11 +26,13 @@ def test_basic_without_conference_date():
|
|
26
26
|
|
27
27
|
def test_date_field_deserialization():
|
28
28
|
#
|
29
|
-
earnings_event = EarningsEvent.from_dict(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
earnings_event = EarningsEvent.from_dict(
|
30
|
+
{
|
31
|
+
"year": 2024,
|
32
|
+
"quarter": 1,
|
33
|
+
"conference_date": "2024-04-28T15:00:00.000-05:00",
|
34
|
+
}
|
35
|
+
)
|
34
36
|
#
|
35
37
|
assert earnings_event.year == 2024
|
36
38
|
assert earnings_event.quarter == 1
|
@@ -25,8 +25,9 @@ def test_get_demo_company():
|
|
25
25
|
company = get_company("msft")
|
26
26
|
##
|
27
27
|
transcript = company.get_transcript(year=2023, quarter=1)
|
28
|
-
assert transcript.text[:100] == (
|
29
|
-
|
28
|
+
assert transcript.text[:100] == (
|
29
|
+
'Greetings, and welcome to the Microsoft Fiscal Year 2023 First Quarter Earnings ' 'Conference Call. At '
|
30
|
+
)
|
30
31
|
|
31
32
|
|
32
33
|
@responses.activate
|
@@ -42,8 +43,9 @@ def test_get_demo_company_with_event_populated():
|
|
42
43
|
assert transcript.event.year == 2022
|
43
44
|
assert transcript.event.quarter == 1
|
44
45
|
assert transcript.event.conference_date.isoformat() == "2022-01-19T00:00:00-08:00"
|
45
|
-
assert transcript.text[:100] == (
|
46
|
-
|
46
|
+
assert transcript.text[:100] == (
|
47
|
+
"Good day and welcome to the Apple Q1 Fiscal Year 2021 earnings conference " "call. Today's call is bein"
|
48
|
+
)
|
47
49
|
|
48
50
|
|
49
51
|
# Uncomment and run following code to generate demo-symbols-v2.yaml file
|
@@ -26,12 +26,33 @@ def test_load_symbols_txt_v2():
|
|
26
26
|
def test_symbols_serialization_to_text_v2():
|
27
27
|
##
|
28
28
|
_symbols = Symbols()
|
29
|
-
_symbols.add(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
29
|
+
_symbols.add(
|
30
|
+
CompanyInfo(
|
31
|
+
exchange="TSX",
|
32
|
+
symbol="TLRY",
|
33
|
+
name="Tilray, Inc",
|
34
|
+
sector="Energy",
|
35
|
+
industry="Electronic Gaming & Multimedia",
|
36
|
+
)
|
37
|
+
)
|
38
|
+
_symbols.add(
|
39
|
+
CompanyInfo(
|
40
|
+
exchange="TSX",
|
41
|
+
symbol="ACB",
|
42
|
+
name="Aurora Cannabis Inc.",
|
43
|
+
sector="Technology",
|
44
|
+
industry="Electronic Gaming & Multimedia",
|
45
|
+
)
|
46
|
+
)
|
47
|
+
_symbols.add(
|
48
|
+
CompanyInfo(
|
49
|
+
exchange="NASDAQ",
|
50
|
+
symbol="HITI",
|
51
|
+
name="High Tide Inc.",
|
52
|
+
sector="Consumer Cyclical",
|
53
|
+
industry="Electronic Gaming & Multimedia",
|
54
|
+
)
|
55
|
+
)
|
35
56
|
##
|
36
57
|
result = _symbols.to_txt_v2()
|
37
58
|
##
|
@@ -1,73 +0,0 @@
|
|
1
|
-
[project]
|
2
|
-
name = "earningscall"
|
3
|
-
version = "0.0.9"
|
4
|
-
description = "The EarningsCall Python library."
|
5
|
-
readme = "README.md"
|
6
|
-
authors = [
|
7
|
-
{name = "EarningsCall", email = "dev@earningscall.biz"},
|
8
|
-
]
|
9
|
-
requires-python = ">= 3.8"
|
10
|
-
dependencies = [
|
11
|
-
"dataclasses>=0.6",
|
12
|
-
"dataclasses-json>=0.6.4",
|
13
|
-
"requests>=2.30.0",
|
14
|
-
]
|
15
|
-
|
16
|
-
[project.urls]
|
17
|
-
Homepage = "https://earningscall.biz"
|
18
|
-
Documentation = "https://github.com/EarningsCall/earningscall-python"
|
19
|
-
Repository = "https://github.com/EarningsCall/earningscall-python"
|
20
|
-
Issues = "https://github.com/EarningsCall/earningscall-python/issues"
|
21
|
-
Source = "https://github.com/EarningsCall/earningscall-python"
|
22
|
-
Changelog = "https://github.com/EarningsCall/earningscall-python/blob/master/CHANGELOG.md"
|
23
|
-
|
24
|
-
[build-system]
|
25
|
-
requires = ["hatchling"]
|
26
|
-
build-backend = "hatchling.build"
|
27
|
-
|
28
|
-
[tool.rye]
|
29
|
-
managed = true
|
30
|
-
dev-dependencies = [
|
31
|
-
"pytest>=8.2.1",
|
32
|
-
"responses>=0.25.0",
|
33
|
-
]
|
34
|
-
|
35
|
-
[tool.hatch.metadata]
|
36
|
-
allow-direct-references = true
|
37
|
-
|
38
|
-
|
39
|
-
[tool.hatch.build.targets.wheel]
|
40
|
-
packages = ["earningscall"]
|
41
|
-
|
42
|
-
#[tool.hatch.envs.test]
|
43
|
-
#dependencies = [
|
44
|
-
# "pytest",
|
45
|
-
# "pytest-cov",
|
46
|
-
# "responses"
|
47
|
-
#]
|
48
|
-
|
49
|
-
[[tool.hatch.envs.test.matrix]]
|
50
|
-
python = ["3.10", "3.11"]
|
51
|
-
|
52
|
-
[tool.hatch.envs.types]
|
53
|
-
extra-dependencies = [
|
54
|
-
"mypy>=1.0.0",
|
55
|
-
"responses"
|
56
|
-
]
|
57
|
-
|
58
|
-
[tool.coverage.run]
|
59
|
-
source_pkgs = ["earningscall", "tests"]
|
60
|
-
branch = true
|
61
|
-
parallel = true
|
62
|
-
omit = []
|
63
|
-
|
64
|
-
[tool.coverage.paths]
|
65
|
-
earningscall = ["earningscall"]
|
66
|
-
tests = ["tests"]
|
67
|
-
|
68
|
-
[tool.coverage.report]
|
69
|
-
exclude_lines = [
|
70
|
-
"no cov",
|
71
|
-
"if __name__ == .__main__.:",
|
72
|
-
"if TYPE_CHECKING:",
|
73
|
-
]
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# generated by rye
|
2
|
-
# use `rye lock` or `rye sync` to update this lockfile
|
3
|
-
#
|
4
|
-
# last locked with the following flags:
|
5
|
-
# pre: false
|
6
|
-
# features: []
|
7
|
-
# all-features: false
|
8
|
-
# with-sources: false
|
9
|
-
# generate-hashes: false
|
10
|
-
|
11
|
-
-e file:.
|
12
|
-
certifi==2024.2.2
|
13
|
-
# via requests
|
14
|
-
charset-normalizer==3.3.2
|
15
|
-
# via requests
|
16
|
-
dataclasses==0.6
|
17
|
-
# via earningscall
|
18
|
-
dataclasses-json==0.6.6
|
19
|
-
# via earningscall
|
20
|
-
idna==3.7
|
21
|
-
# via requests
|
22
|
-
iniconfig==2.0.0
|
23
|
-
# via pytest
|
24
|
-
marshmallow==3.21.2
|
25
|
-
# via dataclasses-json
|
26
|
-
mypy-extensions==1.0.0
|
27
|
-
# via typing-inspect
|
28
|
-
packaging==24.0
|
29
|
-
# via marshmallow
|
30
|
-
# via pytest
|
31
|
-
pluggy==1.5.0
|
32
|
-
# via pytest
|
33
|
-
pytest==8.2.1
|
34
|
-
pyyaml==6.0.1
|
35
|
-
# via responses
|
36
|
-
requests==2.32.2
|
37
|
-
# via earningscall
|
38
|
-
# via responses
|
39
|
-
responses==0.25.0
|
40
|
-
typing-extensions==4.12.0
|
41
|
-
# via typing-inspect
|
42
|
-
typing-inspect==0.9.0
|
43
|
-
# via dataclasses-json
|
44
|
-
urllib3==2.2.1
|
45
|
-
# via requests
|
46
|
-
# via responses
|
@@ -1,35 +0,0 @@
|
|
1
|
-
# generated by rye
|
2
|
-
# use `rye lock` or `rye sync` to update this lockfile
|
3
|
-
#
|
4
|
-
# last locked with the following flags:
|
5
|
-
# pre: false
|
6
|
-
# features: []
|
7
|
-
# all-features: false
|
8
|
-
# with-sources: false
|
9
|
-
# generate-hashes: false
|
10
|
-
|
11
|
-
-e file:.
|
12
|
-
certifi==2024.2.2
|
13
|
-
# via requests
|
14
|
-
charset-normalizer==3.3.2
|
15
|
-
# via requests
|
16
|
-
dataclasses==0.6
|
17
|
-
# via earningscall
|
18
|
-
dataclasses-json==0.6.6
|
19
|
-
# via earningscall
|
20
|
-
idna==3.7
|
21
|
-
# via requests
|
22
|
-
marshmallow==3.21.2
|
23
|
-
# via dataclasses-json
|
24
|
-
mypy-extensions==1.0.0
|
25
|
-
# via typing-inspect
|
26
|
-
packaging==24.0
|
27
|
-
# via marshmallow
|
28
|
-
requests==2.32.2
|
29
|
-
# via earningscall
|
30
|
-
typing-extensions==4.12.0
|
31
|
-
# via typing-inspect
|
32
|
-
typing-inspect==0.9.0
|
33
|
-
# via dataclasses-json
|
34
|
-
urllib3==2.2.1
|
35
|
-
# via requests
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|