Skip to content

Commit 5d55f31

Browse files
authored
Feature/test suite (#11)
* basic tests for categories namespace * add basic tests for tags api * add basic tests for sources api namespace * create basic tests for releases api namespace * add basic tests for series api namespace * create test for decorators * use src for tests * first full test-suite of basic API functionality, closes issue #8 * new CI for lint and test package * upgrade black in CI, use fred api key from GH secrets * reformat files * update CI only test for 3.9 & 3.10 * only run CI with python 3.10.x * run ci using coverage * add coverage upload * add new job skeleton to CI * upload to PyPI when publishing new release/prerelease
1 parent ddbd981 commit 5d55f31

17 files changed

+728
-67
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
3+
name: Lint, Test & Upload fred-py-api
4+
5+
on:
6+
release:
7+
types: [published]
8+
push:
9+
branches: ["main"]
10+
pull_request:
11+
branches: [ "main" ]
12+
13+
jobs:
14+
build:
15+
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
python-version: ["3.10"]
21+
env:
22+
FRED_API_KEY: ${{ secrets.FRED_API_KEY }}
23+
24+
steps:
25+
- uses: actions/checkout@v3
26+
- name: Set up Python ${{ matrix.python-version }}
27+
uses: actions/setup-python@v3
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
- name: Install dependencies
31+
run: |
32+
python -m pip install --upgrade pip
33+
python -m pip install requests coverage black==22.6.0
34+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
35+
- name: Lint with black
36+
run: |
37+
# Run black on all Python files
38+
black --line-length 120 --check ./
39+
- name: Test with coverage
40+
run: |
41+
coverage run -m unittest discover -s tests
42+
coverage report -m
43+
- name: Upload coverage report
44+
uses: codecov/codecov-action@v2
45+
46+
pypi:
47+
needs: build
48+
runs-on: ubuntu-latest
49+
if: github.event_name == 'release'
50+
steps:
51+
- uses: actions/checkout@v3
52+
- name: Set up Python
53+
uses: actions/setup-python@v3
54+
with:
55+
python-version: '3.x'
56+
- name: Install dependencies
57+
run: |
58+
python -m pip install --upgrade pip
59+
pip install build
60+
- name: Build package
61+
run: python -m build
62+
- name: Publish package
63+
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
64+
with:
65+
user: __token__
66+
password: ${{ secrets.PYPI_API_TOKEN }}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "fred_py_api"
7-
version = "0.0.5"
7+
version = "0.0.6"
88
authors = [
99
{ name="Zachary Spar", email="[email protected]" },
1010
]

src/fredapi/api/categories.py

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ class FredAPICategories(FredClient):
2222
@validate_api_args("api_key", "file_type", "category_id")
2323
def get_category(self, category_id: int = None, **kwargs) -> dict:
2424
"""Get category by ID."""
25-
return self._get(f"category", {"category_id": category_id, **kwargs,})
25+
return self._get(
26+
f"category",
27+
{
28+
"category_id": category_id,
29+
**kwargs,
30+
},
31+
)
2632

2733
@validate_api_args(
2834
"api_key",
@@ -41,17 +47,35 @@ def get_category(self, category_id: int = None, **kwargs) -> dict:
4147
)
4248
def get_category_series(self, category_id: int, **kwargs) -> dict:
4349
"""Get category series by ID."""
44-
return self._get(f"category/series", {"category_id": category_id, **kwargs,})
50+
return self._get(
51+
f"category/series",
52+
{
53+
"category_id": category_id,
54+
**kwargs,
55+
},
56+
)
4557

4658
@validate_api_args("api_key", "file_type", "category_id", "realtime_start", "realtime_end")
4759
def get_category_children(self, category_id: int = None, **kwargs) -> dict:
4860
"""Get category children by ID."""
49-
return self._get(f"category/children", {"category_id": category_id, **kwargs,})
61+
return self._get(
62+
f"category/children",
63+
{
64+
"category_id": category_id,
65+
**kwargs,
66+
},
67+
)
5068

5169
@validate_api_args("api_key", "file_type", "category_id", "realtime_start", "realtime_end")
5270
def get_category_related(self, category_id: int, **kwargs) -> dict:
5371
"""Get category related by ID."""
54-
return self._get(f"category/related", {"category_id": category_id, **kwargs,})
72+
return self._get(
73+
f"category/related",
74+
{
75+
"category_id": category_id,
76+
**kwargs,
77+
},
78+
)
5579

5680
@validate_api_args(
5781
"api_key",
@@ -75,7 +99,13 @@ def get_category_related(self, category_id: int, **kwargs) -> dict:
7599
)
76100
def get_category_tags(self, category_id: int, **kwargs) -> dict:
77101
"""Get category tags by ID."""
78-
return self._get(f"category/tags", {"category_id": category_id, **kwargs,})
102+
return self._get(
103+
f"category/tags",
104+
{
105+
"category_id": category_id,
106+
**kwargs,
107+
},
108+
)
79109

80110
@validate_api_args(
81111
"api_key",
@@ -100,4 +130,11 @@ def get_category_tags(self, category_id: int, **kwargs) -> dict:
100130
)
101131
def get_category_related_tags(self, category_id: int, tag_names: str, **kwargs) -> dict:
102132
"""Get category related tags by ID."""
103-
return self._get(f"category/related_tags", {"category_id": category_id, "tag_names": tag_names, **kwargs,})
133+
return self._get(
134+
f"category/related_tags",
135+
{
136+
"category_id": category_id,
137+
"tag_names": tag_names,
138+
**kwargs,
139+
},
140+
)

src/fredapi/api/fred_client.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55
from http import HTTPStatus
66
from os import environ
7+
from typing import Optional
78

89
import requests
910

@@ -13,7 +14,7 @@
1314
class FredClient(object):
1415
"""Base Fred API."""
1516

16-
def __init__(self, api_key: str = None, base_client=None):
17+
def __init__(self, api_key: str = None, base_client: Optional["FredClient"] = None):
1718
"""Init client."""
1819
if not base_client and not api_key:
1920
api_key = environ.get("FRED_API_KEY", None)
@@ -39,6 +40,8 @@ def get_api_key(self) -> str:
3940

4041
def _get(self, endpoint: str = None, payload: dict = None) -> dict:
4142
"""Invoke client get request."""
43+
if not payload:
44+
payload = {}
4245
try:
4346
resp = requests.get(f"{self.base_url}/{endpoint}", params={**self.base_params, **payload})
4447
except requests.exceptions.RequestException as e:

src/fredapi/api/releases.py

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,12 @@ class FredAPIReleases(FredClient):
2727
)
2828
def get_releases(self, **kwargs) -> dict:
2929
"""Get releases."""
30-
return self._get(f"releases", {**kwargs,})
30+
return self._get(
31+
f"releases",
32+
{
33+
**kwargs,
34+
},
35+
)
3136

