Skip to content

Commit

Permalink
43 - Updates NHLClient to use https.Client on requests. (#44)
Browse files Browse the repository at this point in the history
Allows NHLClient to be configured with additional configuration options: timeout, ssl_verify, follow_redirects.  These are configurable at the instantiation point.

Updates tests to now mock httxp.Client.get instead of httpx.get.

Updates README.md with new configuration options available
  • Loading branch information
coreyjs committed Feb 21, 2024
1 parent e7fe292 commit 1bdcc6d
Show file tree
Hide file tree
Showing 11 changed files with 57 additions and 36 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ Im available on [Bluesky](https://bsky.app/profile/coreyjs.dev) for any question
from nhlpy import NHLClient

client = NHLClient()
# OR
client = NHLClient(verbose=True) # a tad more logging such as the URL being called
# Fore more verbose logging
client = NHLClient(verbose=True)
# OR Other available configurations:
client = NHLClient(verbose={bool}, timeout={int}, ssl_verify={bool}, follow_redirects={bool})
```
---
## Stats with QueryBuilder
Expand Down
2 changes: 1 addition & 1 deletion nhlpy/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Should this be driven by the main pyproject.toml file? yes, is it super convoluted? yes, can it wait? sure

__version__ = "2.3.4"
__version__ = "2.4.0"
8 changes: 7 additions & 1 deletion nhlpy/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
class ClientConfig:
def __init__(self, verbose: bool = False) -> None:
def __init__(
self, verbose: bool = False, timeout: int = 10, ssl_verify: bool = True, follow_redirects: bool = True
) -> None:
self.verbose = verbose
self.timeout = timeout
self.ssl_verify = ssl_verify
self.follow_redirects = follow_redirects

self.api_web_base_url = "https://api-web.nhle.com"
self.api_base_url = "https://api.nhle.com"
self.api_web_api_ver = "/v1/"
12 changes: 8 additions & 4 deletions nhlpy/http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ def get(self, resource: str) -> httpx.request:
:param resource:
:return:
"""
r: httpx.request = httpx.get(
url=f"{self._config.api_web_base_url}{self._config.api_web_api_ver}{resource}", follow_redirects=True
)
with httpx.Client(
verify=self._config.ssl_verify, timeout=self._config.timeout, follow_redirects=self._config.follow_redirects
) as client:
r: httpx.request = client.get(url=f"{self._config.api_web_base_url}{self._config.api_web_api_ver}{resource}")

if self._config.verbose:
logging.info(f"API URL: {r.url}")
Expand All @@ -30,7 +31,10 @@ def get_by_url(self, full_resource: str, query_params: dict = None) -> httpx.req
:param full_resource: The full resource to get.
:return:
"""
r: httpx.request = httpx.get(url=full_resource, params=query_params, follow_redirects=True)
with httpx.Client(
verify=self._config.ssl_verify, timeout=self._config.timeout, follow_redirects=self._config.follow_redirects
) as client:
r: httpx.request = client.get(url=full_resource, params=query_params)

if self._config.verbose:
logging.info(f"API URL: {r.url}")
Expand Down
15 changes: 12 additions & 3 deletions nhlpy/nhl_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,20 @@ class NHLClient:
client = NHLClient(verbose=True) # for a lil extra logging
"""

def __init__(self, verbose: bool = False) -> None:
def __init__(
self, verbose: bool = False, timeout: int = 10, ssl_verify: bool = True, follow_redirects: bool = True
) -> None:
"""
param: verbose: If True, will print out the URL of the API call.
:param follow_redirects: bool. Some of these endpoints use redirects (ew). This is the case when using
endpoints that use "/now" in them, which will redirect to todays data.
:param verbose: bool, Defaults to False. Set to True for extra logging.
:param timeout: int, Defaults to 10 seconds.
:param ssl_verify: bool, Defaults to True. Set to false if you want to ignore SSL verification.
"""
self._config = ClientConfig(verbose=verbose)
# This config type setup isnt doing what I thought it would. This will be reworked later on.
self._config = ClientConfig(
verbose=verbose, timeout=timeout, ssl_verify=ssl_verify, follow_redirects=follow_redirects
)
self._http_client = HttpClient(self._config)

self.teams = teams.Teams(http_client=self._http_client)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "nhl-api-py"
version = "2.3.4"
version = "2.4.0"
description = "NHL API. For standings, team stats, outcomes, player information. Contains each individual API endpoint as well as convience methods for easy data loading in Pandas or any ML applications."
authors = ["Corey Schaf <[email protected]>"]
readme = "README.md"
Expand Down
8 changes: 4 additions & 4 deletions tests/test_game_center.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
from unittest import mock


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_boxscore(h_m, nhl_client):
nhl_client.game_center.boxscore(game_id="2020020001")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/gamecenter/2020020001/boxscore"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_play_by_play(h_m, nhl_client):
nhl_client.game_center.play_by_play(game_id="2020020001")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/gamecenter/2020020001/play-by-play"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_landing_page(h_m, nhl_client):
nhl_client.game_center.landing(game_id="2020020001")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/gamecenter/2020020001/landing"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_score_now(h_m, nhl_client):
nhl_client.game_center.score_now()
h_m.assert_called_once()
Expand Down
14 changes: 7 additions & 7 deletions tests/test_schedule.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,49 @@
from unittest import mock


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_with_date(h_m, nhl_client):
nhl_client.schedule.get_schedule(date="2021-01-01")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/schedule/2021-01-01"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_with_no_date(h_m, nhl_client):
nhl_client.schedule.get_schedule()
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/schedule/now"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_by_team_by_month_with_month(h_m, nhl_client):
nhl_client.schedule.get_schedule_by_team_by_month(team_abbr="BUF", month="2023-11")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/club-schedule/BUF/month/2023-11"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_by_team_by_month_with_no_month(h_m, nhl_client):
nhl_client.schedule.get_schedule_by_team_by_month(team_abbr="BUF")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/club-schedule/BUF/month/now"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_by_team_by_week(h_m, nhl_client):
nhl_client.schedule.get_schedule_by_team_by_week(team_abbr="BUF")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/club-schedule/BUF/week/now"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_schedule_by_team_by_week_with_date(h_m, nhl_client):
nhl_client.schedule.get_schedule_by_team_by_week(team_abbr="BUF", date="2024-02-10")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/club-schedule/BUF/week/2024-02-10"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_season_schedule(h_m, nhl_client):
nhl_client.schedule.get_season_schedule(team_abbr="BUF", season="20202021")
h_m.assert_called_once()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_standings.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from unittest import mock


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_standings(h_m, nhl_client):
nhl_client.standings.get_standings()
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/standings/now"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_get_standings_with_cache_load(h_m, nhl_client):
nhl_client.standings.get_standings(season="20202021", cache=True)
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/standings/2021-05-19"
18 changes: 9 additions & 9 deletions tests/test_stats.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
from unittest import mock


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_stats_season(h_m, nhl_client):
nhl_client.stats.club_stats_season(team_abbr="BUF")
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/club-stats-season/BUF"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_player_career_stats(h_m, nhl_client):
nhl_client.stats.player_career_stats(player_id=8481528)
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/player/8481528/landing"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_team_summary_single_year(h_m, nhl_client):
nhl_client.stats.team_summary(start_season="20232024", end_season="20232024")
h_m.assert_called_once()
Expand All @@ -33,7 +33,7 @@ def test_team_summary_single_year(h_m, nhl_client):
}


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def team_test_summary_year_range(h_m, nhl_client):
nhl_client.stats.team_summary(start_season="20202021", end_season="20232024")
h_m.assert_called_once()
Expand All @@ -51,7 +51,7 @@ def team_test_summary_year_range(h_m, nhl_client):
}


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def team_test_summary_year_range_playoffs(h_m, nhl_client):
nhl_client.stats.team_summary(start_season="20182019", end_season="20222023", game_type_id=3)
h_m.assert_called_once()
Expand All @@ -69,7 +69,7 @@ def team_test_summary_year_range_playoffs(h_m, nhl_client):
}


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_skater_stats_summary(h_m, nhl_client):
nhl_client.stats.skater_stats_summary_simple(start_season="20232024", end_season="20232024")
h_m.assert_called_once()
Expand All @@ -87,7 +87,7 @@ def test_skater_stats_summary(h_m, nhl_client):
}


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_skater_stats_summary_franchise(h_m, nhl_client):
nhl_client.stats.skater_stats_summary_simple(start_season="20232024", end_season="20232024", franchise_id=19)
h_m.assert_called_once()
Expand All @@ -105,14 +105,14 @@ def test_skater_stats_summary_franchise(h_m, nhl_client):
}


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_player_game_log(h_m, nhl_client):
nhl_client.stats.player_game_log(player_id="8481528", season_id="20232024", game_type=2)
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api-web.nhle.com/v1/player/8481528/game-log/20232024/2"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_player_game_log_playoffs(h_m, nhl_client):
nhl_client.stats.player_game_log(player_id="8481528", season_id="20232024", game_type=3)
h_m.assert_called_once()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_teams.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from unittest import mock


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_stats_summary(h_m, nhl_client):
nhl_client.teams.team_stats_summary()
h_m.assert_called_once()
assert h_m.call_args[1]["url"] == "https://api.nhle.com/stats/rest/en/team/summary"


@mock.patch("httpx.get")
@mock.patch("httpx.Client.get")
def test_roster(h_m, nhl_client):
nhl_client.teams.roster(team_abbr="BUF", season="20202021")
h_m.assert_called_once()
Expand Down

0 comments on commit 1bdcc6d

Please sign in to comment.