Package: nhl-api-py
NHL-API-PYAboutNHL-api-py is a Python package that provides a simple wrapper around the
NHL API, allowing you to easily access and retrieve NHL data in your Python
applications.Note: This isvery earlymaturing, I created this to help me with some machine learning
projects around the NHL and the NHL data sets.  Special thanks tohttps://github.com/erunion/sport-api-specifications/tree/master/nhlandhttps://gitlab.com/dword4/nhlapi/-/blob/master/stats-api.md.Developer Note: This is being updated with the new, also undocumented, NHL API.More endpoints will be flushed out and completed as they
are discovered. If you find any, open a ticket or post in the discussions tab.   I would love to hear more.ContactIm available onBlueskyfor any questions or just general chats about enhancements.UsagefromnhlpyimportNHLClientclient=NHLClient()# Fore more verbose loggingclient=NHLClient(verbose=True)# OR Other available configurations:client=NHLClient(verbose={bool},timeout={int},ssl_verify={bool},follow_redirects={bool})Stats with QueryBuilderThe skater stats endpoint can be accessed using the new query builder.  It should make
creating and understanding the queries a bit easier.  Filters are being added as I go, and will match up
to what the NHL API will allow.The idea is to easily, and programatically, build up more complex queries using the query filters.  A quick example below:filters=[GameTypeQuery(game_type="2"),DraftQuery(year="2020",draft_round="2"),SeasonQuery(season_start="20202021",season_end="20232024"),PositionQuery(position=PositionTypes.ALL_FORWARDS)]SortingThe sorting is a list of dictionaries similar to below.  You can supply your own, otherwise it will
default to the default sort properties that the stat dashboard uses.  All sorting defaults are found
in thenhl-api-py/nhlpy/api/query/sorting/sorting_options.pyfile.Default Sortingskater_summary_default_sorting=[{"property":"points","direction":"DESC"},{"property":"gamesPlayed","direction":"ASC"},{"property":"playerId","direction":"ASC"},]Report TypesThe following report types are available.  These are used to build the request url.  So/summary,/bios, etc.summary
bios
faceoffpercentages
faceoffwins
goalsForAgainst
realtime
penalties
penaltykill
penaltyShots
powerplay
puckPossessions
summaryshooting
percentages
scoringRates
scoringpergame
shootout
shottype
timeoniceAvailable Filtersfromnhlpy.api.query.filters.franchiseimportFranchiseQueryfromnhlpy.api.query.filters.shoot_catchimportShootCatchesQueryfromnhlpy.api.query.filters.draftimportDraftQueryfromnhlpy.api.query.filters.seasonimportSeasonQueryfromnhlpy.api.query.filters.game_typeimportGameTypeQueryfromnhlpy.api.query.filters.positionimportPositionQuery,PositionTypesfromnhlpy.api.query.filters.statusimportStatusQueryfromnhlpy.api.query.filters.opponentimportOpponentQueryfromnhlpy.api.query.filters.home_roadimportHomeRoadQueryfromnhlpy.api.query.filters.experienceimportExperienceQueryfromnhlpy.api.query.filters.decisionimportDecisionQueryfilters=[GameTypeQuery(game_type="2"),DraftQuery(year="2020",draft_round="2"),SeasonQuery(season_start="20202021",season_end="20232024"),PositionQuery(position=PositionTypes.ALL_FORWARDS),ShootCatchesQuery(shoot_catch="L"),HomeRoadQuery(home_road="H"),FranchiseQuery(franchise_id="1"),StatusQuery(is_active=True)#for active players OR for HOF players StatusQuery(is_hall_of_fame=True),OpponentQuery(opponent_franchise_id="2"),ExperienceQuery(is_rookie=True),# for rookies || ExperienceQuery(is_rookie=False) #for veteranDecisionQuery(decision="W")# OR DecisionQuery(decision="L") OR DecisionQuery(decision="O")]Examplefromnhlpy.api.query.builderimportQueryBuilder,QueryContextfromnhlpy.nhl_clientimportNHLClientfromnhlpy.api.query.filters.draftimportDraftQueryfromnhlpy.api.query.filters.seasonimportSeasonQueryfromnhlpy.api.query.filters.game_typeimportGameTypeQueryfromnhlpy.api.query.filters.positionimportPositionQuery,PositionTypesclient=NHLClient(verbose=True)filters=[GameTypeQuery(game_type="2"),DraftQuery(year="2020",draft_round="2"),SeasonQuery(season_start="20202021",season_end="20232024"),PositionQuery(position=PositionTypes.ALL_FORWARDS)]query_builder=QueryBuilder()query_context:QueryContext=query_builder.build(filters=filters)data=client.stats.skater_stats_with_query_context(report_type='summary',query_context=query_context,aggregate=True)Granular FilteringEach API request uses an additional query parameter calledfactCayenneExp.  This defaults togamesPlayed>=1but can be overridden by setting thefact_queryparameter in theQueryContextObjectobject.  These can
be combined together withandto create a more complex query.  It supports>,<,>=,<=.  For example:shootingPct>=0.01 and timeOnIcePerGame>=60 and faceoffWinPct>=0.01 and shots>=1This should support the following filters:gamesPlayedpointsgoalspointsPerGamepenaltyMinutesplusMinusppGoals# power play goalsevGoals# even strength goalspointsPerGamepenaltyMinutesevPoints# even strength pointsppPoints# power play pointsgameWinningGoalsotGoalsshPoints# short handed pointsshGoals# short handed goalsshootingPcttimeOnIcePerGamefaceoffWinPctshots.....query_builder=QueryBuilder()query_context:QueryContext=query_builder.build(filters=filters)query_context.fact_query="gamesPlayed>=1 and goals>=10"# defaults to gamesPlayed>=1data=client.stats.skater_stats_with_query_context(report_type='summary',query_context=query_context,aggregate=True)Invalid Query / ErrorsTheQueryContextobject will hold the result of the built query with the supplied queries.
In the event of an invalid query (bad data, wrong option, etc), theQueryContextobject will
hold all the errors that were encountered during the build process.  This should help in debugging.You can quickly check theQueryContextobject for errors by callingquery_context.is_valid().  Any "invalid" filters
will be removed from the output query, but anything that is still valid will be included....query_context:QueryContext=query_builder.build(filters=filters)query_context.is_valid()# False if any of the filters fails its validation checkquery_context.errorsAdditional Stats Endpoints (In development)client.stats.club_stats_season(team_abbr="BUF")# kinda weird endpoint.client.stats.player_career_stats(player_id="8478402")# Team Summary Stats.#   These have lots of available parameters.  You can also tap into the apache cayenne expressions to build custom#   queries, if you have that knowledge.client.stats.team_summary(start_season="20202021",end_season="20212022",game_type_id=2)client.stats.team_summary(start_season="20202021",end_season="20212022")# Skater Summary Stats.#   Queries for skaters for year ranges, filterable down by franchise.client.stats.skater_stats_summary(start_season="20232024",end_season="20232024")client.stats.skater_stats_summary(franchise_id=10,start_season="20232024",end_season="20232024")Schedule Endpointsclient.schedule.get_schedule(date="2021-01-13")client.schedule.get_schedule()client.schedule.get_schedule_by_team_by_month(team_abbr="BUF")client.schedule.get_schedule_by_team_by_month(team_abbr="BUF",month="2021-01")client.schedule.get_schedule_by_team_by_week(team_abbr="BUF")client.schedule.get_schedule_by_team_by_week(team_abbr="BUF",date="2024-01-01")client.schedule.get_season_schedule(team_abbr="BUF",season="20212022")client.schedule.schedule_calendar(date="2023-11-23")Standings Endpointsclient.standings.get_standings()client.standings.get_standings(date="2021-01-13")client.standings.get_standings(season="202222023")# standings manifest.  This returns a ton of information for every season ever it seems like# This calls the API for this info, I also cache this in /data/seasonal_information_manifest.json# for less API calls since this only changes yearly.client.standings.season_standing_manifest()Teams Endpointsclient.teams.teams_info()# returns id + abbrevation + name of all teamsclient.teams.team_stats_summary(lang="en")# I honestly dont know. This is missing teams and has teams long abandoned.Game Centerclient.game_center.boxscore(game_id="2023020280")client.game_center.play_by_play(game_id="2023020280")client.game_center.landing(game_id="2023020280")client.game_center.score_now()Misc Endpointsclient.misc.glossary()client.misc.config()client.misc.countries()client.misc.season_specific_rules_and_info()client.misc.draft_year_and_rounds()Insomnia Rest Client ExportInsomnia Rest Clientis a great tool for testingnhl_api-{ver}.json in the root folder is an export of the endpoints I have
been working through using the Insomnia Rest Client.  You can import this directly
into the client and use it to test the endpoints.  I will be updating this as I goDevelopersInstallPoetrycurl -sSL https://install.python-poetry.org | python3 -or using pipxpipx install poetrypoetry install --with devpoetry shellBuild PipelineThe build pipeline will runblack,ruff, andpytest.  Please make sure these are passing before submitting a PR.$poetryshell# You can then run the following$pytest$ruff.$black.