nhl-api-py 2.2.6__tar.gz → 2.3.1__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.
Files changed (39) hide show
  1. nhl_api_py-2.3.1/PKG-INFO +370 -0
  2. nhl_api_py-2.3.1/README.md +344 -0
  3. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/_version.py +1 -1
  4. nhl_api_py-2.3.1/nhlpy/api/__init__.py +0 -0
  5. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/game_center.py +5 -2
  6. nhl_api_py-2.3.1/nhlpy/api/query/__init__.py +2 -0
  7. nhl_api_py-2.3.1/nhlpy/api/query/builder.py +50 -0
  8. nhl_api_py-2.3.1/nhlpy/api/query/filters/__init__.py +12 -0
  9. nhl_api_py-2.3.1/nhlpy/api/query/filters/decision.py +28 -0
  10. nhl_api_py-2.3.1/nhlpy/api/query/filters/draft.py +27 -0
  11. nhl_api_py-2.3.1/nhlpy/api/query/filters/experience.py +20 -0
  12. nhl_api_py-2.3.1/nhlpy/api/query/filters/franchise.py +15 -0
  13. nhl_api_py-2.3.1/nhlpy/api/query/filters/game_type.py +15 -0
  14. nhl_api_py-2.3.1/nhlpy/api/query/filters/home_road.py +19 -0
  15. nhl_api_py-2.3.1/nhlpy/api/query/filters/nationality.py +31 -0
  16. nhl_api_py-2.3.1/nhlpy/api/query/filters/opponent.py +19 -0
  17. nhl_api_py-2.3.1/nhlpy/api/query/filters/position.py +32 -0
  18. nhl_api_py-2.3.1/nhlpy/api/query/filters/season.py +22 -0
  19. nhl_api_py-2.3.1/nhlpy/api/query/filters/shoot_catch.py +19 -0
  20. nhl_api_py-2.3.1/nhlpy/api/query/filters/status.py +32 -0
  21. nhl_api_py-2.3.1/nhlpy/api/query/sorting/__init__.py +0 -0
  22. nhl_api_py-2.3.1/nhlpy/api/query/sorting/sorting_options.py +146 -0
  23. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/stats.py +21 -14
  24. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/pyproject.toml +1 -1
  25. nhl_api_py-2.2.6/PKG-INFO +0 -195
  26. nhl_api_py-2.2.6/README.md +0 -169
  27. nhl_api_py-2.2.6/nhlpy/api/__init__.py +0 -30
  28. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/__init__.py +0 -0
  29. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/helpers.py +0 -0
  30. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/misc.py +0 -0
  31. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/schedule.py +0 -0
  32. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/standings.py +0 -0
  33. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/api/teams.py +0 -0
  34. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/config.py +0 -0
  35. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/data/seasonal_information_manifest.json +0 -0
  36. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/data/team_stat_ids.json +0 -0
  37. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/data/teams_20232024.json +0 -0
  38. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/http_client.py +0 -0
  39. {nhl_api_py-2.2.6 → nhl_api_py-2.3.1}/nhlpy/nhl_client.py +0 -0
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.1
2
+ Name: nhl-api-py
3
+ Version: 2.3.1
4
+ Summary: 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.
5
+ Home-page: https://github.com/coreyjs/nhl-api-py
6
+ License: GPL-3.0-or-later
7
+ Keywords: nhl,api,wrapper,hockey,sports
8
+ Author: Corey Schaf
9
+ Author-email: cschaf@gmail.com
10
+ Requires-Python: >=3.9,<4.0
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3 :: Only
20
+ Classifier: Topic :: Software Development :: Libraries
21
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Dist: httpx
24
+ Project-URL: Repository, https://github.com/coreyjs/nhl-api-py
25
+ Description-Content-Type: text/markdown
26
+
27
+ [![PyPI version](https://badge.fury.io/py/nhl-api-py.svg)](https://badge.fury.io/py/nhl-api-py)
28
+ ![nhl-api-py workflow](https://github.com/coreyjs/nhl-api-py/actions/workflows/python-app.yml/badge.svg?branch=main)
29
+
30
+ # NHL-API-PY
31
+
32
+
33
+ ## About
34
+
35
+ NHL-api-py is a Python package that provides a simple wrapper around the
36
+ NHL API, allowing you to easily access and retrieve NHL data in your Python
37
+ applications.
38
+
39
+ Note: This is ~~very early~~ maturing, I created this to help me with some machine learning
40
+ projects around the NHL and the NHL data sets. Special thanks to https://github.com/erunion/sport-api-specifications/tree/master/nhl and https://gitlab.com/dword4/nhlapi/-/blob/master/stats-api.md.
41
+
42
+ ### Developer Note: This is being updated with the new, also undocumented, NHL API.
43
+
44
+ More endpoints will be flushed out and completed as they
45
+ are discovered. If you find any, open a ticket or post in the discussions tab. I would love to hear more.
46
+
47
+
48
+ ---
49
+ ## Contact
50
+ Im available on [Bluesky](https://bsky.app/profile/coreyjs.dev) for any questions or just general chats about enhancements.
51
+
52
+ ---
53
+
54
+
55
+
56
+ # Usage
57
+ ```python
58
+ from nhlpy import NHLClient
59
+
60
+ client = NHLClient()
61
+ # OR
62
+ client = NHLClient(verbose=True) # a tad more logging such as the URL being called
63
+ ```
64
+ ---
65
+ ## Stats with QueryBuilder
66
+
67
+ The skater stats endpoint can be accessed using the new query builder. It should make
68
+ creating and understanding the queries a bit easier. Filters are being added as I go, and will match up
69
+ to what the NHL API will allow.
70
+
71
+
72
+
73
+ ### Sorting
74
+ The sorting is a list of dictionaries similar to below. You can supply your own, otherwise it will
75
+ default to the default sort properties that the stat dashboard uses. All sorting defaults are found
76
+ in the `nhl-api-py/nhlpy/api/query/sorting/sorting_options.py` file.
77
+
78
+ <details>
79
+ <summary>Default Sorting</summary>
80
+
81
+ ```python
82
+ skater_summary_default_sorting = [
83
+ {"property": "points", "direction": "DESC"},
84
+ {"property": "gamesPlayed", "direction": "ASC"},
85
+ {"property": "playerId", "direction": "ASC"},
86
+ ]
87
+ ```
88
+ </details>
89
+
90
+ ---
91
+
92
+ ### Report Types
93
+ The following report types are available. These are used to build the request url. So `/summary`, `/bios`, etc.
94
+
95
+ ```bash
96
+ summary
97
+ bios
98
+ faceoffpercentages
99
+ faceoffwins
100
+ goalsForAgainst
101
+ realtime
102
+ penalties
103
+ penaltykill
104
+ penaltyShots
105
+ powerplay
106
+ puckPossessions
107
+ summaryshooting
108
+ percentages
109
+ scoringRates
110
+ scoringpergame
111
+ shootout
112
+ shottype
113
+ timeonice
114
+ ```
115
+
116
+ ### Available Filters
117
+
118
+ ```python
119
+ from nhlpy.api.query.filters.franchise import FranchiseQuery
120
+ from nhlpy.api.query.filters.shoot_catch import ShootCatchesQuery
121
+ from nhlpy.api.query.filters.draft import DraftQuery
122
+ from nhlpy.api.query.filters.season import SeasonQuery
123
+ from nhlpy.api.query.filters.game_type import GameTypeQuery
124
+ from nhlpy.api.query.filters.position import PositionQuery, PositionTypes
125
+ from nhlpy.api.query.filters.status import StatusQuery
126
+ from nhlpy.api.query.filters.opponent import OpponentQuery
127
+ from nhlpy.api.query.filters.home_road import HomeRoadQuery
128
+ from nhlpy.api.query.filters.experience import ExperienceQuery
129
+ from nhlpy.api.query.filters.decision import DecisionQuery
130
+
131
+ filters = [
132
+ GameTypeQuery(game_type="2"),
133
+ DraftQuery(year="2020", draft_round="2"),
134
+ SeasonQuery(season_start="20202021", season_end="20232024"),
135
+ PositionQuery(position=PositionTypes.ALL_FORWARDS),
136
+ ShootCatchesQuery(shoot_catch="L"),
137
+ HomeRoadQuery(home_road="H"),
138
+ FranchiseQuery(franchise_id="1"),
139
+ StatusQuery(is_active=True) #for active players OR for HOF players StatusQuery(is_hall_of_fame=True),
140
+ OpponentQuery(opponent_franchise_id="2"),
141
+ ExperienceQuery(is_rookie=True), # for rookies || ExperienceQuery(is_rookie=False) #for veteran
142
+ DecisionQuery(decision="W") # OR DecisionQuery(decision="L") OR DecisionQuery(decision="O")
143
+ ]
144
+ ```
145
+
146
+
147
+ ### Example
148
+ ```python
149
+ from nhlpy.api.query.builder import QueryBuilder, QueryContext
150
+ from nhlpy.nhl_client import NHLClient
151
+ from nhlpy.api.query.filters.draft import DraftQuery
152
+ from nhlpy.api.query.filters.season import SeasonQuery
153
+ from nhlpy.api.query.filters.game_type import GameTypeQuery
154
+ from nhlpy.api.query.filters.position import PositionQuery, PositionTypes
155
+
156
+ client = NHLClient(verbose=True)
157
+
158
+ filters = [
159
+ GameTypeQuery(game_type="2"),
160
+ DraftQuery(year="2020", draft_round="2"),
161
+ SeasonQuery(season_start="20202021", season_end="20232024"),
162
+ PositionQuery(position=PositionTypes.ALL_FORWARDS)
163
+ ]
164
+
165
+ query_builder = QueryBuilder()
166
+ query_context: QueryContext = query_builder.build(filters=filters)
167
+
168
+ data = client.stats.skater_stats_with_query_context(
169
+ report_type='summary',
170
+ query_context=query_context,
171
+ aggregate=True
172
+ )
173
+ ```
174
+
175
+ ### Granular Filtering
176
+ Each API request uses an additional query parameter called `factCayenneExp`. This defaults to `gamesPlayed>=1`
177
+ but can be overridden by setting the `fact_query` parameter in the `QueryContextObject` object. These can
178
+ be combined together with `and` to create a more complex query. It supports `>`, `<`, `>=`, `<=`. For example: `shootingPct>=0.01 and timeOnIcePerGame>=60 and faceoffWinPct>=0.01 and shots>=1`
179
+
180
+
181
+ This should support the following filters:
182
+
183
+ - `gamesPlayed`
184
+ - `points`
185
+ - `goals`
186
+ - `pointsPerGame`
187
+ - `penaltyMinutes`
188
+ - `plusMinus`
189
+ - `ppGoals` # power play goals
190
+ - `evGoals` # even strength goals
191
+ - `pointsPerGame`
192
+ - `penaltyMinutes`
193
+ - `evPoints` # even strength points
194
+ - `ppPoints` # power play points
195
+ - `gameWinningGoals`
196
+ - `otGoals`
197
+ - `shPoints` # short handed points
198
+ - `shGoals` # short handed goals
199
+ - `shootingPct`
200
+ - `timeOnIcePerGame`
201
+ - `faceoffWinPct`
202
+ - `shots`
203
+
204
+ ```python
205
+ .....
206
+ query_builder = QueryBuilder()
207
+ query_context: QueryContext = query_builder.build(filters=filters)
208
+
209
+ query_context.fact_query = "gamesPlayed>=1 and goals>=10" # defaults to gamesPlayed>=1
210
+
211
+ data = client.stats.skater_stats_with_query_context(
212
+ report_type='summary',
213
+ query_context=query_context,
214
+ aggregate=True
215
+ )
216
+ ```
217
+
218
+
219
+ ### Invalid Query / Errors
220
+
221
+ The `QueryContext` object will hold the result of the built query with the supplied queries.
222
+ In the event of an invalid query (bad data, wrong option, etc), the `QueryContext` object will
223
+ hold all the errors that were encountered during the build process. This should help in debugging.
224
+
225
+ You can quickly check the `QueryContext` object for errors by calling `query_context.is_valid()`. Any "invalid" filters
226
+ will be removed from the output query, but anything that is still valid will be included.
227
+
228
+ ```python
229
+ ...
230
+ query_context: QueryContext = query_builder.build(filters=filters)
231
+ query_context.is_valid() # False if any of the filters fails its validation check
232
+ query_context.errors
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Additional Stats Endpoints (In development)
238
+
239
+ ```python
240
+
241
+ client.stats.club_stats_season(team_abbr="BUF") # kinda weird endpoint.
242
+
243
+ client.stats.player_career_stats(player_id="8478402")
244
+
245
+ # Team Summary Stats.
246
+ # These have lots of available parameters. You can also tap into the apache cayenne expressions to build custom
247
+ # queries, if you have that knowledge.
248
+ client.stats.team_summary(start_season="20202021", end_season="20212022", game_type_id=2)
249
+ client.stats.team_summary(start_season="20202021", end_season="20212022")
250
+
251
+
252
+ # Skater Summary Stats.
253
+ # Queries for skaters for year ranges, filterable down by franchise.
254
+ client.stats.skater_stats_summary(start_season="20232024", end_season="20232024")
255
+ client.stats.skater_stats_summary(franchise_id=10, start_season="20232024", end_season="20232024")
256
+ ```
257
+ ---
258
+
259
+
260
+ ## Schedule Endpoints
261
+
262
+ ```python
263
+ client.schedule.get_schedule(date="2021-01-13")
264
+ client.schedule.get_schedule()
265
+
266
+ client.schedule.get_schedule_by_team_by_month(team_abbr="BUF")
267
+ client.schedule.get_schedule_by_team_by_month(team_abbr="BUF", month="2021-01")
268
+
269
+ client.schedule.get_schedule_by_team_by_week(team_abbr="BUF")
270
+ client.schedule.get_schedule_by_team_by_week(team_abbr="BUF", date="2024-01-01")
271
+
272
+ client.schedule.get_season_schedule(team_abbr="BUF", season="20212022")
273
+
274
+ client.schedule.schedule_calendar(date="2023-11-23")
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Standings Endpoints
280
+
281
+ ```python
282
+ client.standings.get_standings()
283
+ client.standings.get_standings(date="2021-01-13")
284
+ client.standings.get_standings(season="202222023")
285
+
286
+ # standings manifest. This returns a ton of information for every season ever it seems like
287
+ # This calls the API for this info, I also cache this in /data/seasonal_information_manifest.json
288
+ # for less API calls since this only changes yearly.
289
+ client.standings.season_standing_manifest()
290
+ ```
291
+ ---
292
+
293
+ ## Teams Endpoints
294
+
295
+ ```python
296
+ client.teams.teams_info() # returns id + abbrevation + name of all teams
297
+
298
+ client.teams.team_stats_summary(lang="en") # I honestly dont know. This is missing teams and has teams long abandoned.
299
+ ```
300
+
301
+ ---
302
+
303
+ ## Game Center
304
+ ```python
305
+ client.game_center.boxscore(game_id="2023020280")
306
+
307
+ client.game_center.play_by_play(game_id="2023020280")
308
+
309
+ client.game_center.landing(game_id="2023020280")
310
+
311
+ client.game_center.score_now()
312
+ ```
313
+
314
+ ---
315
+
316
+ ## Misc Endpoints
317
+ ```python
318
+ client.misc.glossary()
319
+
320
+ client.misc.config()
321
+
322
+ client.misc.countries()
323
+
324
+ client.misc.season_specific_rules_and_info()
325
+
326
+ client.misc.draft_year_and_rounds()
327
+ ```
328
+
329
+ ---
330
+ ## Insomnia Rest Client Export
331
+
332
+ [Insomnia Rest Client](https://insomnia.rest) is a great tool for testing
333
+
334
+ nhl_api-{ver}.json in the root folder is an export of the endpoints I have
335
+ been working through using the Insomnia Rest Client. You can import this directly
336
+ into the client and use it to test the endpoints. I will be updating this as I go
337
+
338
+
339
+ - - -
340
+
341
+
342
+ ## Developers
343
+
344
+ 1) Install [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
345
+
346
+ `curl -sSL https://install.python-poetry.org | python3 -`
347
+
348
+ or using pipx
349
+
350
+ `pipx install poetry`
351
+
352
+
353
+ 2) `poetry install --with dev`
354
+
355
+ 3) `poetry shell`
356
+
357
+
358
+ ### Build Pipeline
359
+ The build pipeline will run `black`, `ruff`, and `pytest`. Please make sure these are passing before submitting a PR.
360
+
361
+ ```python
362
+
363
+ $ poetry shell
364
+
365
+ # You can then run the following
366
+ $ pytest
367
+ $ ruff .
368
+ $ black .
369
+
370
+ ```
@@ -0,0 +1,344 @@
1
+ [![PyPI version](https://badge.fury.io/py/nhl-api-py.svg)](https://badge.fury.io/py/nhl-api-py)
2
+ ![nhl-api-py workflow](https://github.com/coreyjs/nhl-api-py/actions/workflows/python-app.yml/badge.svg?branch=main)
3
+
4
+ # NHL-API-PY
5
+
6
+
7
+ ## About
8
+
9
+ NHL-api-py is a Python package that provides a simple wrapper around the
10
+ NHL API, allowing you to easily access and retrieve NHL data in your Python
11
+ applications.
12
+
13
+ Note: This is ~~very early~~ maturing, I created this to help me with some machine learning
14
+ projects around the NHL and the NHL data sets. Special thanks to https://github.com/erunion/sport-api-specifications/tree/master/nhl and https://gitlab.com/dword4/nhlapi/-/blob/master/stats-api.md.
15
+
16
+ ### Developer Note: This is being updated with the new, also undocumented, NHL API.
17
+
18
+ More endpoints will be flushed out and completed as they
19
+ are discovered. If you find any, open a ticket or post in the discussions tab. I would love to hear more.
20
+
21
+
22
+ ---
23
+ ## Contact
24
+ Im available on [Bluesky](https://bsky.app/profile/coreyjs.dev) for any questions or just general chats about enhancements.
25
+
26
+ ---
27
+
28
+
29
+
30
+ # Usage
31
+ ```python
32
+ from nhlpy import NHLClient
33
+
34
+ client = NHLClient()
35
+ # OR
36
+ client = NHLClient(verbose=True) # a tad more logging such as the URL being called
37
+ ```
38
+ ---
39
+ ## Stats with QueryBuilder
40
+
41
+ The skater stats endpoint can be accessed using the new query builder. It should make
42
+ creating and understanding the queries a bit easier. Filters are being added as I go, and will match up
43
+ to what the NHL API will allow.
44
+
45
+
46
+
47
+ ### Sorting
48
+ The sorting is a list of dictionaries similar to below. You can supply your own, otherwise it will
49
+ default to the default sort properties that the stat dashboard uses. All sorting defaults are found
50
+ in the `nhl-api-py/nhlpy/api/query/sorting/sorting_options.py` file.
51
+
52
+ <details>
53
+ <summary>Default Sorting</summary>
54
+
55
+ ```python
56
+ skater_summary_default_sorting = [
57
+ {"property": "points", "direction": "DESC"},
58
+ {"property": "gamesPlayed", "direction": "ASC"},
59
+ {"property": "playerId", "direction": "ASC"},
60
+ ]
61
+ ```
62
+ </details>
63
+
64
+ ---
65
+
66
+ ### Report Types
67
+ The following report types are available. These are used to build the request url. So `/summary`, `/bios`, etc.
68
+
69
+ ```bash
70
+ summary
71
+ bios
72
+ faceoffpercentages
73
+ faceoffwins
74
+ goalsForAgainst
75
+ realtime
76
+ penalties
77
+ penaltykill
78
+ penaltyShots
79
+ powerplay
80
+ puckPossessions
81
+ summaryshooting
82
+ percentages
83
+ scoringRates
84
+ scoringpergame
85
+ shootout
86
+ shottype
87
+ timeonice
88
+ ```
89
+
90
+ ### Available Filters
91
+
92
+ ```python
93
+ from nhlpy.api.query.filters.franchise import FranchiseQuery
94
+ from nhlpy.api.query.filters.shoot_catch import ShootCatchesQuery
95
+ from nhlpy.api.query.filters.draft import DraftQuery
96
+ from nhlpy.api.query.filters.season import SeasonQuery
97
+ from nhlpy.api.query.filters.game_type import GameTypeQuery
98
+ from nhlpy.api.query.filters.position import PositionQuery, PositionTypes
99
+ from nhlpy.api.query.filters.status import StatusQuery
100
+ from nhlpy.api.query.filters.opponent import OpponentQuery
101
+ from nhlpy.api.query.filters.home_road import HomeRoadQuery
102
+ from nhlpy.api.query.filters.experience import ExperienceQuery
103
+ from nhlpy.api.query.filters.decision import DecisionQuery
104
+
105
+ filters = [
106
+ GameTypeQuery(game_type="2"),
107
+ DraftQuery(year="2020", draft_round="2"),
108
+ SeasonQuery(season_start="20202021", season_end="20232024"),
109
+ PositionQuery(position=PositionTypes.ALL_FORWARDS),
110
+ ShootCatchesQuery(shoot_catch="L"),
111
+ HomeRoadQuery(home_road="H"),
112
+ FranchiseQuery(franchise_id="1"),
113
+ StatusQuery(is_active=True) #for active players OR for HOF players StatusQuery(is_hall_of_fame=True),
114
+ OpponentQuery(opponent_franchise_id="2"),
115
+ ExperienceQuery(is_rookie=True), # for rookies || ExperienceQuery(is_rookie=False) #for veteran
116
+ DecisionQuery(decision="W") # OR DecisionQuery(decision="L") OR DecisionQuery(decision="O")
117
+ ]
118
+ ```
119
+
120
+
121
+ ### Example
122
+ ```python
123
+ from nhlpy.api.query.builder import QueryBuilder, QueryContext
124
+ from nhlpy.nhl_client import NHLClient
125
+ from nhlpy.api.query.filters.draft import DraftQuery
126
+ from nhlpy.api.query.filters.season import SeasonQuery
127
+ from nhlpy.api.query.filters.game_type import GameTypeQuery
128
+ from nhlpy.api.query.filters.position import PositionQuery, PositionTypes
129
+
130
+ client = NHLClient(verbose=True)
131
+
132
+ filters = [
133
+ GameTypeQuery(game_type="2"),
134
+ DraftQuery(year="2020", draft_round="2"),
135
+ SeasonQuery(season_start="20202021", season_end="20232024"),
136
+ PositionQuery(position=PositionTypes.ALL_FORWARDS)
137
+ ]
138
+
139
+ query_builder = QueryBuilder()
140
+ query_context: QueryContext = query_builder.build(filters=filters)
141
+
142
+ data = client.stats.skater_stats_with_query_context(
143
+ report_type='summary',
144
+ query_context=query_context,
145
+ aggregate=True
146
+ )
147
+ ```
148
+
149
+ ### Granular Filtering
150
+ Each API request uses an additional query parameter called `factCayenneExp`. This defaults to `gamesPlayed>=1`
151
+ but can be overridden by setting the `fact_query` parameter in the `QueryContextObject` object. These can
152
+ be combined together with `and` to create a more complex query. It supports `>`, `<`, `>=`, `<=`. For example: `shootingPct>=0.01 and timeOnIcePerGame>=60 and faceoffWinPct>=0.01 and shots>=1`
153
+
154
+
155
+ This should support the following filters:
156
+
157
+ - `gamesPlayed`
158
+ - `points`
159
+ - `goals`
160
+ - `pointsPerGame`
161
+ - `penaltyMinutes`
162
+ - `plusMinus`
163
+ - `ppGoals` # power play goals
164
+ - `evGoals` # even strength goals
165
+ - `pointsPerGame`
166
+ - `penaltyMinutes`
167
+ - `evPoints` # even strength points
168
+ - `ppPoints` # power play points
169
+ - `gameWinningGoals`
170
+ - `otGoals`
171
+ - `shPoints` # short handed points
172
+ - `shGoals` # short handed goals
173
+ - `shootingPct`
174
+ - `timeOnIcePerGame`
175
+ - `faceoffWinPct`
176
+ - `shots`
177
+
178
+ ```python
179
+ .....
180
+ query_builder = QueryBuilder()
181
+ query_context: QueryContext = query_builder.build(filters=filters)
182
+
183
+ query_context.fact_query = "gamesPlayed>=1 and goals>=10" # defaults to gamesPlayed>=1
184
+
185
+ data = client.stats.skater_stats_with_query_context(
186
+ report_type='summary',
187
+ query_context=query_context,
188
+ aggregate=True
189
+ )
190
+ ```
191
+
192
+
193
+ ### Invalid Query / Errors
194
+
195
+ The `QueryContext` object will hold the result of the built query with the supplied queries.
196
+ In the event of an invalid query (bad data, wrong option, etc), the `QueryContext` object will
197
+ hold all the errors that were encountered during the build process. This should help in debugging.
198
+
199
+ You can quickly check the `QueryContext` object for errors by calling `query_context.is_valid()`. Any "invalid" filters
200
+ will be removed from the output query, but anything that is still valid will be included.
201
+
202
+ ```python
203
+ ...
204
+ query_context: QueryContext = query_builder.build(filters=filters)
205
+ query_context.is_valid() # False if any of the filters fails its validation check
206
+ query_context.errors
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Additional Stats Endpoints (In development)
212
+
213
+ ```python
214
+
215
+ client.stats.club_stats_season(team_abbr="BUF") # kinda weird endpoint.
216
+
217
+ client.stats.player_career_stats(player_id="8478402")
218
+
219
+ # Team Summary Stats.
220
+ # These have lots of available parameters. You can also tap into the apache cayenne expressions to build custom
221
+ # queries, if you have that knowledge.
222
+ client.stats.team_summary(start_season="20202021", end_season="20212022", game_type_id=2)
223
+ client.stats.team_summary(start_season="20202021", end_season="20212022")
224
+
225
+
226
+ # Skater Summary Stats.
227
+ # Queries for skaters for year ranges, filterable down by franchise.
228
+ client.stats.skater_stats_summary(start_season="20232024", end_season="20232024")
229
+ client.stats.skater_stats_summary(franchise_id=10, start_season="20232024", end_season="20232024")
230
+ ```
231
+ ---
232
+
233
+
234
+ ## Schedule Endpoints
235
+
236
+ ```python
237
+ client.schedule.get_schedule(date="2021-01-13")
238
+ client.schedule.get_schedule()
239
+
240
+ client.schedule.get_schedule_by_team_by_month(team_abbr="BUF")
241
+ client.schedule.get_schedule_by_team_by_month(team_abbr="BUF", month="2021-01")
242
+
243
+ client.schedule.get_schedule_by_team_by_week(team_abbr="BUF")
244
+ client.schedule.get_schedule_by_team_by_week(team_abbr="BUF", date="2024-01-01")
245
+
246
+ client.schedule.get_season_schedule(team_abbr="BUF", season="20212022")
247
+
248
+ client.schedule.schedule_calendar(date="2023-11-23")
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Standings Endpoints
254
+
255
+ ```python
256
+ client.standings.get_standings()
257
+ client.standings.get_standings(date="2021-01-13")
258
+ client.standings.get_standings(season="202222023")
259
+
260
+ # standings manifest. This returns a ton of information for every season ever it seems like
261
+ # This calls the API for this info, I also cache this in /data/seasonal_information_manifest.json
262
+ # for less API calls since this only changes yearly.
263
+ client.standings.season_standing_manifest()
264
+ ```
265
+ ---
266
+
267
+ ## Teams Endpoints
268
+
269
+ ```python
270
+ client.teams.teams_info() # returns id + abbrevation + name of all teams
271
+
272
+ client.teams.team_stats_summary(lang="en") # I honestly dont know. This is missing teams and has teams long abandoned.
273
+ ```
274
+
275
+ ---
276
+
277
+ ## Game Center
278
+ ```python
279
+ client.game_center.boxscore(game_id="2023020280")
280
+
281
+ client.game_center.play_by_play(game_id="2023020280")
282
+
283
+ client.game_center.landing(game_id="2023020280")
284
+
285
+ client.game_center.score_now()
286
+ ```
287
+
288
+ ---
289
+
290
+ ## Misc Endpoints
291
+ ```python
292
+ client.misc.glossary()
293
+
294
+ client.misc.config()
295
+
296
+ client.misc.countries()
297
+
298
+ client.misc.season_specific_rules_and_info()
299
+
300
+ client.misc.draft_year_and_rounds()
301
+ ```
302
+
303
+ ---
304
+ ## Insomnia Rest Client Export
305
+
306
+ [Insomnia Rest Client](https://insomnia.rest) is a great tool for testing
307
+
308
+ nhl_api-{ver}.json in the root folder is an export of the endpoints I have
309
+ been working through using the Insomnia Rest Client. You can import this directly
310
+ into the client and use it to test the endpoints. I will be updating this as I go
311
+
312
+
313
+ - - -
314
+
315
+
316
+ ## Developers
317
+
318
+ 1) Install [Poetry](https://python-poetry.org/docs/#installing-with-the-official-installer)
319
+
320
+ `curl -sSL https://install.python-poetry.org | python3 -`
321
+
322
+ or using pipx
323
+
324
+ `pipx install poetry`
325
+
326
+
327
+ 2) `poetry install --with dev`
328
+
329
+ 3) `poetry shell`
330
+
331
+
332
+ ### Build Pipeline
333
+ The build pipeline will run `black`, `ruff`, and `pytest`. Please make sure these are passing before submitting a PR.
334
+
335
+ ```python
336
+
337
+ $ poetry shell
338
+
339
+ # You can then run the following
340
+ $ pytest
341
+ $ ruff .
342
+ $ black .
343
+
344
+ ```