3237
@validate_api_args(
3338
"api_key",
@@ -42,12 +47,23 @@ def get_releases(self, **kwargs) -> dict:
4247
)
4348
def get_releases_dates(self, **kwargs) -> dict:
4449
"""Get releases dates."""
45-
return self._get(f"releases/dates", {**kwargs,})
50+
return self._get(
51+
f"releases/dates",
52+
{
53+
**kwargs,
54+
},
55+
)
4656

4757
@validate_api_args("api_key", "release_id", "file_type", "realtime_start", "realtime_end")
4858
def get_release(self, release_id: int, **kwargs) -> dict:
4959
"""Get release by ID."""
50-
return self._get(f"release", {"release_id": release_id, **kwargs,})
60+
return self._get(
61+
f"release",
62+
{
63+
"release_id": release_id,
64+
**kwargs,
65+
},
66+
)
5167

5268
@validate_api_args(
5369
"api_key",
@@ -62,7 +78,13 @@ def get_release(self, release_id: int, **kwargs) -> dict:
6278
)
6379
def get_release_dates(self, release_id: int, **kwargs) -> dict:
6480
"""Get release dates by ID."""
65-
return self._get(f"release/dates", {"release_id": release_id, **kwargs,})
81+
return self._get(
82+
f"release/dates",
83+
{
84+
"release_id": release_id,
85+
**kwargs,
86+
},
87+
)
6688

6789
@validate_api_args(
6890
"api_key",
@@ -81,12 +103,24 @@ def get_release_dates(self, release_id: int, **kwargs) -> dict:
81103
)
82104
def get_release_series(self, release_id: int, **kwargs) -> dict:
83105
"""Get release series by ID."""
84-
return self._get(f"release/series", {"release_id": release_id, **kwargs,})
106+
return self._get(
107+
f"release/series",
108+
{
109+
"release_id": release_id,
110+
**kwargs,
111+
},
112+
)
85113

86114
@validate_api_args("api_key", "file_type", "release_id", "realtime_start", "realtime_end")
87115
def get_release_sources(self, release_id: int, **kwargs) -> dict:
88116
"""Get release sources by ID."""
89-
return self._get(f"release/sources", {"release_id": release_id, **kwargs,})
117+
return self._get(
118+
f"release/sources",
119+
{
120+
"release_id": release_id,
121+
**kwargs,
122+
},
123+
)
90124

91125
@validate_api_args(
92126
"api_key",
@@ -104,7 +138,13 @@ def get_release_sources(self, release_id: int, **kwargs) -> dict:
104138
)
105139
def get_release_tags(self, release_id: int, **kwargs) -> dict:
106140
"""Get release tags by ID."""
107-
return self._get(f"release/tags", {"release_id": release_id, **kwargs,})
141+
return self._get(
142+
f"release/tags",
143+
{
144+
"release_id": release_id,
145+
**kwargs,
146+
},
147+
)
108148

109149
@validate_api_args(
110150
"api_key",
@@ -123,11 +163,25 @@ def get_release_tags(self, release_id: int, **kwargs) -> dict:
123163
)
124164
def get_release_related_tags(self, release_id: int, tag_names: str, **kwargs) -> dict:
125165
"""Get release related tags by ID."""
126-
return self._get(f"release/related_tags", {"release_id": release_id, "tag_names": tag_names, **kwargs,})
166+
return self._get(
167+
f"release/related_tags",
168+
{
169+
"release_id": release_id,
170+
"tag_names": tag_names,
171+
**kwargs,
172+
},
173+
)
127174

128175
@validate_api_args(
129176
"api_key", "file_type", "release_id", "element_id", "include_observation_values", "observation_date"
130177
)
131178
def get_release_tables(self, release_id: int, element_id: int = None, **kwargs) -> dict:
132179
"""Get release tables by ID."""
133-
return self._get(f"release/tables", {"release_id": release_id, "element_id": element_id, **kwargs,})
180+
return self._get(
181+
f"release/tables",
182+
{
183+
"release_id": release_id,
184+
"element_id": element_id,
185+
**kwargs,
186+
},
187+
)

0 commit comments

Comments
 (0)