From 4f6b408bd8592929050ff3129400e1034b4af4b8 Mon Sep 17 00:00:00 2001 From: Corey Schaf Date: Mon, 11 May 2026 18:31:11 -0400 Subject: [PATCH] docs: #110 adds llm friendly documentation and indexable response and request examples. code: updates some doc strings to better reflect the response object --- context7.json | 16 ++ docs/edge.md | 479 +++++++++++++++++++++++++++++++++++++++ docs/game_center.md | 384 +++++++++++++++++++++++++++++++ docs/helpers.md | 125 ++++++++++ docs/misc.md | 154 +++++++++++++ docs/players.md | 96 ++++++++ docs/schedule.md | 403 ++++++++++++++++++++++++++++++++ docs/standings.md | 110 +++++++++ docs/stats.md | 425 ++++++++++++++++++++++++++++++++++ docs/teams.md | 97 ++++++++ llms.txt | 109 +++++++++ nhlpy/api/edge.py | 195 ++++++++++++++++ nhlpy/api/game_center.py | 170 +++++++++++--- nhlpy/api/helpers.py | 75 +++++- nhlpy/api/misc.py | 76 ++++++- nhlpy/api/players.py | 53 ++++- nhlpy/api/schedule.py | 212 ++++++++++++++--- nhlpy/api/standings.py | 83 ++++--- nhlpy/api/stats.py | 100 ++++++++ nhlpy/api/teams.py | 90 ++++++-- pyproject.toml | 2 +- 21 files changed, 3310 insertions(+), 144 deletions(-) create mode 100644 context7.json create mode 100644 docs/edge.md create mode 100644 docs/game_center.md create mode 100644 docs/helpers.md create mode 100644 docs/misc.md create mode 100644 docs/players.md create mode 100644 docs/schedule.md create mode 100644 docs/standings.md create mode 100644 docs/stats.md create mode 100644 docs/teams.md create mode 100644 llms.txt diff --git a/context7.json b/context7.json new file mode 100644 index 0000000..b601bdb --- /dev/null +++ b/context7.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://context7.com/schema/context7.json", + "projectTitle": "nhl-api-py", + "description": "Python wrapper for the NHL API — stats, schedules, standings, teams, game data, and EDGE analytics", + "folders": ["docs"], + "excludeFolders": ["tests", ".github"], + "excludeFiles": ["CONTRIBUTING.md"], + "rules": [ + "Always import from nhlpy: from nhlpy import NHLClient", + "Game IDs format: YYYYTTNNNN (e.g., 2023020280 = 2023 season, regular season game 280)", + "Season format: YYYYYYYY (e.g., 20242025)", + "Method names have no get_ prefix (e.g., boxscore() not get_boxscore())", + "Team abbreviations are 3 letters (e.g., BUF, TOR, EDM)", + "Many name fields use localized format: {\"default\": \"English\", \"fr\": \"French\"}" + ] +} diff --git a/docs/edge.md b/docs/edge.md new file mode 100644 index 0000000..ae72261 --- /dev/null +++ b/docs/edge.md @@ -0,0 +1,479 @@ +# Edge API Module (NHL EDGE Tracking) + +The edge module provides access to NHL EDGE puck and player tracking data, including shot speed, skating speed, distance skated, zone time, and shot location analytics for skaters, goalies, and teams. Access it via `client.edge` on an `NHLClient` instance. EDGE data is only available from the 2021-2022 season onward. + +## Common Parameters for All EDGE Methods + +All EDGE methods share a consistent set of parameters. Player methods accept `player_id`, team methods accept `team_id`, and landing page methods accept neither. + +- `player_id` (str): NHL player ID (e.g., "8478402" for Connor McDavid) +- `team_id` (str): NHL team ID (e.g., "10" for Toronto Maple Leafs) +- `season` (str, optional): Season in YYYYYYYY format (e.g., "20242025"). When omitted, defaults to the current season using the `/now` endpoint variant. +- `game_type` (int, optional): Type of games to include. Defaults to `2`. + - `1`: Preseason + - `2`: Regular season + - `3`: Playoffs + +All responses include a `seasonsWithEdgeStats` field listing the seasons that have EDGE data available for the given player or team. + +## Get Comprehensive Skater EDGE Profile with skater_detail + +Returns the full EDGE tracking profile for a skater, including shot speed, skating speed, distance traveled, shot locations, and zone time data. Every stat includes a league-average comparison and percentile ranking. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current season (uses /now endpoint) +detail = client.edge.skater_detail(player_id="8478402") + +# Specific season and game type +detail = client.edge.skater_detail( + player_id="8478402", + season="20242025", + game_type=2 +) + +print(f"Top shot speed: {detail['topShotSpeed']['imperial']} mph") +print(f"Max skating speed: {detail['skatingSpeed']['speedMax']['imperial']} mph") +``` + +**Response structure:** + +- `player` (object): Player identification and basic stats + - `id` (int): Player ID + - `firstName` (object): `default` (str) first name + - `lastName` (object): `default` (str) last name + - `sweaterNumber` (int): Jersey number + - `position` (str): Position played + - `headshot` (str): URL to headshot image + - `goals` (int): Goals scored + - `assists` (int): Assists recorded + - `points` (int): Total points + - `gamesPlayed` (int): Games played + - `team` (object): `abbrev` (str) team abbreviation +- `topShotSpeed` (object): Hardest shot recorded + - `imperial` (float): Speed in mph + - `metric` (float): Speed in km/h + - `percentile` (float): League percentile (0-1) + - `leagueAvg` (object): `imperial` (float) league average in mph + - `overlay` (object): Game context for the top shot +- `skatingSpeed` (object): Skating speed metrics + - `speedMax` (object): `imperial` (float), `metric` (float), `percentile` (float) + - `burstsOver20` (object): `value` (int) number of 20+ mph bursts, `percentile` (float) +- `totalDistanceSkated` (object): Total distance metrics + - `imperial` (float): Distance in miles + - `metric` (float): Distance in kilometers + - `percentile` (float): League percentile +- `sogSummary` (list): Shots on goal by location zone + - `locationCode` (str): Zone identifier ("all", "high", "mid", "low") + - `shots` (int): Shot count + - `shotsPercentile` (float): Percentile for shot count + - `goals` (int): Goals scored from this zone + - `goalsPercentile` (float): Percentile for goal count + - `shootingPctg` (float): Shooting percentage +- `sogDetails` (list): Shots on goal by specific area + - `area` (str): Specific area name (e.g., "Slot", "Behind the Net", "Inner Slot", "Point") + - `shots` (int): Shot count from this area + - `shotsPercentile` (float): Percentile for shot count +- `zoneTimeDetails` (object): Time spent in each zone + - `offensiveZonePctg` (float): Percentage of time in offensive zone + - `offensiveZonePercentile` (float): League percentile + - `neutralZonePctg` (float): Percentage of time in neutral zone + - `defensiveZonePctg` (float): Percentage of time in defensive zone + - Even-strength variants: `offensiveZoneEvPctg`, `offensiveZoneEvPercentile`, etc. + - `leagueAvg` (object): League averages for each zone metric + +## Get Skater Shot Speed Breakdown with skater_shot_speed_detail + +Returns detailed shot speed data for a specific skater, including speed distributions and game-by-game breakdowns. + +```python +from nhlpy import NHLClient + +client = NHLClient() +shot_speed = client.edge.skater_shot_speed_detail(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Skater Skating Speed Stats with skater_skating_speed_detail + +Returns skating speed statistics for a specific skater, including top speed, burst counts, and speed distributions. + +```python +from nhlpy import NHLClient + +client = NHLClient() +skating_speed = client.edge.skater_skating_speed_detail(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Skater Shot Locations with skater_shot_location_detail + +Returns shot location data for a specific skater, including shooting patterns from different ice areas. + +```python +from nhlpy import NHLClient + +client = NHLClient() +shot_locations = client.edge.skater_shot_location_detail(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Skater Distance Traveled with skater_skating_distance_detail + +Returns distance skated statistics for a specific skater, including per-game and per-shift breakdowns. + +```python +from nhlpy import NHLClient + +client = NHLClient() +distance = client.edge.skater_skating_distance_detail(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Compare Skater Against League with skater_comparison + +Returns comparison statistics for a skater against league averages across all EDGE metrics. + +```python +from nhlpy import NHLClient + +client = NHLClient() +comparison = client.edge.skater_comparison(player_id="8478402", season="20242025") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Skater Zone Time Breakdown with skater_zone_time + +Returns time spent in offensive, defensive, and neutral zones for a specific skater. + +```python +from nhlpy import NHLClient + +client = NHLClient() +zone_time = client.edge.skater_zone_time(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get League-Wide Skater EDGE Leaders with skater_landing + +Returns the league leaders across all skater EDGE categories. This is a league-wide overview, not specific to any single player. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current season leaders +leaders = client.edge.skater_landing() + +# Specific season leaders +leaders = client.edge.skater_landing(season="20242025", game_type=2) +``` + +**Parameters:** `season` (str, optional), `game_type` (int, default 2) + +**Response structure:** + +- `leaders` (object): League leaders by category + - `hardestShot` (list): Players with the hardest shots, each with player info and stat values + - `maxSkatingSpeed` (list): Players with highest skating speeds + - `totalDistanceSkated` (list): Players with most distance skated + - `highDangerSOG` (list): Players with most high-danger shots on goal + - `offensiveZoneTime` (list): Players with most offensive zone time + - `defensiveZoneTime` (list): Players with most defensive zone time + - Each leader entry includes player identification fields and the relevant stat value + +## Get Compact Skater EDGE Profile with cat_skater_detail + +Returns a compact version of the skater EDGE detail using the CAT (Catch All Tracking) endpoint. Contains the same categories as `skater_detail` in a more condensed format. + +```python +from nhlpy import NHLClient + +client = NHLClient() +cat_detail = client.edge.cat_skater_detail(player_id="8478402") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Comprehensive Goalie EDGE Profile with goalie_detail + +Returns the full EDGE tracking profile for a goalie, including save percentages by location, goals against metrics, and performance comparisons. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current season +detail = client.edge.goalie_detail(player_id="8476945") + +# Specific season +detail = client.edge.goalie_detail( + player_id="8476945", + season="20242025", + game_type=2 +) + +print(f"Save percentage: {detail['player']['savePctg']}") +``` + +**Response structure:** + +- `player` (object): Goalie identification and basic stats + - `id` (int): Player ID + - `firstName` (object): `default` (str) first name + - `lastName` (object): `default` (str) last name + - `wins` (int): Wins + - `losses` (int): Losses + - `overtimeLosses` (int): Overtime losses + - `goalsAgainstAvg` (float): Goals against average + - `savePctg` (float): Save percentage + - `gamesPlayed` (int): Games played + - `team` (object): `abbrev` (str) team abbreviation +- `stats` (object): Advanced goalie metrics + - `goalsAgainstAvg` (object): `value` (float), `percentile` (float), `leagueAvg` (float) + - `gamesAbove900` (object): Count of games with save percentage above .900 + - `goalDifferentialPer60` (object): Goal differential per 60 minutes + - `goalSupportAvg` (object): Average goal support from the team + - `pointPctg` (object): Point percentage +- `shotLocationSummary` (list): Save stats by shot location zone + - `locationCode` (str): Zone identifier + - `goalsAgainst` (int): Goals allowed from this zone + - `saves` (int): Saves made from this zone + - `savePctg` (float): Save percentage for this zone + - Each field has `percentile` (float) and `leagueAvg` (float) variants +- `shotLocationDetails` (list): Save stats by specific area + - `area` (str): Specific area name + - `saves` (int): Save count + - `savesPercentile` (float): Percentile for saves + - `savePctg` (float): Save percentage + - `savePctgPercentile` (float): Percentile for save percentage + +## Get Goalie Shot Location Saves with goalie_shot_location_detail + +Returns detailed shot location data faced by a specific goalie, including save percentages by zone. + +```python +from nhlpy import NHLClient + +client = NHLClient() +shot_locations = client.edge.goalie_shot_location_detail(player_id="8476945") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Goalie 5v5 Performance with goalie_5v5_detail + +Returns five-on-five performance statistics and save percentages for a specific goalie. + +```python +from nhlpy import NHLClient + +client = NHLClient() +fivevfive = client.edge.goalie_5v5_detail(player_id="8476945") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Compare Goalie Against League with goalie_comparison + +Returns comparison statistics for a goalie relative to league averages across all EDGE metrics. + +```python +from nhlpy import NHLClient + +client = NHLClient() +comparison = client.edge.goalie_comparison(player_id="8476945") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Goalie Save Percentage Breakdown with goalie_save_percentage_detail + +Returns detailed save percentage breakdowns by situation, shot type, and location for a specific goalie. + +```python +from nhlpy import NHLClient + +client = NHLClient() +sv_pct = client.edge.goalie_save_percentage_detail(player_id="8476945") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get League-Wide Goalie EDGE Leaders with goalie_landing + +Returns the league leaders across all goalie EDGE categories. This is a league-wide overview, not specific to any single goalie. + +```python +from nhlpy import NHLClient + +client = NHLClient() +leaders = client.edge.goalie_landing() +leaders = client.edge.goalie_landing(season="20242025", game_type=2) +``` + +**Parameters:** `season` (str, optional), `game_type` (int, default 2) + +## Get Compact Goalie EDGE Profile with cat_goalie_detail + +Returns a compact version of the goalie EDGE detail using the CAT (Catch All Tracking) endpoint. + +```python +from nhlpy import NHLClient + +client = NHLClient() +cat_detail = client.edge.cat_goalie_detail(player_id="8476945") +``` + +**Parameters:** `player_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Comprehensive Team EDGE Profile with team_detail + +Returns the full EDGE tracking profile for a team, including shot speed, skating speed, distance skated, shot locations, and zone time. Team responses use league rank instead of percentile for comparisons. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current season +detail = client.edge.team_detail(team_id="10") + +# Specific season +detail = client.edge.team_detail( + team_id="10", + season="20242025", + game_type=2 +) + +print(f"Top shot speed: {detail['shotSpeed']['topShotSpeed']['imperial']} mph") +print(f"Shot speed rank: {detail['shotSpeed']['topShotSpeed']['rank']}") +``` + +**Response structure:** + +- `team` (object): Team identification and record + - `id` (int): Team ID + - `commonName` (object): `default` (str) team name + - `abbrev` (str): Team abbreviation + - `teamLogo` (object): `light` (str) and `dark` (str) logo URLs + - `conference` (str): Conference name + - `division` (str): Division name + - `wins` (int): Wins + - `losses` (int): Losses + - `otLosses` (int): Overtime losses + - `gamesPlayed` (int): Games played + - `points` (int): Points in standings +- `shotSpeed` (object): Team shot speed metrics + - `shotAttemptsOver90` (object): `value` (int) shots over 90 mph, `rank` (int) league rank + - `topShotSpeed` (object): `imperial` (float) mph, `metric` (float) km/h, `rank` (int) league rank +- `skatingSpeed` (object): Team skating speed metrics + - `burstsOver22` (object): `value` (int) bursts over 22 mph, `rank` (int) + - `burstsOver20` (object): `value` (int), `rank` (int) + - `speedMax` (object): `imperial` (float), `metric` (float), `rank` (int) +- `distanceSkated` (object): Team distance metrics + - `total` (object): `imperial` (float) miles, `metric` (float) km, `rank` (int) league rank +- `sogSummary` (list): Shots on goal by location zone + - `locationCode` (str): Zone identifier + - `shots` (int): Shot count + - `shotsRank` (int): League rank for shots + - `shootingPctg` (float): Shooting percentage + - `shootingPctgRank` (int): League rank for shooting percentage + - `goals` (int): Goals scored + - `goalsRank` (int): League rank for goals +- `zoneTimeDetails` (object): Zone time with league rankings + - `offensiveZonePctg` (float): Percentage of time in offensive zone + - `offensiveZoneRank` (int): League rank for offensive zone time + - `neutralZonePctg` (float): Neutral zone time percentage + - `defensiveZonePctg` (float): Defensive zone time percentage + - `defensiveZoneRank` (int): League rank for defensive zone time + +## Get Team Skating Distance Stats with team_skating_distance_detail + +Returns skating distance statistics for a specific team, including per-game and per-player breakdowns. + +```python +from nhlpy import NHLClient + +client = NHLClient() +distance = client.edge.team_skating_distance_detail(team_id="10") +``` + +**Parameters:** `team_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Team Zone Time Breakdown with team_zone_time_details + +Returns time spent in offensive, defensive, and neutral zones for a specific team. + +```python +from nhlpy import NHLClient + +client = NHLClient() +zone_time = client.edge.team_zone_time_details(team_id="10") +``` + +**Parameters:** `team_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Team Shot Location Stats with team_shot_location_detail + +Returns shot location data for a specific team, including shooting patterns from different ice areas. + +```python +from nhlpy import NHLClient + +client = NHLClient() +shot_locations = client.edge.team_shot_location_detail(team_id="10") +``` + +**Parameters:** `team_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get League-Wide Team EDGE Leaders with team_landing + +Returns the league leaders and rankings across all team EDGE categories. + +```python +from nhlpy import NHLClient + +client = NHLClient() +leaders = client.edge.team_landing() +leaders = client.edge.team_landing(season="20242025", game_type=2) +``` + +**Parameters:** `season` (str, optional), `game_type` (int, default 2) + +## Get Team Shot Speed Stats with team_shot_speed_detail + +Returns shot speed statistics for a specific team, including maximum and average speeds. + +```python +from nhlpy import NHLClient + +client = NHLClient() +shot_speed = client.edge.team_shot_speed_detail(team_id="10") +``` + +**Parameters:** `team_id` (str), `season` (str, optional), `game_type` (int, default 2) + +## Get Team Skating Speed Stats with team_skating_speed_detail + +Returns skating speed statistics for a specific team, including burst speed counts and averages. + +```python +from nhlpy import NHLClient + +client = NHLClient() +skating_speed = client.edge.team_skating_speed_detail(team_id="10") +``` + +**Parameters:** `team_id` (str), `season` (str, optional), `game_type` (int, default 2) diff --git a/docs/game_center.md b/docs/game_center.md new file mode 100644 index 0000000..606b399 --- /dev/null +++ b/docs/game_center.md @@ -0,0 +1,384 @@ +# GameCenter API Reference + +The `game_center` module provides access to live and completed NHL game data including boxscores, play-by-play events, shift charts, scoring summaries, and daily scores. All methods are accessed via `client.game_center` on an `NHLClient` instance. + +Game IDs follow the format `YYYYTTNNNN` where `YYYY` is the season start year, `TT` is the game type (01=preseason, 02=regular, 03=playoffs), and `NNNN` is the game number (e.g., `2023020280`). Game IDs can be retrieved from any schedule endpoint. + +## GameCenter: Get Game Boxscore + +Retrieve the full boxscore for a specific NHL game, including team totals and individual player statistics broken down by position group. + +```python +from nhlpy import NHLClient + +client = NHLClient() +boxscore = client.game_center.boxscore(game_id="2023020280") + +# Access team scores +home_score = boxscore["homeTeam"]["score"] +away_score = boxscore["awayTeam"]["score"] + +# Access forward stats for the home team +home_forwards = boxscore["playerByGameStats"]["homeTeam"]["forwards"] +for player in home_forwards: + print(player["name"]["default"], player["goals"], player["assists"]) +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) + +**Response top-level fields:** +- `id` (int): Numeric game identifier +- `season` (int): Season identifier (e.g., 20232024) +- `gameType` (int): Game type (1=preseason, 2=regular, 3=playoffs) +- `gameDate` (str): Date in YYYY-MM-DD format +- `venue` (object) + - `default` (str): Arena name +- `startTimeUTC` (str): ISO 8601 game start time +- `gameState` (str): One of `"FUT"`, `"LIVE"`, `"OFF"`, `"FINAL"` +- `gameScheduleState` (str): Schedule status +- `tvBroadcasts` (list): TV broadcast information + +**`awayTeam` / `homeTeam` fields:** +- `id` (int): Team ID +- `commonName` (object) + - `default` (str): Team common name (e.g., "Sabres") +- `abbrev` (str): Three-letter abbreviation (e.g., "BUF") +- `score` (int): Goals scored +- `sog` (int): Shots on goal +- `logo` (str): URL to team logo +- `darkLogo` (str): URL to dark-mode team logo +- `placeName` (object) + - `default` (str): City/place name (e.g., "Buffalo") + +**`clock` fields:** +- `timeRemaining` (str): Time left in period (e.g., "12:34") +- `secondsRemaining` (int): Seconds left in period +- `running` (bool): Whether the clock is actively running +- `inIntermission` (bool): Whether the game is in intermission + +**`playerByGameStats` structure:** +- `awayTeam` (object) + - `forwards` (list): Forward player stat lines + - `defense` (list): Defenseman stat lines + - `goalies` (list): Goalie stat lines +- `homeTeam` (object): Same structure as `awayTeam` + +**`gameOutcome` fields:** +- `lastPeriodType` (str): One of `"REG"`, `"OT"`, `"SO"` + +## GameCenter: Get Play-by-Play Events + +Retrieve detailed play-by-play event data for an NHL game, including every event (shots, goals, faceoffs, penalties, stoppages) with timestamps, players involved, and situational context. + +```python +from nhlpy import NHLClient + +client = NHLClient() +pbp = client.game_center.play_by_play(game_id="2023020280") + +# Iterate over all plays +for play in pbp["plays"]: + print(play["typeDescKey"], play["timeInPeriod"], play.get("periodDescriptor", {}).get("number")) + +# Filter for goals only +goals = [p for p in pbp["plays"] if p["typeDescKey"] == "goal"] +for goal in goals: + print(f"Goal at {goal['timeInPeriod']} in period {goal['periodDescriptor']['number']}") +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) + +**Response fields (in addition to boxscore-level game metadata):** +- `plays` (list): All play events, typically ~340 items per game +- `rosterSpots` (list): All players on both rosters +- `summary` (object): Game summary data +- `shootoutInUse` (bool): Whether shootout rules apply +- `otInUse` (bool): Whether overtime rules apply + +**`plays[]` item fields:** +- `eventId` (int): Unique event identifier +- `periodDescriptor` (object) + - `number` (int): Period number (1, 2, 3, 4 for OT) + - `periodType` (str): Period type (e.g., "REG", "OT") +- `timeInPeriod` (str): Time elapsed in period (e.g., "05:32") +- `timeRemaining` (str): Time remaining in period +- `situationCode` (str): Encoded situation (strength, empty net status) +- `typeCode` (int): Numeric event type code +- `typeDescKey` (str): Human-readable event type, one of: + - `"shot-on-goal"`, `"goal"`, `"period-start"`, `"period-end"`, `"faceoff"`, `"hit"`, `"blocked-shot"`, `"missed-shot"`, `"giveaway"`, `"takeaway"`, `"penalty"`, `"stoppage"`, `"game-end"` +- `sortOrder` (int): Event ordering within the game +- `homeTeamDefendingSide` (str): Which side home team defends (e.g., "left", "right") + +**`rosterSpots[]` item fields:** +- `teamId` (int): Team ID +- `playerId` (int): Player ID +- `firstName` (object) + - `default` (str): First name +- `lastName` (object) + - `default` (str): Last name +- `sweaterNumber` (int): Jersey number +- `positionCode` (str): Position code (C, L, R, D, G) +- `headshot` (str): URL to player headshot image + +## GameCenter: Get Game Matchup and Scoring Summary + +Retrieve detailed matchup information for a game, including the scoring summary broken down by period, three stars selections, and penalty summary. + +```python +from nhlpy import NHLClient + +client = NHLClient() +matchup = client.game_center.match_up(game_id="2023020280") + +# Get three stars +for star in matchup["summary"]["threeStars"]: + print(f"Star #{star['star']}: {star['name']['default']} ({star['teamAbbrev']})") + +# Get scoring summary by period +for period in matchup["summary"]["scoring"]: + for goal in period.get("goals", []): + print(goal) +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) + +**Response fields (in addition to game metadata):** +- `summary` (object): Contains scoring, three stars, and penalties + +**`summary.scoring` structure:** +- List of period objects, each containing: + - `goals` (list): Goals scored in that period + +**`summary.threeStars[]` item fields:** +- `star` (int): Star ranking (1, 2, or 3) +- `playerId` (int): Player ID +- `teamAbbrev` (str): Three-letter team abbreviation +- `headshot` (str): URL to player headshot +- `name` (object) + - `default` (str): Player full name +- `sweaterNo` (int): Jersey number +- `position` (str): Position code +- `goalsAgainstAverage` (float, goalies only): GAA if the player is a goalie +- `savePctg` (float, goalies only): Save percentage if the player is a goalie + +**`summary.penalties` structure:** +- List of period objects, each containing penalty events for that period + +## GameCenter: Get Daily Scores + +Retrieve scores for all NHL games on a specific date, including goal scorers, game state, and links to recaps. Pass a date string or omit it to get today's scores. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get today's scores +today_scores = client.game_center.daily_scores() + +# Get scores for a specific date +scores = client.game_center.daily_scores(date="2024-01-15") + +for game in scores["games"]: + away = game["awayTeam"] + home = game["homeTeam"] + print(f"{away['abbrev']} {away['score']} - {home['abbrev']} {home['score']} ({game['gameState']})") +``` + +**Parameters:** +- `date` (str, optional): Date in `"YYYY-MM-DD"` format. Omit or pass `None` for current day. + +**Response top-level fields:** +- `prevDate` (str): Previous date with games +- `currentDate` (str): Requested date +- `nextDate` (str): Next date with games +- `gameWeek` (list): 7-day schedule window +- `oddsPartners` (list): Odds partner information +- `games` (list): All games for the date + +**`games[]` item fields:** +- `id` (int): Game ID +- `season` (int): Season identifier +- `gameType` (int): Game type (1=preseason, 2=regular, 3=playoffs) +- `gameDate` (str): Date in YYYY-MM-DD format +- `venue` (object) + - `default` (str): Arena name +- `startTimeUTC` (str): ISO 8601 start time +- `gameState` (str): One of `"FUT"`, `"LIVE"`, `"OFF"`, `"FINAL"` +- `awayTeam` (object) + - `id` (int): Team ID + - `name` (object) with `default` (str): Team name + - `abbrev` (str): Three-letter abbreviation + - `score` (int): Goals scored + - `sog` (int): Shots on goal + - `logo` (str): URL to team logo +- `homeTeam` (object): Same structure as `awayTeam` +- `gameCenterLink` (str): Relative link to game center page +- `threeMinRecap` (str): URL to three-minute recap video +- `condensedGame` (str): URL to condensed game video +- `clock` (object): Clock state (see boxscore clock fields) +- `periodDescriptor` (object): Current period info +- `gameOutcome` (object): Outcome info if game is final + +**`goals[]` item fields (nested within each game):** +- `period` (int): Period number +- `timeInPeriod` (str): Time of goal in period +- `playerId` (int): Scoring player's ID +- `name` (object) + - `default` (str): Scorer's name +- `goalModifier` (str): Modifier (e.g., empty net, penalty shot) +- `assists` (list): List of assisting players +- `teamAbbrev` (str): Scoring team abbreviation +- `goalsToDate` (int): Scorer's season goal total +- `awayScore` (int): Away team score after this goal +- `homeScore` (int): Home team score after this goal +- `strength` (str): One of `"ev"` (even strength), `"pp"` (power play), `"sh"` (shorthanded) + +## GameCenter: Get Shift Chart Data + +Retrieve shift-by-shift data for every player in a game, useful for building shift charts or analyzing time-on-ice patterns. By default, `eventDetails` are excluded from the response. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get shift data with default exclusions +shifts = client.game_center.shift_chart_data(game_id="2023020280") + +print(f"Total shifts: {shifts['total']}") +for shift in shifts["data"][:5]: + print(f"{shift['firstName']} {shift['lastName']} - Period {shift['period']}, " + f"{shift['startTime']}-{shift['endTime']} ({shift['duration']})") + +# Get shift data without any exclusions +shifts_full = client.game_center.shift_chart_data(game_id="2023020280", excludes=[]) +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) +- `excludes` (List[str], optional): Fields to exclude from the response. Defaults to `["eventDetails"]`. Pass an empty list to include all fields. + +**Response top-level fields:** +- `data` (list): All shift records, typically ~740 items per game +- `total` (int): Total number of shift records + +**`data[]` item fields:** +- `id` (int): Shift record ID +- `duration` (str): Shift duration in `"MM:SS"` format +- `endTime` (str): Shift end time in period +- `startTime` (str): Shift start time in period +- `firstName` (str): Player first name +- `lastName` (str): Player last name +- `gameId` (int): Game ID +- `period` (int): Period number +- `playerId` (int): Player ID +- `shiftNumber` (int): Sequential shift number for this player +- `teamAbbrev` (str): Three-letter team abbreviation +- `teamId` (int): Team ID +- `teamName` (str): Full team name +- `typeCode` (int): Shift type code +- `hexValue` (str): Team color hex code (e.g., "#003087") + +## GameCenter: Get Season Series and Game Stats + +Retrieve the season series between two teams, linescore, per-period shot totals, team comparison stats, and game report URLs for a specific game. This corresponds to the "right rail" data on the NHL website. + +```python +from nhlpy import NHLClient + +client = NHLClient() +rail = client.game_center.season_series_matchup(game_id="2023020280") + +# Season series wins +wins = rail["seasonSeriesWins"] +print(f"Away wins: {wins['awayTeamWins']}, Home wins: {wins['homeTeamWins']}") + +# Team comparison stats +for stat in rail["teamGameStats"]: + print(f"{stat['category']}: Away={stat['awayValue']} Home={stat['homeValue']}") + +# Access game report URLs +reports = rail["gameReports"] +print(f"Game summary PDF: {reports['gameSummary']}") +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) + +**Response top-level fields:** +- `seasonSeries` (list): Previous matchup games between the two teams this season +- `seasonSeriesWins` (object) + - `awayTeamWins` (int): Away team's wins in the season series + - `homeTeamWins` (int): Home team's wins in the season series +- `gameInfo` (object) + - `referees` (list): Referee names + - `linesmen` (list): Linesman names + - `scratches` (object): Healthy scratches for both teams + - `headCoach` (object): Head coaches for both teams +- `gameVideo` (object): Video links +- `linescore` (object) + - `byPeriod` (list): Score by period + - `totals` (object): Final score totals +- `shotsByPeriod` (list): Shot counts per period for each team + +**`teamGameStats[]` item fields:** +- `category` (str): Stat category, one of: + - `"sog"` (shots on goal) + - `"faceoffWinningPctg"` (faceoff win percentage) + - `"powerPlay"` (power play results, e.g., "1/3") + - `"pim"` (penalty minutes) + - `"hits"`, `"blockedShots"`, `"giveaways"`, `"takeaways"` +- `awayValue` (int or str): Away team's value for this stat +- `homeValue` (int or str): Home team's value for this stat + +**`gameReports` fields:** +- `gameSummary` (str): URL to game summary PDF +- `eventSummary` (str): URL to event summary PDF +- `playByPlay` (str): URL to play-by-play PDF +- `faceoffSummary` (str): URL to faceoff summary PDF +- `faceoffComparison` (str): URL to faceoff comparison PDF +- `rosters` (str): URL to game rosters PDF +- `shotSummary` (str): URL to shot summary PDF +- `shiftChart` (str): URL to shift chart PDF +- `toiAway` (str): URL to away team time-on-ice PDF +- `toiHome` (str): URL to home team time-on-ice PDF + +## GameCenter: Get Game Story and Recap + +Retrieve the game story/recap including a scoring summary, three stars, team comparison stats, and shootout data if applicable. Similar to the matchup endpoint but includes team game stats and shootout information. + +```python +from nhlpy import NHLClient + +client = NHLClient() +story = client.game_center.game_story(game_id="2023020280") + +# Team comparison stats +for stat in story["summary"]["teamGameStats"]: + print(f"{stat['category']}: {stat['awayValue']} vs {stat['homeValue']}") + +# Three stars (note: uses simple name string, not object) +for star in story["summary"]["threeStars"]: + print(f"Star #{star['star']}: {star['name']}") +``` + +**Parameters:** +- `game_id` (str, required): The NHL game ID (e.g., `"2023020280"`) + +**Response fields (in addition to game metadata):** +- `summary` (object): Contains all recap data + +**`summary` sub-fields:** +- `scoring` (list): Scoring summary by period +- `threeStars` (list): Three stars of the game + - Note: Uses a simple `name` string (not an object like `match_up`) +- `penalties` (list): Penalty summary by period +- `teamGameStats` (list): Team comparison stats + - `category` (str): Stat name (e.g., `"sog"`, `"faceoffWinningPctg"`, `"powerPlay"`) + - `awayValue` (int or str): Away team's value + - `homeValue` (int or str): Home team's value +- `shootout` (list): Shootout attempts if the game went to a shootout diff --git a/docs/helpers.md b/docs/helpers.md new file mode 100644 index 0000000..d58c4d7 --- /dev/null +++ b/docs/helpers.md @@ -0,0 +1,125 @@ +# Helpers API Module + +The helpers module provides convenience methods that aggregate data from multiple NHL API calls into single results. Access it via `client.helpers` on an `NHLClient` instance. + +**Performance warning:** Every method in this module makes multiple API calls internally (typically 32, one per NHL team) with built-in sleep delays between requests to avoid rate limiting. These methods are significantly slower than individual API calls. Expect execution times of 30 seconds to several minutes depending on the method and sleep rate. + +## Get All Game IDs for a Season with game_ids_by_season + +Retrieves all unique game IDs for an entire NHL season by iterating through each team's schedule. Makes 32 API calls (one per team) with a configurable sleep delay between each call. Returns approximately 2600 unique game IDs for a standard regular season. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get all regular season game IDs (default) +game_ids = client.helpers.game_ids_by_season(season="20242025") +print(f"Total games: {len(game_ids)}") + +# Get playoff game IDs only +playoff_ids = client.helpers.game_ids_by_season( + season="20242025", + game_types=[3] +) + +# Get both regular season and playoff game IDs +all_ids = client.helpers.game_ids_by_season( + season="20242025", + game_types=[2, 3], + api_sleep_rate=1.5 +) +``` + +**Parameters:** + +- `season` (str, required): Season in YYYYYYYY format (e.g., "20242025") +- `game_types` (List[int], optional): List of game types to include. Defaults to `[2]` (regular season only). + - `1`: Preseason + - `2`: Regular season + - `3`: Playoffs +- `api_sleep_rate` (float, optional): Seconds to sleep between API calls. Defaults to `1`. Increase if you encounter rate limiting. + +**Returns:** `List[int]` of unique game IDs. Each game ID is an integer (e.g., 2024020001). + +**Performance note:** With the default 1-second sleep rate, this method takes at least 32 seconds to complete. The method deduplicates game IDs since games appear in both teams' schedules. + +## Get All Players Across All Teams with all_players + +Retrieves every player from every team's roster for a given season. Makes 32 API calls (one per team) and returns a single flattened list of all player dictionaries with an added `team` field. + +```python +from nhlpy import NHLClient + +client = NHLClient() +players = client.helpers.all_players(season="20242025") + +print(f"Total players: {len(players)}") +for player in players: + print(f"{player['firstName']} {player['lastName']} - {player['team']}") +``` + +**Parameters:** + +- `season` (str, required): Season in YYYYYYYY format (e.g., "20242025") +- `api_sleep_rate` (float, optional): Seconds to sleep between API calls. Defaults to `0.5`. Increase if you encounter rate limiting. + +**Returns:** `List[dict]` of player objects from all 32 teams combined. + +**Player fields:** + +- `id` (int): Unique NHL player identifier +- `headshot` (str): URL to the player's headshot image +- `firstName` (str): Player's first name (cleaned from the nested `firstName.default` format) +- `lastName` (str): Player's last name (cleaned from the nested `lastName.default` format) +- `sweaterNumber` (int): Jersey number +- `positionCode` (str): Position code (e.g., "C", "L", "R", "D", "G") +- `shootsCatches` (str): Handedness ("L" or "R") +- `heightInInches` (int): Height in inches +- `weightInPounds` (int): Weight in pounds +- `birthDate` (str): Date of birth in "YYYY-MM-DD" format +- `birthCity` (object): + - `default` (str): City of birth +- `birthCountry` (str): Three-letter country code (e.g., "CAN", "USA") +- `team` (str): Three-letter team abbreviation (added by the helper method) + +**Performance note:** With the default 0.5-second sleep rate, this method takes at least 16 seconds to complete. A progress message is printed to stdout when the method starts. + +## Get Summary Statistics for All Players with all_players_summary_statistics + +Retrieves summary statistics for every skater in a given season by first fetching all players, then querying stats for each team using the query builder. Makes multiple rounds of API calls (32 for rosters plus 32 for stats) and merges the results. + +```python +from nhlpy import NHLClient + +client = NHLClient() +stats = client.helpers.all_players_summary_statistics(season="20242025") + +for player in stats: + name = player.get("skaterFullName", f"{player.get('firstName', '')} {player.get('lastName', '')}") + points = player.get("points", 0) + print(f"{name}: {points} pts") +``` + +**Parameters:** + +- `season` (str, required): Season in YYYYYYYY format (e.g., "20242025") +- `api_sleep_rate` (float, optional): Seconds to sleep between API calls. Defaults to `1`. Increase if you encounter rate limiting. + +**Returns:** `list` of merged player/stats dictionaries. Each entry combines roster data (from `all_players`) with summary statistics (from the stats query builder). Players without matching stats are included from the stats data alone. + +**Merged fields include all fields from `all_players` above, plus stats fields such as:** + +- `playerId` (int): Player ID from the stats response +- `skaterFullName` (str): Full name from the stats response +- `gamesPlayed` (int): Number of games played +- `goals` (int): Goals scored +- `assists` (int): Assists recorded +- `points` (int): Total points +- `plusMinus` (int): Plus/minus rating +- `penaltyMinutes` (int): Penalty minutes +- `shots` (int): Shots on goal +- `timeOnIcePerGame` (float): Average time on ice per game +- Additional summary stat columns depending on the report type + +**Performance note:** This is the slowest helper method. With the default 1-second sleep rate, expect a minimum of 64 seconds (32 roster calls + 32 stats calls). A logging warning is emitted when the method starts. Increase `api_sleep_rate` if you encounter rate limiting. diff --git a/docs/misc.md b/docs/misc.md new file mode 100644 index 0000000..1ebacbf --- /dev/null +++ b/docs/misc.md @@ -0,0 +1,154 @@ +# Misc API Module + +The misc module provides utility and reference data endpoints for the NHL API, including glossary definitions, configuration options, country lists, historical season rules, and draft information. Access it via `client.misc` on an `NHLClient` instance. + +## Get NHL Glossary with glossary + +Returns all 321 NHL statistical term definitions sorted by full name. Useful for building tooltips, data dictionaries, or looking up stat abbreviations programmatically. + +```python +from nhlpy import NHLClient + +client = NHLClient() +terms = client.misc.glossary() + +for term in terms: + print(f"{term['abbreviation']}: {term['fullName']} - {term['definition']}") +``` + +**Parameters:** None + +**Returns:** `List[dict]` containing 321 glossary entries. + +**Fields for each entry:** + +- `id` (int): Unique identifier for the glossary term +- `abbreviation` (str): Short abbreviation used in stats (e.g., "G", "A", "PTS", "TOI") +- `definition` (str): Human-readable description of the stat +- `fullName` (str): Full name of the statistic (e.g., "Goals", "Assists", "Points") +- `firstSeasonForStat` (int): The first NHL season this stat was tracked (e.g., 19171918) +- `languageCode` (str): Language code for the definition (e.g., "en") + +## Get Stats Configuration with config + +Returns available filter and report options for the stats endpoints. Use this to discover which report types, columns, and aggregations are supported when building stats queries. + +```python +from nhlpy import NHLClient + +client = NHLClient() +config = client.misc.config() + +# List available skater report types +for report_type in config["playerReportData"]: + print(f"Skater report: {report_type}") + +# List available goalie report types +for report_type in config["goalieReportData"]: + print(f"Goalie report: {report_type}") +``` + +**Parameters:** None + +**Returns:** `dict` with the following top-level keys. + +**Response structure:** + +- `playerReportData` (object): Keys are skater report type names (e.g., "summary", "realtime", "penalties", "powerplay", "penaltykill", "faceoffpercentages", "goalsForAgainst", "shootout", "percentages", "scoringRates", "scoringpergame", "bios", "faceoffwins", "timeonice") + - Each key maps to an object describing available columns and options for that report type +- `goalieReportData` (object): Keys are goalie report type names (e.g., "summary", "advanced", "savesByStrength", "shootout", "startedVsRelieved", "daysRest", "penaltyShots", "bios") + - Each key maps to an object describing available columns and options for that report type +- `teamReportData` (object): Keys are team report type names (e.g., "summary", "penalties", "powerplay", "penaltykill", "faceoffpercentages", "goalsForAgainst", "shootout", "percentages", "realtime", "outshootoutshotby", "goalsbyperiod", "leadingtrailing", "scoringfirst") + - Each key maps to an object describing available columns and options for that report type +- `aggregatedColumns` (list[str]): Column names that can be aggregated across multiple seasons +- `individualColumns` (list[str]): Column names that apply to individual season records + +## Get Hockey Nations with countries + +Returns a list of 49 countries associated with NHL hockey, including active and historical nations. Useful for filtering players by nationality or building country selector UIs. + +```python +from nhlpy import NHLClient + +client = NHLClient() +countries = client.misc.countries() + +for country in countries: + if country["hasPlayerStats"]: + print(f"{country['countryName']} ({country['id']})") +``` + +**Parameters:** None + +**Returns:** `List[dict]` containing 49 country entries. + +**Fields for each entry:** + +- `id` (str): Three-letter country code used as the primary identifier (e.g., "CAN", "USA", "SWE") +- `country3Code` (str): Three-letter country code (same as id) +- `countryCode` (str): Two-letter country code (e.g., "CA", "US", "SE") +- `countryName` (str): Full country name (e.g., "Canada", "United States", "Sweden") +- `nationalityName` (str): Nationality demonym (e.g., "Canadian", "American", "Swedish") +- `hasPlayerStats` (int): 1 if the country has players with NHL stats, 0 otherwise +- `isActive` (int): 1 if the country is currently active in the NHL, 0 otherwise +- `imageUrl` (str): URL to the country's flag image (full size) +- `thumbnailUrl` (str): URL to the country's flag image (thumbnail size) + +## Get Historical Season Rules with season_specific_rules_and_info + +Returns configuration and rules for all 108 historical NHL seasons, from the league's founding to the present. Includes game counts, date ranges, and which rules were in effect for each season. + +```python +from nhlpy import NHLClient + +client = NHLClient() +seasons = client.misc.season_specific_rules_and_info() + +for season in seasons: + ties = "Yes" if season["tiesInUse"] else "No" + print(f"{season['formattedSeasonId']}: {season['numberOfGames']} games, Ties: {ties}") +``` + +**Parameters:** None + +**Returns:** `List[dict]` containing 108 season entries. + +**Fields for each entry:** + +- `id` (int): Season identifier in YYYYYYYY format (e.g., 20242025) +- `formattedSeasonId` (str): Human-readable season format (e.g., "2024-25") +- `numberOfGames` (int): Number of regular season games per team +- `startDate` (str): Season start date +- `regularSeasonEndDate` (str): Last day of the regular season +- `conferencesInUse` (int): 1 if the conference structure was active, 0 otherwise +- `divisionsInUse` (int): 1 if divisions were active, 0 otherwise +- `pointForOTLossInUse` (int): 1 if teams received a point for overtime losses, 0 otherwise +- `tiesInUse` (int): 1 if games could end in a tie, 0 otherwise +- `wildcardInUse` (int): 1 if the wildcard playoff format was active, 0 otherwise +- `totalPlayoffGames` (int): Total number of playoff games played that season +- `totalRegularSeasonGames` (int): Total number of regular season games across all teams +- `olympicsParticipation` (int): 1 if the NHL paused for Olympic participation, 0 otherwise + +## Get Draft Years and Rounds with draft_year_and_rounds + +Returns a list of all 63 NHL draft years with the number of rounds held in each. Useful for building draft history browsers or validating draft-related queries. + +```python +from nhlpy import NHLClient + +client = NHLClient() +drafts = client.misc.draft_year_and_rounds() + +for draft in drafts: + print(f"{draft['draftYear']}: {draft['rounds']} rounds") +``` + +**Parameters:** None + +**Returns:** `List[dict]` containing 63 draft year entries. + +**Fields for each entry:** + +- `id` (int): Unique identifier for the draft year record +- `draftYear` (int): The calendar year of the draft (e.g., 2024) +- `rounds` (int): Number of rounds held in that draft diff --git a/docs/players.md b/docs/players.md new file mode 100644 index 0000000..334a5f4 --- /dev/null +++ b/docs/players.md @@ -0,0 +1,96 @@ +# Players API Module + +The players module provides methods for retrieving NHL player rosters and prospect information by team. Access it via `client.players` on an `NHLClient` instance. + +## Get Team Prospects with prospects_by_team + +Retrieves all prospects for a given NHL team, grouped by position. Returns forwards, defensemen, and goalies in separate lists. + +```python +from nhlpy import NHLClient + +client = NHLClient() +prospects = client.players.prospects_by_team(team_abbr="BUF") + +for forward in prospects["forwards"]: + print(f"{forward['firstName']['default']} {forward['lastName']['default']}") +``` + +**Parameters:** + +- `team_abbr` (str, required): Three-letter team abbreviation (e.g., "BUF", "TOR", "EDM") + +**Response structure:** + +- `forwards` (list): List of forward prospect objects +- `defensemen` (list): List of defensemen prospect objects +- `goalies` (list): List of goalie prospect objects + +**Player fields within each list:** + +- `id` (int): Unique NHL player identifier +- `headshot` (str): URL to the player's headshot image +- `firstName` (object): + - `default` (str): Player's first name +- `lastName` (object): + - `default` (str): Player's last name +- `positionCode` (str): Position code (e.g., "C", "L", "R", "D", "G") +- `shootsCatches` (str): Handedness ("L" or "R") +- `heightInInches` (int): Height in inches +- `weightInPounds` (int): Weight in pounds +- `heightInCentimeters` (int): Height in centimeters +- `weightInKilograms` (int): Weight in kilograms +- `birthDate` (str): Date of birth in "YYYY-MM-DD" format +- `birthCity` (object): + - `default` (str): City of birth +- `birthCountry` (str): Three-letter country code (e.g., "CAN", "USA") +- `sweaterNumber` (int, optional): Jersey number. Not all prospects have one assigned. +- `birthStateProvince` (object, optional): + - `default` (str): State or province of birth. Only present for some countries. + +## Get Team Roster with players_by_team + +Retrieves the full roster for a given team and season. This is an alias for `client.teams.team_roster()` and returns the same data structure. Use whichever access pattern fits your code organization. + +```python +from nhlpy import NHLClient + +client = NHLClient() +roster = client.players.players_by_team(team_abbr="TOR", season="20242025") + +for player in roster["forwards"]: + print(f"#{player['sweaterNumber']} {player['firstName']['default']} {player['lastName']['default']}") +``` + +**Parameters:** + +- `team_abbr` (str, required): Three-letter team abbreviation (e.g., "BUF", "TOR", "EDM") +- `season` (str, required): Season in YYYYYYYY format (e.g., "20242025") + +**Response structure:** + +- `forwards` (list): List of forward player objects +- `defensemen` (list): List of defensemen player objects +- `goalies` (list): List of goalie player objects + +**Player fields within each list:** + +- `id` (int): Unique NHL player identifier +- `headshot` (str): URL to the player's headshot image +- `firstName` (object): + - `default` (str): Player's first name +- `lastName` (object): + - `default` (str): Player's last name +- `sweaterNumber` (int): Jersey number +- `positionCode` (str): Position code (e.g., "C", "L", "R", "D", "G") +- `shootsCatches` (str): Handedness ("L" or "R") +- `heightInInches` (int): Height in inches +- `weightInPounds` (int): Weight in pounds +- `heightInCentimeters` (int): Height in centimeters +- `weightInKilograms` (int): Weight in kilograms +- `birthDate` (str): Date of birth in "YYYY-MM-DD" format +- `birthCity` (object): + - `default` (str): City of birth +- `birthCountry` (str): Three-letter country code (e.g., "CAN", "USA") +- `birthStateProvince` (object, optional): + - `default` (str): State or province of birth. Only present for some countries. diff --git a/docs/schedule.md b/docs/schedule.md new file mode 100644 index 0000000..aea1301 --- /dev/null +++ b/docs/schedule.md @@ -0,0 +1,403 @@ +# Schedule API Reference + +The `schedule` module provides access to NHL game schedules at various granularities: daily, weekly, monthly, full-season, and team-specific views. It also covers playoff brackets, series schedules, and calendar-formatted data. All methods are accessed via `client.schedule` on an `NHLClient` instance. + +## Schedule: Get Daily Schedule + +Retrieve the NHL game schedule for a specific date. This method transforms the raw API response, extracting only the games for the requested date from the weekly data returned by the NHL API and adding a `numberOfGames` count. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get today's schedule +today = client.schedule.daily_schedule() + +# Get schedule for a specific date +schedule = client.schedule.daily_schedule(date="2024-01-15") + +print(f"Games on {schedule['date']}: {schedule['numberOfGames']}") +for game in schedule.get("games", []): + away = game["awayTeam"] + home = game["homeTeam"] + print(f"{away['abbrev']} @ {home['abbrev']} - {game['startTimeUTC']}") +``` + +**Parameters:** +- `date` (str, optional): Date in `"YYYY-MM-DD"` format. Defaults to today's date if omitted. + +**Response top-level fields:** +- `nextStartDate` (str): Next date with scheduled games +- `previousStartDate` (str): Previous date with scheduled games +- `date` (str): The requested date in YYYY-MM-DD format +- `oddsPartners` (None or list): Odds partner information +- `games` (list): Games scheduled for the specified date +- `numberOfGames` (int): Count of games on this date + +**`games[]` item fields:** +- `id` (int): Game ID (format: `YYYYTTNNNN`) +- `season` (int): Season identifier (e.g., 20232024) +- `gameType` (int): Game type (1=preseason, 2=regular, 3=playoffs) +- `venue` (object) + - `default` (str): Arena name +- `neutralSite` (bool): Whether the game is at a neutral site +- `startTimeUTC` (str): ISO 8601 game start time +- `gameState` (str): One of `"FUT"`, `"LIVE"`, `"OFF"`, `"FINAL"` +- `gameScheduleState` (str): Schedule status +- `tvBroadcasts` (list): TV broadcast details +- `awayTeam` (object) + - `id` (int): Team ID + - `commonName` (object) with `default` (str): Team common name + - `placeName` (object) with `default` (str): City/place name + - `abbrev` (str): Three-letter abbreviation + - `logo` (str): URL to team logo + - `darkLogo` (str): URL to dark-mode team logo + - `awaySplitSquad` (bool): Whether this is a split-squad game for the away team + - `score` (int): Goals scored (present for completed/in-progress games) +- `homeTeam` (object): Same structure as `awayTeam` but with `homeSplitSquad` instead of `awaySplitSquad` +- `periodDescriptor` (object): Current or final period information +- `gameOutcome` (object): Outcome data for completed games +- `winningGoalie` (object, completed games only) + - `playerId` (int): Goalie's player ID + - `firstInitial` (object) with `default` (str): First initial + - `lastName` (object) with `default` (str): Last name +- `winningGoalScorer` (object, completed games only): Same structure as `winningGoalie` +- `threeMinRecap` (str): URL to three-minute recap video +- `condensedGame` (str): URL to condensed game video +- `gameCenterLink` (str): Relative link to game center page + +## Schedule: Get Weekly Schedule + +Retrieve the full NHL schedule for a week, including metadata about preseason, regular season, and playoff date ranges. Unlike `daily_schedule`, this returns the raw API response without transformation. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get current week's schedule +week = client.schedule.weekly_schedule() + +# Get a specific week's schedule +week = client.schedule.weekly_schedule(date="2024-01-15") + +for day in week["gameWeek"]: + print(f"{day['date']} ({day['dayAbbrev']}): {day['numberOfGames']} games") + for game in day["games"]: + print(f" {game['awayTeam']['abbrev']} @ {game['homeTeam']['abbrev']}") +``` + +**Parameters:** +- `date` (str, optional): Date in `"YYYY-MM-DD"` format. Defaults to `"now"` (current week) if omitted. + +**Response top-level fields:** +- `nextStartDate` (str): Start date of the next week +- `previousStartDate` (str): Start date of the previous week +- `gameWeek` (list): 7 day objects covering the week +- `preSeasonStartDate` (str): Preseason start date +- `regularSeasonStartDate` (str): Regular season start date +- `regularSeasonEndDate` (str): Regular season end date +- `playoffEndDate` (str): Playoff end date +- `numberOfGames` (int): Total games across the week + +**`gameWeek[]` item fields:** +- `date` (str): Date in YYYY-MM-DD format +- `dayAbbrev` (str): Day abbreviation (e.g., "MON", "TUE") +- `numberOfGames` (int): Number of games on this day +- `games` (list): Game objects (same structure as `daily_schedule` games) + +## Schedule: Get Team Monthly Schedule + +Retrieve the schedule for a specific team for a given month. Returns a flat list of game dicts (not wrapped in a top-level object). If no month is provided, defaults to the current month. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get current month's schedule for Buffalo +games = client.schedule.team_monthly_schedule(team_abbr="BUF") + +# Get a specific month +games = client.schedule.team_monthly_schedule(team_abbr="TOR", month="2024-01") + +for game in games: + away = game["awayTeam"] + home = game["homeTeam"] + print(f"{game['gameDate']}: {away['abbrev']} @ {home['abbrev']} ({game['gameState']})") +``` + +**Parameters:** +- `team_abbr` (str, required): Three-letter team abbreviation (e.g., `"BUF"`, `"TOR"`, `"NYR"`) +- `month` (str, optional): Month in `"YYYY-MM"` format (e.g., `"2024-01"`). Defaults to current month if omitted. + +**Returns:** `List[dict]` -- a list of game dicts (not wrapped in a top-level object). + +**Each game dict fields:** +- `id` (int): Game ID +- `season` (int): Season identifier +- `gameType` (int): Game type (1=preseason, 2=regular, 3=playoffs) +- `gameDate` (str): Date in YYYY-MM-DD format +- `venue` (object) + - `default` (str): Arena name +- `neutralSite` (bool): Whether the game is at a neutral site +- `startTimeUTC` (str): ISO 8601 start time +- `gameState` (str): One of `"FUT"`, `"LIVE"`, `"OFF"`, `"FINAL"` +- `tvBroadcasts` (list): TV broadcast details +- `awayTeam` (object) + - `commonName` (object) with `default` (str): Team common name + - `abbrev` (str): Three-letter abbreviation + - `logo` (str): URL to team logo + - `score` (int): Goals scored (present for completed games) +- `homeTeam` (object): Same as `awayTeam` plus: + - `airlineLink` (str): Airline partner link (home games) + - `airlineDesc` (str): Airline partner description + - `hotelLink` (str): Hotel partner link (home games) + - `hotelDesc` (str): Hotel partner description +- `periodDescriptor` (object): Period information +- `gameOutcome` (object): Outcome for completed games +- `winningGoalie` (object): Winning goalie info (playerId, firstInitial, lastName) +- `winningGoalScorer` (object): Winning goal scorer info +- `threeMinRecap` (str): URL to recap video +- `condensedGame` (str): URL to condensed game video +- `gameCenterLink` (str): Relative game center link + +## Schedule: Get Team Weekly Schedule + +Retrieve the schedule for a specific team for the week containing a given date. Returns a flat list of game dicts. If no date is provided, defaults to the current week. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Get current week's games for Edmonton +games = client.schedule.team_weekly_schedule(team_abbr="EDM") + +# Get a specific week +games = client.schedule.team_weekly_schedule(team_abbr="EDM", date="2024-03-11") + +for game in games: + print(f"{game['gameDate']}: {game['awayTeam']['abbrev']} @ {game['homeTeam']['abbrev']}") +``` + +**Parameters:** +- `team_abbr` (str, required): Three-letter team abbreviation (e.g., `"EDM"`, `"BOS"`) +- `date` (str, optional): Date in `"YYYY-MM-DD"` format. Retrieves the week containing this date. Defaults to current week if omitted. + +**Returns:** `List[dict]` -- a list of game dicts with the same structure as `team_monthly_schedule` games. + +## Schedule: Get Team Full Season Schedule + +Retrieve the complete schedule for a team across an entire season, including metadata about adjacent seasons and the team's timezone. + +```python +from nhlpy import NHLClient + +client = NHLClient() +season_data = client.schedule.team_season_schedule(team_abbr="BUF", season="20232024") + +print(f"Timezone: {season_data['clubTimezone']}") +print(f"Total games: {len(season_data['games'])}") + +for game in season_data["games"]: + print(f"{game['gameDate']}: {game['awayTeam']['abbrev']} @ {game['homeTeam']['abbrev']}") +``` + +**Parameters:** +- `team_abbr` (str, required): Three-letter team abbreviation (e.g., `"BUF"`) +- `season` (str, required): Season in `"YYYYYYYY"` format (e.g., `"20232024"`) + +**Response top-level fields:** +- `previousSeason` (int): Previous season identifier (e.g., 20222023) +- `currentSeason` (int): Current season identifier (e.g., 20232024) +- `nextSeason` (int): Next season identifier (e.g., 20242025) +- `clubTimezone` (str): Team's timezone (e.g., "US/Eastern") +- `clubUTCOffset` (str): UTC offset (e.g., "-05:00") +- `games` (list): All games for the season (same game structure as `team_monthly_schedule`) + +## Schedule: Get Calendar Schedule + +Retrieve the schedule in a calendar view format showing all 32 teams. This provides a high-level overview of all teams and their basic information for a given date range. + +```python +from nhlpy import NHLClient + +client = NHLClient() +calendar = client.schedule.calendar_schedule(date="2024-01-15") + +print(f"Schedule from {calendar['startDate']} to {calendar['endDate']}") +for team in calendar["teams"]: + print(f"{team['abbrev']}: {team['name']['default']}") +``` + +**Parameters:** +- `date` (str, required): Date in `"YYYY-MM-DD"` format (e.g., `"2024-01-15"`) + +**Response top-level fields:** +- `startDate` (str): Start of the calendar range +- `endDate` (str): End of the calendar range +- `nextStartDate` (str): Next calendar period start +- `previousStartDate` (str): Previous calendar period start +- `teams` (list): All 32 NHL teams + +**`teams[]` item fields:** +- `id` (int): Team ID +- `seasonId` (int): Season identifier +- `commonName` (object) + - `default` (str): Team common name (e.g., "Sabres") +- `abbrev` (str): Three-letter abbreviation (e.g., "BUF") +- `name` (object) + - `default` (str): Full team name (e.g., "Buffalo Sabres") +- `placeName` (object) + - `default` (str): City/place name +- `logo` (str): URL to team logo +- `darkLogo` (str): URL to dark-mode team logo +- `french` (bool): Whether this is the French-language version + +## Schedule: Get Playoff Carousel + +Retrieve an overview of all playoff series up to the current round for a given season, including series results, win totals, and team seeding. + +```python +from nhlpy import NHLClient + +client = NHLClient() +playoffs = client.schedule.playoff_carousel(season="20232024") + +print(f"Current round: {playoffs['currentRound']}") +for rnd in playoffs["rounds"]: + print(f"\n{rnd['roundLabel']} ({rnd['roundAbbrev']}):") + for series in rnd["series"]: + print(f" {series['seriesLabel']}: {series['seriesLetter']}") +``` + +**Parameters:** +- `season` (str, required): Season in `"YYYYYYYY"` format (e.g., `"20232024"`) + +**Response top-level fields:** +- `seasonId` (int): Season identifier +- `currentRound` (int): Current active playoff round number +- `rounds` (list): All playoff rounds + +**`rounds[]` item fields:** +- `roundNumber` (int): Round number (1-4) +- `roundLabel` (str): Human-readable round name (e.g., "First Round") +- `roundAbbrev` (str): Round abbreviation (e.g., `"R1"`, `"R2"`, `"R3"`, `"R4"`) +- `series` (list): All series in this round + +**`series[]` item fields:** +- `seriesLetter` (str): Series identifier letter (e.g., "A" through "H" for Round 1) +- `seriesLabel` (str): Human-readable series label +- `seriesLink` (str): Link to series details +- `bottomSeed` (object): Lower-seeded team information +- `topSeed` (object): Higher-seeded team information +- `neededToWin` (int): Wins needed to clinch (4 for NHL playoffs) +- `winningTeamId` (int): ID of the series winner (0 if ongoing) +- `losingTeamId` (int): ID of the series loser (0 if ongoing) + +## Schedule: Get Playoff Bracket + +Retrieve visual playoff bracket data for a given year, including all 15 series across 4 rounds with team seedings, win counts, and logos. + +```python +from nhlpy import NHLClient + +client = NHLClient() +bracket = client.schedule.playoff_bracket(year="2024") + +for series in bracket["series"]: + top = series["topSeedTeam"] + bottom = series["bottomSeedTeam"] + print(f"Round {series['playoffRound']}: " + f"({series['topSeedRank']}) {top['abbrev']} {series['topSeedWins']} - " + f"{series['bottomSeedWins']} {bottom['abbrev']} ({series['bottomSeedRank']})") +``` + +**Parameters:** +- `year` (str, required): Calendar year the playoffs take place (e.g., `"2024"`) + +**Response top-level fields:** +- `bracketLogo` (str): URL to the playoff bracket logo +- `series` (list): All 15 playoff series + +**`series[]` item fields:** +- `seriesUrl` (str): URL to series detail page +- `seriesTitle` (str): Human-readable series title +- `seriesAbbrev` (str): Series abbreviation +- `seriesLetter` (str): Series letter identifier +- `playoffRound` (int): Round number (1-4) +- `topSeedRank` (int): Higher seed's rank in their conference +- `topSeedWins` (int): Higher seed's wins in the series +- `bottomSeedRank` (int): Lower seed's rank in their conference +- `bottomSeedWins` (int): Lower seed's wins in the series +- `winningTeamId` (int): ID of the series winner (0 if ongoing) +- `losingTeamId` (int): ID of the series loser (0 if ongoing) +- `topSeedTeam` (object) + - `id` (int): Team ID + - `abbrev` (str): Three-letter abbreviation + - `name` (object) with `default` (str): Full team name + - `logo` (str): URL to team logo +- `bottomSeedTeam` (object): Same structure as `topSeedTeam` + +## Schedule: Get Playoff Series Schedule (Games, Results, Series Status) + +Retrieve the full schedule and results for a specific playoff series, including every game with scores, series status after each game, and team seeding info. + +**Method**: `client.schedule.playoff_series_schedule(season: str, series: str) -> dict` + +**Parameters:** +- `season` (str, required): Season in `"YYYYYYYY"` format (e.g., `"20252026"`) +- `series` (str, required): Series letter identifier (lowercase). `"a"`-`"h"` for Round 1, `"i"`-`"l"` for Round 2, `"m"`-`"n"` for Conference Finals, `"o"` for Stanley Cup Final. + +**Response shape:** +- `round` (int): Playoff round number (1-4) +- `roundAbbrev` (str): Round abbreviation (e.g., "R1") +- `roundLabel` (str): Round label (e.g., "1st-round") +- `seriesLetter` (str): Series letter (e.g., "B") +- `neededToWin` (int): Wins required to advance (4) +- `length` (int): Total games played in the series +- `topSeedTeam` (object): Higher-seeded team + - `id` (int): Team ID + - `abbrev` (str): Team abbreviation (e.g., "TBL") + - `name.default` (str): Team name (e.g., "Lightning") + - `seed` (int): Seed number + - `record` (str): Series record (e.g., "3-4") + - `seriesWins` (int): Series wins + - `logo` (str): Team logo URL + - `conference.name` (str): Conference name + - `divisionAbbrev` (str): Division abbreviation +- `bottomSeedTeam` (object): Lower-seeded team (same structure as topSeedTeam) +- `games` (list): List of game objects in the series + - `id` (int): Game ID (e.g., 2025030121) + - `gameNumber` (int): Game number within the series (1-7) + - `ifNecessary` (bool): Whether the game was an "if necessary" game + - `gameState` (str): "FUT", "LIVE", "OFF" + - `gameType` (int): Always 3 (playoffs) + - `season` (int): Season ID + - `startTimeUTC` (str): ISO 8601 start time + - `venue.default` (str): Arena name + - `awayTeam` (object): Away team with abbrev, commonName.default, score + - `homeTeam` (object): Home team with abbrev, commonName.default, score + - `seriesStatus` (object): Series state after this game + - `topSeedWins` (int): Top seed wins after this game + - `bottomSeedWins` (int): Bottom seed wins after this game + - `gameOutcome.lastPeriodType` (str): "REG", "OT" + - `gameCenterLink` (str): Relative URL to game center + - `tvBroadcasts` (list): TV broadcast info +- `seriesLogo` (str): URL of the playoff series logo +- `fullCoverageUrl` (object): Localized URLs keyed by language code (en, fr, etc.) + +**Example:** +```python +from nhlpy import NHLClient + +client = NHLClient() +series = client.schedule.playoff_series_schedule(season="20252026", series="b") +top = series["topSeedTeam"] +bot = series["bottomSeedTeam"] +print(f"{top['abbrev']} ({top['record']}) vs {bot['abbrev']} ({bot['record']})") +for game in series["games"]: + print(f"Game {game['gameNumber']}: {game['awayTeam']['abbrev']} {game['awayTeam']['score']} @ {game['homeTeam']['abbrev']} {game['homeTeam']['score']}") +``` diff --git a/docs/standings.md b/docs/standings.md new file mode 100644 index 0000000..f452066 --- /dev/null +++ b/docs/standings.md @@ -0,0 +1,110 @@ +# Standings API + +The Standings module provides access to NHL league standings and historical season metadata. Access it via `client.standings` on an `NHLClient` instance. + +## Standings: Get Current or Historical League Standings + +Retrieves NHL standings for the current date, a specific date, or the end of a historical season. Supply either `season` or `date` but not both -- if both are provided, `season` takes precedence. When neither is provided, returns standings for the current date. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current standings +standings = client.standings.league_standings() + +# Standings for a specific date +standings = client.standings.league_standings(date="2025-01-15") + +# Final standings for a completed season +standings = client.standings.league_standings(season="20232024") +``` + +- **Parameters** + - `season` (str, optional): Season identifier in YYYYYYYY format (e.g., "20232024"). When provided, the method looks up the last date of that season via the season manifest and returns final standings. Takes precedence over `date` if both are supplied. + - `date` (str, optional): Date in YYYY-MM-DD format. Returns standings as of that date. Defaults to "now" (current date) when neither parameter is provided. +- **Returns**: dict with standings metadata and a list of team standing objects + - `wildCardIndicator` (bool): Whether wildcard standings apply + - `standings` (list): 32 team standing entries, one per team +- **Team standing fields** + - `teamName.default` (str): Full team name (e.g., "Winnipeg Jets") + - `teamCommonName.default` (str): Common name (e.g., "Jets") + - `teamAbbrev.default` (str): Three-letter abbreviation (e.g., "WPG") + - `teamLogo` (str): URL to team logo + - `conferenceAbbrev` (str): Conference abbreviation ("E" or "W") + - `conferenceName` (str): Conference name ("Eastern" or "Western") + - `divisionAbbrev` (str): Division abbreviation ("A", "M", "C", or "P") + - `divisionName` (str): Division name ("Atlantic", "Metropolitan", "Central", or "Pacific") + - `conferenceSequence` (int): Rank within conference + - `divisionSequence` (int): Rank within division + - `leagueSequence` (int): Rank across the entire league + - `wildcardSequence` (int): Wildcard ranking (0 if not in wildcard position) + - `date` (str): Standings date + - `seasonId` (int): Season identifier + - `placeName.default` (str): City or place name + - **Record fields** + - `gamesPlayed` (int) + - `wins` (int) + - `losses` (int) + - `otLosses` (int): Overtime losses + - `points` (int) + - `pointPctg` (float): Points percentage + - `regulationWins` (int) + - `regulationPlusOtWins` (int): Regulation plus overtime wins (ROW) + - `goalFor` (int): Total goals scored + - `goalAgainst` (int): Total goals allowed + - `goalDifferential` (int): Goal differential + - **Streak fields** + - `streakCode` (str): Current streak type ("W" for wins, "L" for losses, "OT" for OT losses) + - `streakCount` (int): Length of current streak + - **Home record** + - `homeWins` (int) + - `homeLosses` (int) + - `homePoints` (int) + - **Road record** + - `roadWins` (int) + - `roadLosses` (int) + - `roadPoints` (int) + - **Last 10 games** + - `l10Wins` (int) + - `l10Losses` (int) + - `l10Points` (int) + - **Shootout record** + - `shootoutWins` (int) + - `shootoutLosses` (int) + - **Clinch indicator** + - `clinchIndicator` (str, optional): Playoff clinch status. Not present during regular season before clinching begins. + - `"p"` = Clinched Presidents' Trophy + - `"x"` = Clinched playoff spot + - `"y"` = Clinched division title + - `"z"` = Clinched conference title + +## Standings: Get Historical Season Metadata + +Returns metadata for every NHL season in the standings system. Useful for discovering valid season identifiers, date ranges, and which rules were in effect for each season. + +```python +from nhlpy import NHLClient + +client = NHLClient() +seasons = client.standings.season_standing_manifest() + +# Find a specific season +season_2024 = next(s for s in seasons if s["id"] == 20242025) +print(season_2024["standingsStart"]) # First day of standings +print(season_2024["standingsEnd"]) # Last day of standings +``` + +- **Parameters**: None +- **Returns**: list of dicts, one per historical season + - `id` (int): Season identifier in YYYYYYYY format (e.g., 20242025) + - `conferencesInUse` (bool): Whether conferences were used for standings + - `divisionsInUse` (bool): Whether divisions were used for standings + - `pointForOTlossInUse` (bool): Whether a point was awarded for overtime losses + - `regulationWinsInUse` (bool): Whether regulation wins were tracked separately + - `rowInUse` (bool): Whether regulation/overtime wins (ROW) tiebreaker was active + - `standingsStart` (str): First date of standings for the season (YYYY-MM-DD) + - `standingsEnd` (str): Last date of standings for the season (YYYY-MM-DD) + - `tiesInUse` (bool): Whether tie games were possible (pre-shootout era) + - `wildcardInUse` (bool): Whether wildcard playoff format was in effect diff --git a/docs/stats.md b/docs/stats.md new file mode 100644 index 0000000..e82ab00 --- /dev/null +++ b/docs/stats.md @@ -0,0 +1,425 @@ +# Stats API + +The Stats module provides access to player statistics, team statistics, goalie statistics, and advanced query-based stat lookups. Access it via `client.stats` on an `NHLClient` instance. + +## Stats: List Game Types Per Season for a Team + +Returns every season a team has played along with which game types (regular season, playoffs, etc.) occurred in each season. Useful for discovering which seasons had playoff appearances. + +```python +from nhlpy import NHLClient + +client = NHLClient() +seasons = client.stats.gametypes_per_season_directory_by_team(team_abbr="TOR") +``` + +- **Parameters** + - `team_abbr` (str, required): Three-letter team abbreviation (e.g., "TOR", "BUF", "EDM") +- **Returns**: list of dicts, one per season + - `season` (int): Season identifier such as 20242025 + - `gameTypes` (list[int]): Game type codes present in that season + - `2` = Regular season + - `3` = Playoffs + +## Stats: Get Player Career Statistics and Biography + +Retrieves a comprehensive player profile including biographical details, career totals, featured stats, recent games, season-by-season totals, and awards. + +```python +from nhlpy import NHLClient + +client = NHLClient() +player = client.stats.player_career_stats(player_id="8478402") +``` + +- **Parameters** + - `player_id` (str, required): Unique NHL player identifier (e.g., "8478402" for Connor McDavid) +- **Returns**: dict with top-level biographical fields and nested stat objects + - `playerId` (int): Unique player identifier + - `isActive` (bool): Whether the player is currently active + - `currentTeamId` (int): Numeric team identifier + - `currentTeamAbbrev` (str): Three-letter team abbreviation + - `fullTeamName.default` (str): Full team name (e.g., "Edmonton Oilers") + - `firstName.default` (str): Player first name + - `lastName.default` (str): Player last name + - `sweaterNumber` (int): Jersey number + - `position` (str): Position code ("C", "L", "R", "D", "G") + - `headshot` (str): URL to player headshot image + - `heroImage` (str): URL to player hero image + - `heightInInches` (int): Height in inches + - `weightInPounds` (int): Weight in pounds + - `birthDate` (str): Date of birth + - `birthCity.default` (str): Birth city + - `birthCountry` (str): Birth country code + - `shootsCatches` (str): "L" or "R" + - `draftDetails` (object): Draft information + - `year` (int): Draft year + - `teamAbbrev` (str): Drafting team + - `round` (int): Draft round + - `pickInRound` (int): Pick number within the round + - `overallPick` (int): Overall draft position + - `playerSlug` (str): URL-safe player name slug + - `careerTotals.regularSeason` (object): Career regular season totals + - `gamesPlayed` (int) + - `goals` (int) + - `assists` (int) + - `points` (int) + - `plusMinus` (int) + - `pim` (int): Penalty minutes + - `powerPlayGoals` (int) + - `powerPlayPoints` (int) + - `shots` (int) + - `avgToi` (str): Average time on ice per game + - `shootingPctg` (float) + - `gameWinningGoals` (int) + - `shorthandedGoals` (int) + - `careerTotals.playoffs` (object): Same fields as regularSeason + - `featuredStats.season` (int): Season identifier for featured stats + - `featuredStats.regularSeason.subSeason` (object): Current season stats + - `featuredStats.regularSeason.career` (object): Career aggregates + - `last5Games` (list): Most recent five games + - `gameDate` (str): Game date + - `gameId` (int): Game identifier + - `goals` (int) + - `assists` (int) + - `points` (int) + - `plusMinus` (int) + - `shots` (int) + - `toi` (str): Time on ice + - `opponentAbbrev` (str): Opponent team abbreviation + - `homeRoadFlag` (str): "H" for home, "R" for road + - `seasonTotals` (list): Per-season stats across all leagues + - `season` (int): Season identifier + - `leagueAbbrev` (str): League abbreviation (e.g., "NHL", "AHL") + - `teamName.default` (str): Team name for that season + - `gamesPlayed` (int) + - `goals` (int) + - `assists` (int) + - `points` (int) + - `awards` (list): Player awards history + - `trophy.default` (str): Trophy name + - `seasons` (list): Award season details + +## Stats: Get Player Game Log for a Season + +Returns game-by-game statistics for a specific player in a given season and game type. Each entry represents one game. + +```python +from nhlpy import NHLClient + +client = NHLClient() +games = client.stats.player_game_log( + player_id="8478402", + season_id="20242025", + game_type=2 +) +``` + +- **Parameters** + - `player_id` (str, required): Unique NHL player identifier + - `season_id` (str, required): Season in YYYYYYYY format (e.g., "20242025") + - `game_type` (int, required): Type of games to retrieve + - `1` = Preseason + - `2` = Regular season + - `3` = Playoffs +- **Returns**: list of dicts, one per game + - `gameId` (int): Unique game identifier + - `teamAbbrev` (str): Player's team abbreviation + - `homeRoadFlag` (str): "H" for home, "R" for road + - `gameDate` (str): Date of the game + - `goals` (int) + - `assists` (int) + - `commonName.default` (str): Player's team name + - `opponentCommonName.default` (str): Opponent team name + - `points` (int) + - `plusMinus` (int) + - `powerPlayGoals` (int) + - `powerPlayPoints` (int) + - `gameWinningGoals` (int) + - `otGoals` (int): Overtime goals + - `shots` (int) + - `shifts` (int) + - `shorthandedGoals` (int) + - `shorthandedPoints` (int) + - `opponentAbbrev` (str): Opponent abbreviation + - `pim` (int): Penalty minutes + - `toi` (str): Time on ice in "MM:SS" format + +## Stats: Get Team Summary Statistics + +Retrieves aggregated team statistics for one or more seasons. For a single season, set `start_season` equal to `end_season`. Supports pagination, sorting, and Apache Cayenne filter expressions. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Single season +teams = client.stats.team_summary( + start_season="20242025", + end_season="20242025" +) + +# Multiple seasons, playoffs only +teams = client.stats.team_summary( + start_season="20222023", + end_season="20242025", + game_type_id=3, + is_aggregate=True +) +``` + +- **Parameters** + - `start_season` (str, required): Start of range in YYYYYYYY format (e.g., "20242025") + - `end_season` (str, required): End of range in YYYYYYYY format + - `game_type_id` (int, default 2): Game type (1=Preseason, 2=Regular season, 3=Playoffs) + - `is_game` (bool, default False): API parameter for game-level granularity + - `is_aggregate` (bool, default False): Whether to aggregate stats across seasons + - `sort_expr` (list[dict], optional): Sorting criteria. Defaults to points DESC, wins DESC, teamId ASC + - `start` (int, default 0): Pagination offset + - `limit` (int, default 50): Maximum results to return + - `fact_cayenne_exp` (str, default "gamesPlayed>1"): Apache Cayenne filter expression + - `default_cayenne_exp` (str, optional): Overrides the auto-generated Cayenne expression if provided +- **Returns**: list of dicts, one per team + - `teamFullName` (str): Full team name + - `teamId` (int): Team identifier + - `seasonId` (int): Season identifier + - `gamesPlayed` (int) + - `wins` (int) + - `losses` (int) + - `otLosses` (int): Overtime losses + - `points` (int) + - `pointPct` (float): Points percentage + - `goalsFor` (int) + - `goalsAgainst` (int) + - `goalsForPerGame` (float) + - `goalsAgainstPerGame` (float) + - `powerPlayPct` (float) + - `penaltyKillPct` (float) + - `shotsForPerGame` (float) + - `shotsAgainstPerGame` (float) + - `faceoffWinPct` (float) + - `regulationAndOtWins` (int) + - `winsInRegulation` (int) + - `winsInShootout` (int) + - `teamShutouts` (int) + +## Stats: Get Skater Statistics Leaderboard + +Returns league-wide skater statistics with pagination and optional franchise filtering. Results are sorted by points descending by default. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Top 25 skaters for 2024-2025 +skaters = client.stats.skater_stats_summary( + start_season="20242025", + end_season="20242025" +) + +# Filter by franchise, larger page +skaters = client.stats.skater_stats_summary( + start_season="20242025", + end_season="20242025", + franchise_id="10", + limit=50 +) +``` + +- **Parameters** + - `start_season` (str, required): Start of range in YYYYYYYY format + - `end_season` (str, required): End of range in YYYYYYYY format + - `franchise_id` (str, optional): Filter to a specific franchise (note: franchise IDs differ from team IDs) + - `game_type_id` (int, default 2): Game type (1=Preseason, 2=Regular season, 3=Playoffs) + - `aggregate` (bool, default False): Combine multiple seasons per player when True + - `sort_expr` (list[dict], optional): Sorting criteria. Defaults to points DESC, gamesPlayed ASC, playerId ASC + - `start` (int, default 0): Pagination offset + - `limit` (int, default 25): Maximum results to return + - `fact_cayenne_exp` (str, default "gamesPlayed>=1"): Apache Cayenne filter expression + - `default_cayenne_exp` (str, optional): Overrides auto-generated Cayenne expression +- **Returns**: list of dicts, one per skater + - `skaterFullName` (str): Full player name + - `playerId` (int): Unique player identifier + - `lastName` (str) + - `positionCode` (str): "C", "L", "R", or "D" + - `teamAbbrevs` (str): Team abbreviation + - `seasonId` (int) + - `gamesPlayed` (int) + - `goals` (int) + - `assists` (int) + - `points` (int) + - `plusMinus` (int) + - `pointsPerGame` (float) + - `evGoals` (int): Even-strength goals + - `evPoints` (int): Even-strength points + - `ppGoals` (int): Power play goals + - `ppPoints` (int): Power play points + - `shGoals` (int): Shorthanded goals + - `shPoints` (int): Shorthanded points + - `gameWinningGoals` (int) + - `otGoals` (int): Overtime goals + - `shots` (int) + - `shootingPct` (float) + - `penaltyMinutes` (int) + - `faceoffWinPct` (float) + - `timeOnIcePerGame` (float): Time on ice per game in seconds + - `shootsCatches` (str): "L" or "R" + +## Stats: Advanced Skater Stats with QueryBuilder + +Uses the QueryBuilder system to construct complex filtered queries for skater statistics. Supports multiple report types and filter combinations including draft class, position, nationality, and more. + +```python +from nhlpy import NHLClient +from nhlpy.api.query.builder import QueryBuilder, QueryContext +from nhlpy.api.query.filters.game_type import GameTypeQuery +from nhlpy.api.query.filters.season import SeasonQuery +from nhlpy.api.query.filters.draft import DraftQuery +from nhlpy.api.query.filters.position import PositionQuery, PositionTypes + +client = NHLClient() + +filters = [ + GameTypeQuery(game_type="2"), + DraftQuery(year="2020", draft_round="2"), + SeasonQuery(season_start="20202021", season_end="20242025"), + 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 +) +``` + +- **Parameters** + - `query_context` (QueryContext, required): Built from QueryBuilder with one or more filters + - `report_type` (str, required): Type of statistical report. Options: + - `"summary"` -- General stats overview + - `"bios"` -- Biographical information + - `"faceoffpercentages"` -- Faceoff statistics + - `"faceoffwins"` -- Faceoff win counts + - `"goalsForAgainst"` -- Goals for/against breakdown + - `"realtime"` -- Real-time tracking stats + - `"penalties"` -- Penalty statistics + - `"penaltykill"` -- Penalty kill stats + - `"penaltyShots"` -- Penalty shot stats + - `"powerplay"` -- Power play stats + - `"puckPossessions"` -- Puck possession metrics + - `"summaryshooting"` -- Shooting summary + - `"percentages"` -- Percentage-based stats + - `"scoringRates"` -- Scoring rate stats + - `"scoringpergame"` -- Per-game scoring + - `"shootout"` -- Shootout stats + - `"shottype"` -- Shot type breakdown + - `"timeonice"` -- Time on ice breakdown + - `sort_expr` (list[dict], optional): Custom sorting criteria + - `aggregate` (bool, default False): Combine multiple seasons per player + - `start` (int, default 0): Pagination offset + - `limit` (int, default 25): Maximum results +- **Returns**: dict with a `"data"` key containing a list of skater stat dicts + +**Important: Response fields vary by `report_type`.** The only fields common across all report types are: +- `playerId` (int): Unique player identifier +- `skaterFullName` (str): Full display name +- `teamAbbrevs` (str): Three-letter team abbreviation(s) +- `seasonId` (int): Season identifier +- `gamesPlayed` (int): Total games played + +For example, `"summary"` returns goals/assists/points/shots, `"realtime"` returns hits/blocks/giveaways, `"penalties"` returns minorPenalties/majorPenalties. Use `client.misc.config()` to discover the available fields for each report type via the `playerReportData` key. + +## Stats: Available Query Filters for QueryBuilder + +The QueryBuilder accepts a list of filter objects that each implement `QueryBase`. Combine any number of these filters to construct precise queries. + +```python +from nhlpy.api.query.filters.game_type import GameTypeQuery +from nhlpy.api.query.filters.season import SeasonQuery +from nhlpy.api.query.filters.position import PositionQuery, PositionTypes +from nhlpy.api.query.filters.draft import DraftQuery +from nhlpy.api.query.filters.franchise import FranchiseQuery +from nhlpy.api.query.filters.nationality import NationalityQuery +``` + +- **GameTypeQuery(game_type: str)**: Filter by game type ("1"=Preseason, "2"=Regular season, "3"=Playoffs) +- **SeasonQuery(season_start: str, season_end: str)**: Filter by season range (e.g., "20202021", "20242025") +- **PositionQuery(position: PositionTypes)**: Filter by position + - `PositionTypes.ALL_FORWARDS` ("F") -- All forward positions + - `PositionTypes.CENTER` ("C") + - `PositionTypes.LEFT_WING` ("L") + - `PositionTypes.RIGHT_WING` ("R") + - `PositionTypes.DEFENSE` ("D") +- **DraftQuery(year: str, draft_round: str = None)**: Filter by draft year and optionally round +- **FranchiseQuery(franchise_id: str)**: Filter by franchise identifier +- **NationalityQuery(nation_code: str)**: Filter by country code (e.g., "CAN", "USA", "SWE", "FIN", "CZE") + +## Stats: Get Goalie Statistics Leaderboard + +Returns league-wide goalie statistics with multiple report types, pagination, and optional franchise filtering. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Default summary stats +goalies = client.stats.goalie_stats_summary( + start_season="20242025" +) + +# Advanced goalie stats for a specific franchise +goalies = client.stats.goalie_stats_summary( + start_season="20242025", + stats_type="advanced", + franchise_id="10" +) +``` + +- **Parameters** + - `start_season` (str, required): Start of range in YYYYYYYY format + - `end_season` (str, optional): End of range. Defaults to `start_season` if not provided + - `stats_type` (str, default "summary"): Report type. Options: + - `"summary"` -- General goalie stats + - `"advanced"` -- Advanced metrics + - `"bios"` -- Biographical data + - `"daysrest"` -- Stats by days of rest + - `"penaltyShots"` -- Penalty shot performance + - `"savesByStrength"` -- Saves by game situation + - `"shootout"` -- Shootout performance + - `"startedVsRelieved"` -- Starter vs. reliever stats + - `game_type_id` (int, default 2): Game type (1=Preseason, 2=Regular season, 3=Playoffs) + - `franchise_id` (str, optional): Filter to a specific franchise + - `aggregate` (bool, default False): Combine multiple seasons per goalie + - `sort_expr` (list[dict], optional): Custom sorting. Uses NHL Edge defaults per report type + - `start` (int, default 0): Pagination offset + - `limit` (int, default 25): Maximum results + - `fact_cayenne_exp` (str, optional): Apache Cayenne filter expression + - `default_cayenne_exp` (str, optional): Overrides auto-generated Cayenne expression +- **Returns**: list of dicts, one per goalie (summary report fields shown) + - `goalieFullName` (str): Full goalie name + - `playerId` (int): Unique player identifier + - `lastName` (str) + - `seasonId` (int) + - `teamAbbrevs` (str): Team abbreviation + - `gamesPlayed` (int) + - `gamesStarted` (int) + - `wins` (int) + - `losses` (int) + - `otLosses` (int): Overtime losses + - `savePct` (float): Save percentage + - `goalsAgainstAverage` (float) + - `saves` (int) + - `shotsAgainst` (int) + - `shutouts` (int) + - `timeOnIce` (int): Time on ice in seconds + - `goals` (int) + - `assists` (int) + - `points` (int) + - `penaltyMinutes` (int) + - `shootsCatches` (str): "L" or "R" diff --git a/docs/teams.md b/docs/teams.md new file mode 100644 index 0000000..ea9fa5b --- /dev/null +++ b/docs/teams.md @@ -0,0 +1,97 @@ +# Teams API + +The Teams module provides access to NHL team information, rosters, and franchise data. Access it via `client.teams` on an `NHLClient` instance. + +## Teams: List All Current NHL Teams + +Returns a list of all 32 current NHL teams with conference, division, and franchise information. This method transforms the raw API response into a clean, standardized format by combining standings data with franchise metadata. + +```python +from nhlpy import NHLClient + +client = NHLClient() + +# Current teams +teams = client.teams.teams() + +# Teams for a specific date (useful during preseason) +teams = client.teams.teams(date="2024-10-04") +``` + +- **Parameters** + - `date` (str, default "now"): Date in YYYY-MM-DD format. The NHL API resolves "now" to the current date, but during preseason this may return previous-season data. Supply a specific date at the start of the upcoming season to get accurate results (e.g., "2024-10-04" for the 2024-2025 season). +- **Returns**: list of dicts, one per team (32 entries for current NHL) + - `name` (str): Full team name (e.g., "Toronto Maple Leafs") + - `common_name` (str): Common team name (e.g., "Maple Leafs") + - `abbr` (str): Three-letter abbreviation (e.g., "TOR") + - `logo` (str): URL to the team logo SVG + - `franchise_id` (int): Franchise identifier, joined from the franchises endpoint + - `conference` (object): Conference details + - `abbr` (str): Conference abbreviation (e.g., "E", "W") + - `name` (str): Conference name (e.g., "Eastern", "Western") + - `division` (object): Division details + - `abbr` (str): Division abbreviation (e.g., "A", "M", "C", "P") + - `name` (str): Division name (e.g., "Atlantic", "Metropolitan", "Central", "Pacific") + +## Teams: Get Team Roster by Season + +Returns the full roster for a team in a given season, grouped by position category. + +```python +from nhlpy import NHLClient + +client = NHLClient() +roster = client.teams.team_roster(team_abbr="TOR", season="20242025") + +# Access by position group +forwards = roster["forwards"] +defensemen = roster["defensemen"] +goalies = roster["goalies"] +``` + +- **Parameters** + - `team_abbr` (str, required): Three-letter team abbreviation (e.g., "BUF", "TOR", "EDM") + - `season` (str, required): Season in YYYYYYYY format (e.g., "20242025") +- **Returns**: dict with three keys, each containing a list of player dicts + - `forwards` (list): Forward players + - `defensemen` (list): Defensemen + - `goalies` (list): Goaltenders +- **Player fields** (same for all position groups) + - `id` (int): Unique player identifier + - `headshot` (str): URL to player headshot image + - `firstName.default` (str): Player first name + - `lastName.default` (str): Player last name + - `sweaterNumber` (int): Jersey number + - `positionCode` (str): Position code + - `"L"` = Left wing + - `"R"` = Right wing + - `"C"` = Center + - `"D"` = Defenseman + - `"G"` = Goaltender + - `shootsCatches` (str): "L" or "R" + - `heightInInches` (int): Height in inches + - `weightInPounds` (int): Weight in pounds + - `heightInCentimeters` (int): Height in centimeters + - `weightInKilograms` (int): Weight in kilograms + - `birthDate` (str): Date of birth + - `birthCity.default` (str): Birth city + - `birthCountry` (str): Three-letter country code (e.g., "CAN", "USA", "SWE") + - `birthStateProvince.default` (str, optional): Birth state or province, not present for all players + +## Teams: List All NHL Franchises Including Historical + +Returns all NHL franchises, including historical and defunct teams. The current league has 32 active teams, but there are approximately 40 franchise records total. + +```python +from nhlpy import NHLClient + +client = NHLClient() +franchises = client.teams.franchises() +``` + +- **Parameters**: None +- **Returns**: list of dicts, one per franchise (approximately 40 entries) + - `id` (int): Franchise identifier, used as `franchise_id` in stats API filters + - `fullName` (str): Full franchise name (e.g., "Toronto Maple Leafs", "Montreal Wanderers") + - `teamCommonName` (str): Common name (e.g., "Maple Leafs", "Wanderers") + - `teamPlaceName` (str): Place name (e.g., "Toronto", "Montreal") diff --git a/llms.txt b/llms.txt new file mode 100644 index 0000000..095113a --- /dev/null +++ b/llms.txt @@ -0,0 +1,109 @@ +# nhl-api-py + +> Python wrapper for the NHL API. Access NHL data including stats, schedules, standings, teams, game center, player info, and EDGE tracking analytics. + +## Installation + +pip install nhl-api-py + +## Quick Start + +```python +from nhlpy import NHLClient + +client = NHLClient() +``` + +## Docs + +- [Game Center](docs/game_center.md): Boxscores, play-by-play, scores, shift charts, game stories +- [Schedule](docs/schedule.md): Daily/weekly/monthly/season schedules, playoffs +- [Stats](docs/stats.md): Player career stats, game logs, team/skater/goalie summaries with query builder +- [Teams](docs/teams.md): Team info, rosters, franchises +- [Standings](docs/standings.md): League standings, season metadata +- [Players](docs/players.md): Prospects, team rosters by season +- [EDGE](docs/edge.md): NHL EDGE tracking analytics — shot speed, skating speed, zone time, distance +- [Misc](docs/misc.md): Glossary, config, countries, draft info, season rules +- [Helpers](docs/helpers.md): Convenience methods — all game IDs, all players, bulk stats + +## Architecture + +NHLClient is the main entry point. Access modules via attributes: + +- `client.game_center` — Live game data, boxscores, play-by-play, scores +- `client.schedule` — Game schedules (daily/weekly/monthly/season/playoffs) +- `client.stats` — Player and team statistics with advanced query builder +- `client.teams` — Team info, rosters, franchises +- `client.standings` — League standings +- `client.players` — Player lookup by team, prospects +- `client.edge` — NHL EDGE tracking analytics (shot speed, skating speed, zone time) +- `client.misc` — Reference data (glossary, countries, draft info) +- `client.helpers` — Cross-domain convenience methods (all game IDs, all players) + +## Common Patterns + +- **Season format**: 8-digit string, start year + end year (e.g., `"20242025"`) +- **Team abbreviation**: 3-letter code (e.g., `"BUF"`, `"TOR"`, `"EDM"`) +- **Player ID**: Numeric string (e.g., `"8478402"` for Connor McDavid) +- **Game ID format**: `YYYYTTNNNN` — season start year + game type + game number (e.g., `2024020641`) +- **Game types**: `1` = Preseason, `2` = Regular Season, `3` = Playoffs +- **Date format**: `"YYYY-MM-DD"` (e.g., `"2025-01-07"`) +- **Localized names**: Many name fields use `{"default": "English name", "fr": "French name"}` format + +## Workflows + +### Get today's scores +```python +from nhlpy import NHLClient +client = NHLClient() +scores = client.game_center.daily_scores() +for game in scores["games"]: + away = game["awayTeam"] + home = game["homeTeam"] + print(f"{away['abbrev']} {away['score']} - {home['abbrev']} {home['score']}") +``` + +### Get a player's career stats +```python +from nhlpy import NHLClient +client = NHLClient() +stats = client.stats.player_career_stats(player_id="8478402") +career = stats["careerTotals"]["regularSeason"] +print(f"{stats['firstName']['default']} {stats['lastName']['default']}: {career['goals']}G {career['assists']}A {career['points']}P") +``` + +### Find a team's roster +```python +from nhlpy import NHLClient +client = NHLClient() +roster = client.teams.team_roster(team_abbr="EDM", season="20242025") +for player in roster["forwards"]: + print(f"#{player['sweaterNumber']} {player['firstName']['default']} {player['lastName']['default']}") +``` + +### Get league standings +```python +from nhlpy import NHLClient +client = NHLClient() +standings = client.standings.league_standings(season="20242025") +for team in standings["standings"][:5]: + print(f"{team['teamAbbrev']['default']}: {team['points']}pts ({team['wins']}W-{team['losses']}L-{team['otLosses']}OTL)") +``` + +### Query advanced skater stats +```python +from nhlpy import NHLClient +from nhlpy.api.query.builder import QueryBuilder +from nhlpy.api.query.filters.season import SeasonQuery +from nhlpy.api.query.filters.game_type import GameTypeQuery + +client = NHLClient() +filters = [ + SeasonQuery(season_start="20242025", season_end="20242025"), + GameTypeQuery(game_type="2"), +] +query = QueryBuilder.build(filters=filters) +stats = client.stats.skater_stats_with_query_context(query_context=query, report_type="summary") +for player in stats[:5]: + print(f"{player['skaterFullName']}: {player['points']}pts") +``` diff --git a/nhlpy/api/edge.py b/nhlpy/api/edge.py index 64322bd..577f747 100644 --- a/nhlpy/api/edge.py +++ b/nhlpy/api/edge.py @@ -27,6 +27,19 @@ def skater_detail(self, player_id: str, season: str = None, game_type: int = 2) Returns: dict: Dictionary containing detailed EDGE statistics for the skater + Key Response Fields: + player.firstName.default (str): Player first name + player.lastName.default (str): Player last name + player.goals (int): Total goals scored + player.points (int): Total points + topShotSpeed.imperial (float): Top shot speed in mph + skatingSpeed.speedMax.imperial (float): Maximum skating speed in mph + totalDistanceSkated.imperial (float): Total distance skated in miles + zoneTimeDetails.offensiveZonePctg (float): Offensive zone time percentage + + Response Docs: + docs/edge.md + Example: client.edge.skater_detail(player_id=8478402) client.edge.skater_detail(player_id=8478402, season=20232024, game_type=2) @@ -47,6 +60,14 @@ def skater_shot_speed_detail(self, player_id: str, season: str = None, game_type Returns: dict: Shot speed statistics including maximum and average speeds + + Key Response Fields: + shotSpeedData (list): Shot speed entries with percentiles + topShotSpeed.imperial (float): Top shot speed in mph + averageShotSpeed.imperial (float): Average shot speed in mph + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-shot-speed-detail/{player_id}/now" @@ -64,6 +85,14 @@ def skater_skating_speed_detail(self, player_id: str, season: str = None, game_t Returns: dict: Skating speed statistics including burst speed and average speed + + Key Response Fields: + skatingSpeedData (list): Skating speed entries with burst counts + speedMax.imperial (float): Maximum skating speed in mph + burstCount (int): Number of speed bursts + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-skating-speed-detail/{player_id}/now" @@ -81,6 +110,14 @@ def skater_shot_location_detail(self, player_id: str, season: str = None, game_t Returns: dict: Shot location data including shooting patterns and heat maps + + Key Response Fields: + shotLocations (list): Shot data grouped by area + area (str): Ice zone identifier + shotCount (int): Number of shots from each area + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-shot-location-detail/{player_id}/now" @@ -98,6 +135,14 @@ def skater_skating_distance_detail(self, player_id: str, season: str = None, gam Returns: dict: Distance traveled statistics per game and per shift + + Key Response Fields: + distanceData (list): Distance entries per game + totalDistance.imperial (float): Total distance skated in miles + gameMax.imperial (float): Maximum distance skated in a single game in miles + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-skating-distance-detail/{player_id}/now" @@ -115,6 +160,14 @@ def skater_comparison(self, player_id: str, season: str = None, game_type: int = Returns: dict: Comparison data relative to league averages + + Key Response Fields: + comparisonData (list): Comparison metrics vs league + leagueAverage (float): League average value for each metric + playerValue (float): Player value for each metric + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-comparison/{player_id}/now" @@ -132,6 +185,14 @@ def skater_zone_time(self, player_id: str, season: str = None, game_type: int = Returns: dict: Time spent in offensive, defensive, and neutral zones + + Key Response Fields: + offensiveZonePctg (float): Offensive zone time percentage + defensiveZonePctg (float): Defensive zone time percentage + neutralZonePctg (float): Neutral zone time percentage + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/skater-zone-time/{player_id}/now" @@ -150,6 +211,14 @@ def skater_landing(self, season: str = None, game_type: int = 2) -> Dict[str, An Returns: dict: Overview of league-wide skater EDGE statistics + + Key Response Fields: + leaders.hardestShot (list): League leaders for hardest shot + leaders.maxSkatingSpeed (list): League leaders for max skating speed + leaders.totalDistanceSkated (list): League leaders for total distance skated + + Response Docs: + docs/edge.md """ if season is None: resource = "edge/skater-landing/now" @@ -167,6 +236,14 @@ def cat_skater_detail(self, player_id: str, season: str = None, game_type: int = Returns: dict: CAT EDGE statistics for the skater + + Key Response Fields: + player (dict): Compact player summary with EDGE highlights + shotSpeed (dict): Condensed shot speed data + skatingSpeed (dict): Condensed skating speed data + + Response Docs: + docs/edge.md """ if season is None: resource = f"cat/edge/skater-detail/{player_id}/now" @@ -194,6 +271,16 @@ def goalie_detail(self, player_id: str, season: str = None, game_type: int = 2) Returns: dict: Dictionary containing detailed EDGE statistics for the goalie + Key Response Fields: + player.wins (int): Total wins + player.savePctg (float): Overall save percentage + stats.goalsAgainstAvg.value (float): Goals against average + stats.gamesAbove900.value (float): Games with save pct above .900 + shotLocationSummary (list): Save data grouped by shot area + + Response Docs: + docs/edge.md + Example: client.edge.goalie_detail(player_id=8476945) client.edge.goalie_detail(player_id=8476945, season=20232024, game_type=2) @@ -214,6 +301,14 @@ def goalie_shot_location_detail(self, player_id: str, season: str = None, game_t Returns: dict: Shot location data faced by the goalie including save percentages by zone + + Key Response Fields: + shotLocations (list): Save data grouped by shot location + area (str): Ice zone identifier + savePctg (float): Save percentage for each area + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/goalie-shot-location-detail/{player_id}/now" @@ -231,6 +326,14 @@ def goalie_5v5_detail(self, player_id: str, season: str = None, game_type: int = Returns: dict: 5-on-5 performance statistics and save percentages + + Key Response Fields: + fiveOnFiveStats (dict): 5-on-5 performance metrics + savePctg5v5 (float): Save percentage at 5-on-5 + goalsAgainstAvg5v5 (float): Goals against average at 5-on-5 + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/goalie-5v5-detail/{player_id}/now" @@ -248,6 +351,14 @@ def goalie_comparison(self, player_id: str, season: str = None, game_type: int = Returns: dict: Comparison data relative to league averages + + Key Response Fields: + comparisonData (list): Comparison metrics vs league + leagueAverage (float): League average value for each metric + playerValue (float): Player value for each metric + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/goalie-comparison/{player_id}/now" @@ -265,6 +376,14 @@ def goalie_save_percentage_detail(self, player_id: str, season: str = None, game Returns: dict: Detailed save percentage breakdowns by situation and location + + Key Response Fields: + savePctgBreakdown (list): Save percentage by situation type + overallSavePctg (float): Overall save percentage + highDangerSavePctg (float): Save percentage on high-danger chances + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/goalie-save-percentage-detail/{player_id}/now" @@ -283,6 +402,14 @@ def goalie_landing(self, season: str = None, game_type: int = 2) -> Dict[str, An Returns: dict: Overview of league-wide goalie EDGE statistics + + Key Response Fields: + leaders (dict): League leaders for goalie EDGE stats + topSavePctg (list): Leaders by save percentage + topGamesAbove900 (list): Leaders by games above .900 + + Response Docs: + docs/edge.md """ if season is None: resource = "edge/goalie-landing/now" @@ -300,6 +427,14 @@ def cat_goalie_detail(self, player_id: str, season: str = None, game_type: int = Returns: dict: CAT EDGE statistics for the goalie + + Key Response Fields: + player (dict): Compact goalie summary with EDGE highlights + savePctg (float): Condensed save percentage data + goalsAgainstAvg (float): Condensed goals against average + + Response Docs: + docs/edge.md """ if season is None: resource = f"cat/edge/goalie-detail/{player_id}/now" @@ -327,6 +462,18 @@ def team_detail(self, team_id: str, season: str = None, game_type: int = 2) -> D Returns: dict: Dictionary containing detailed EDGE statistics for the team + Key Response Fields: + team.abbrev (str): Team abbreviation + team.wins (int): Total wins + team.points (int): Total points + shotSpeed.topShotSpeed.imperial (float): Top shot speed in mph + skatingSpeed.speedMax.imperial (float): Maximum skating speed in mph + distanceSkated.total.imperial (float): Total distance skated in miles + zoneTimeDetails.offensiveZonePctg (float): Offensive zone time percentage + + Response Docs: + docs/edge.md + Example: client.edge.team_detail(team_id=10) client.edge.team_detail(team_id=10, season=20232024, game_type=2) @@ -347,6 +494,14 @@ def team_skating_distance_detail(self, team_id: str, season: str = None, game_ty Returns: dict: Team skating distance statistics per game and per player + + Key Response Fields: + distanceData (list): Distance entries per game and per player + totalDistance.imperial (float): Total team distance skated in miles + perGameAvg.imperial (float): Average distance per game in miles + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/team-skating-distance-detail/{team_id}/now" @@ -364,6 +519,14 @@ def team_zone_time_details(self, team_id: str, season: str = None, game_type: in Returns: dict: Team time spent in offensive, defensive, and neutral zones + + Key Response Fields: + offensiveZonePctg (float): Offensive zone time percentage + defensiveZonePctg (float): Defensive zone time percentage + neutralZonePctg (float): Neutral zone time percentage + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/team-zone-time-details/{team_id}/now" @@ -381,6 +544,14 @@ def team_shot_location_detail(self, team_id: str, season: str = None, game_type: Returns: dict: Team shot location data including shooting patterns and heat maps + + Key Response Fields: + shotLocations (list): Shot data grouped by area + area (str): Ice zone identifier + shotCount (int): Number of shots from each area + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/team-shot-location-detail/{team_id}/now" @@ -399,6 +570,14 @@ def team_landing(self, season: str = None, game_type: int = 2) -> Dict[str, Any] Returns: dict: Overview of league-wide team EDGE statistics + + Key Response Fields: + leaders (dict): Team EDGE leaders across categories + topShotSpeed (list): Leaders by team shot speed + topSkatingSpeed (list): Leaders by team skating speed + + Response Docs: + docs/edge.md """ if season is None: resource = "edge/team-landing/now" @@ -416,6 +595,14 @@ def team_shot_speed_detail(self, team_id: str, season: str = None, game_type: in Returns: dict: Team shot speed statistics including maximum and average speeds + + Key Response Fields: + shotSpeedData (list): Shot speed entries by player + topShotSpeed.imperial (float): Top team shot speed in mph + averageShotSpeed.imperial (float): Average team shot speed in mph + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/team-shot-speed-detail/{team_id}/now" @@ -433,6 +620,14 @@ def team_skating_speed_detail(self, team_id: str, season: str = None, game_type: Returns: dict: Team skating speed statistics including burst speed and average speed + + Key Response Fields: + skatingSpeedData (list): Skating speed entries by player + speedMax.imperial (float): Maximum team skating speed in mph + averageSpeed.imperial (float): Average team skating speed in mph + + Response Docs: + docs/edge.md """ if season is None: resource = f"edge/team-skating-speed-detail/{team_id}/now" diff --git a/nhlpy/api/game_center.py b/nhlpy/api/game_center.py index 46b566c..231c326 100644 --- a/nhlpy/api/game_center.py +++ b/nhlpy/api/game_center.py @@ -7,64 +7,148 @@ def __init__(self, http_client: HttpClient): self.client = http_client def boxscore(self, game_id: str) -> dict: - """Get boxscore data for a specific NHL game. GameIds can be retrieved from the schedule endpoint. + """Get the full boxscore for a specific NHL game, including team scores, shots on goal, + and per-player stats broken down by position. Game IDs can be retrieved from the schedule endpoint. Args: - game_id (str): The game_id for the game you want the boxscore for + game_id (str): The unique game identifier (e.g. "2023020280"). + + Key Response Fields: + gameState (str): Current state of the game ("FUT", "LIVE", "OFF", "FINAL"). + awayTeam.abbrev (str): Away team abbreviation (e.g. "TOR"). + awayTeam.score (int): Away team total goals. + homeTeam.abbrev (str): Home team abbreviation (e.g. "BOS"). + homeTeam.score (int): Home team total goals. + awayTeam.sog (int): Away team shots on goal. + homeTeam.sog (int): Home team shots on goal. + playerByGameStats.awayTeam.forwards (list): Per-player stats for away forwards. + gameOutcome.lastPeriodType (str): Period type the game ended in ("REG", "OT", "SO"). + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. Example: - API endpoint format: https://api-web.nhle.com/v1/gamecenter/2023020280/boxscore + client.game_center.boxscore(game_id="2023020280") Returns: - dict: Game boxscore data + dict: Full boxscore data including team totals and player-level game stats. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"gamecenter/{game_id}/boxscore").json() def play_by_play(self, game_id: str) -> dict: - """Get play-by-play data for a specific NHL game. GameIds can be retrieved from the schedule endpoint. + """Get the full play-by-play feed for a specific NHL game, containing every recorded event + such as shots, goals, faceoffs, hits, and penalties. Game IDs can be retrieved from the + schedule endpoint. Args: - game_id (str): The game_id for the game you want the play by play for + game_id (str): The unique game identifier (e.g. "2023020280"). + + Key Response Fields: + plays (list): All game events (~340 per game), ordered chronologically. + plays[].typeDescKey (str): Event type descriptor (e.g. "shot-on-goal", "goal", "faceoff"). + plays[].timeInPeriod (str): Time elapsed in the period (e.g. "12:34"). + plays[].periodDescriptor.number (int): Period number (1, 2, 3, 4 for OT). + plays[].details.xCoord (float): Ice x-coordinate of the event. + plays[].details.yCoord (float): Ice y-coordinate of the event. + rosterSpots (list): Player info for all rostered players in the game. + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.play_by_play(game_id="2023020280") Returns: - dict: Play-by-play game data + dict: Complete play-by-play data including all events and roster information. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"gamecenter/{game_id}/play-by-play").json() def match_up(self, game_id: str) -> dict: - """Get detailed match up information for a specific NHL game. GameIds can be retrieved - from the schedule endpoint. + """Get the landing-page summary for a specific NHL game, including scoring by period, + three-stars selections, and penalty details. Game IDs can be retrieved from the + schedule endpoint. Args: - game_id (str): The game_id for the game you want the landing page for + game_id (str): The unique game identifier (e.g. "2023020280"). + + Key Response Fields: + summary.scoring (list): Goals broken down by period. + summary.threeStars (list): Three stars of the game, each containing: + star (int), playerId (int), teamAbbrev (str), name (str), position (str). + summary.penalties (list): All penalties assessed during the game. + summary.teamGameStats (list): Head-to-head team stats (SOG, faceoff %, PIM, etc.). + awayTeam.abbrev (str): Away team abbreviation. + homeTeam.abbrev (str): Home team abbreviation. + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.match_up(game_id="2023020280") Returns: - dict: Detailed game matchup data + dict: Detailed game matchup data including scoring summary, three stars, and penalties. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"gamecenter/{game_id}/landing").json() def daily_scores(self, date: Optional[str] = None) -> dict: - """Get scores for NHL games on a specific date or current day. + """Get scores and game states for all NHL games on a given date. Returns the current + day's scoreboard when no date is provided, along with navigation links to adjacent dates. Args: - date (str, optional): Date to check scores in YYYY-MM-DD format. - If not provided, returns current day's scores. + date (str, optional): Date in YYYY-MM-DD format (e.g. "2024-01-15"). + If not provided, returns the current day's scores. + + Key Response Fields: + currentDate (str): The date for the returned scores (YYYY-MM-DD). + prevDate (str): Previous date with NHL games, for pagination. + nextDate (str): Next date with NHL games, for pagination. + games (list): All games on the requested date. + games[].awayTeam.abbrev (str): Away team abbreviation (e.g. "NYR"). + games[].awayTeam.score (int): Away team score. + games[].homeTeam.abbrev (str): Home team abbreviation (e.g. "PIT"). + games[].homeTeam.score (int): Home team score. + games[].gameState (str): Game state ("FUT", "LIVE", "OFF", "FINAL"). + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.daily_scores(date="2024-01-15") Returns: - dict: Game scores and status information + dict: Scoreboard data with all games, scores, statuses, and date navigation. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"score/{date if date else 'now'}").json() def shift_chart_data(self, game_id: str, excludes: List[str] = None) -> dict: - """Gets shift chart data for a specific game. + """Get individual player shift data for a specific game, including start/end times and + durations for every shift. A typical game contains ~740 shift records across both teams. Args: - game_id (str): ID of the game to retrieve shift data for. Game IDs can be retrieved - from the schedule endpoint. - excludes (List[str]): List of items to exclude from the response. + game_id (str): The unique game identifier (e.g. "2023020280"). Game IDs can be + retrieved from the schedule endpoint. + excludes (List[str], optional): Fields to exclude from the response. + Defaults to ["eventDetails"] if not provided. + + Key Response Fields: + data (list): All shift records (~740 per game). + data[].firstName (str): Player's first name. + data[].lastName (str): Player's last name. + data[].teamAbbrev (str): Team abbreviation for the player. + data[].period (int): Period number the shift occurred in. + data[].startTime (str): Shift start time within the period (e.g. "05:23"). + data[].duration (str): Length of the shift (e.g. "00:45"). + total (int): Total number of shift records returned. + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.shift_chart_data(game_id="2023020280") Returns: - Dict containing the shift chart data. + dict: Shift chart data containing individual shift records for all players. """ if excludes is None: excludes = ["eventDetails"] @@ -76,25 +160,55 @@ def shift_chart_data(self, game_id: str, excludes: List[str] = None) -> dict: ).json() def season_series_matchup(self, game_id: str) -> dict: - """Gets game stats and season series information for a specific game. + """Get the season-series record and contextual stats for a specific game, including + head-to-head win totals, team game stats, and linescore data from the right-rail panel. Args: - game_id (str): ID of the game to retrieve stats for. Game IDs can be retrieved - from the schedule endpoint. + game_id (str): The unique game identifier (e.g. "2023020280"). Game IDs can be + retrieved from the schedule endpoint. + + Key Response Fields: + seasonSeries (list): Results of all regular-season matchups between the two teams. + seasonSeriesWins (object): Win counts keyed by team ID. + teamGameStats (list): Comparative team stats for this game (SOG, faceoff %, etc.). + linescore (object): Period-by-period scoring breakdown. + gameReports (object): Links to official game reports (e.g. summary, event summary). + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.season_series_matchup(game_id="2023020280") Returns: - Dict containing game stats and season series data. + dict: Season series record, team game stats, linescore, and game report links. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"gamecenter/{game_id}/right-rail").json() def game_story(self, game_id: str) -> dict: - """Gets game story information for a specific game. + """Get the narrative game story for a specific game, including scoring summaries, + three-stars selections, and head-to-head team statistics. This is the data behind + the NHL's post-game recap page. Args: - game_id (str): ID of the game to retrieve story for. Game IDs can be retrieved - from the schedule endpoint. + game_id (str): The unique game identifier (e.g. "2023020280"). Game IDs can be + retrieved from the schedule endpoint. + + Key Response Fields: + summary.scoring (list): Goals organized by period, with scorer and assist details. + summary.threeStars (list): Three stars of the game with player info. + summary.teamGameStats (list): Comparative team stats (SOG, faceoff %, PIM, hits, etc.). + awayTeam.abbrev (str): Away team abbreviation. + homeTeam.abbrev (str): Home team abbreviation. + gameState (str): Current state of the game ("FUT", "LIVE", "OFF", "FINAL"). + + Response Docs: + See ``docs/game_center.md`` for the complete response schema. + + Example: + client.game_center.game_story(game_id="2023020280") Returns: - Dict containing game story data. + dict: Game story data with scoring summary, three stars, and team stat comparisons. """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"wsc/game-story/{game_id}").json() diff --git a/nhlpy/api/helpers.py b/nhlpy/api/helpers.py index 9c268bb..efa70c0 100644 --- a/nhlpy/api/helpers.py +++ b/nhlpy/api/helpers.py @@ -21,18 +21,31 @@ def _clean_name(self, ntype, name): return name[ntype]["default"] def game_ids_by_season(self, season: str, game_types: List[int] = None, api_sleep_rate: float = 1) -> List[str]: - """Gets all game IDs for a specified season. + """Gets all game IDs for a specified season by querying every team's schedule. + + Iterates over all 32 NHL teams and collects game IDs from each team's + season schedule. Expect roughly 2,600 IDs for a full regular season + and approximately 32 API calls (one per team). Args: - season (str): Season to retrieve game IDs for in YYYYYYYY format (e.g., 20232024). - game_types (List[int]): List of game types to include. Valid types: - 1: Preseason - 2: Regular season - 3: Playoffs - api_sleep_rate (float): Sleep rate in seconds between API calls to avoid hitting rate limits. + season (str): Season in YYYYYYYY format (e.g., "20232024"). + game_types (List[int], optional): Game types to include. Valid values: + + - ``1`` -- Preseason + - ``2`` -- Regular season + - ``3`` -- Playoffs + + Defaults to ``None`` (all game types). + api_sleep_rate (float): Seconds to sleep between API calls to + avoid rate limiting. Defaults to ``1``. Returns: - List of game IDs for the specified season and game types. + List[str]: Game IDs matching the requested season and game types. + + Note: + This method makes one API call per team (~32 calls) and respects + ``api_sleep_rate`` between each call. Total runtime depends on the + sleep rate chosen. """ from nhlpy.api.teams import Teams from nhlpy.api.schedule import Schedule @@ -60,13 +73,30 @@ def game_ids_by_season(self, season: str, game_types: List[int] = None, api_slee return game_ids def all_players(self, season: str, api_sleep_rate: float = 0.5) -> List[dict[str, Any]]: - """Gets all player base stats. + """Gets every rostered player across all 32 NHL teams for a given season. + + Iterates over every team roster and returns a flat list of player + dicts with cleaned name fields and an added ``team`` key. Makes + approximately 32 API calls (one per team). Args: - api_sleep_rate (float): Sleep rate in seconds between API calls to avoid hitting rate limits. + season (str): Season in YYYYYYYY format (e.g., "20232024"). + api_sleep_rate (float): Seconds to sleep between API calls to + avoid rate limiting. Defaults to ``0.5``. Returns: - List of player base stats. + List[dict[str, Any]]: List of player dicts. Key fields include: + + - ``id`` (int): Player ID. + - ``firstName`` (str): Cleaned first name (``default`` value). + - ``lastName`` (str): Cleaned last name (``default`` value). + - ``sweaterNumber`` (int): Jersey number. + - ``positionCode`` (str): Position code (e.g., "C", "D", "G"). + - ``team`` (str): Team abbreviation added by this method. + + Note: + This method makes one API call per team (~32 calls) and respects + ``api_sleep_rate`` between each call. """ from nhlpy.api.teams import Teams @@ -90,7 +120,28 @@ def all_players(self, season: str, api_sleep_rate: float = 0.5) -> List[dict[str return out_data def all_players_summary_statistics(self, season: str, api_sleep_rate: float = 1): - """Gets all player summary statistics for a specified season.""" + """Gets summary statistics for every skater in a given season. + + Combines roster data from ``all_players()`` with per-team summary + stats fetched through the query builder, then merges the two datasets + on player ID. Makes multiple paginated API calls (one roster call + per team plus one stats call per team franchise). + + Args: + season (str): Season in YYYYYYYY format (e.g., "20232024"). + api_sleep_rate (float): Seconds to sleep between API calls to + avoid rate limiting. Defaults to ``1``. + + Returns: + list[dict]: Merged player and summary-stats dicts. Each entry + contains the roster fields from ``all_players()`` plus stats + fields such as ``goals``, ``assists``, ``points``, + ``gamesPlayed``, and other summary report columns. + + Warning: + This method is slow and makes a large number of API calls. + Increase ``api_sleep_rate`` if you encounter rate limiting. + """ logging.warning( "This method will take a while to run. In the event of rate limiting, you may need to increase the api_sleep_rate." ) diff --git a/nhlpy/api/misc.py b/nhlpy/api/misc.py index aaee0ca..6788dec 100644 --- a/nhlpy/api/misc.py +++ b/nhlpy/api/misc.py @@ -8,45 +8,101 @@ def __init__(self, http_client: HttpClient) -> None: self.client = http_client def glossary(self) -> List[dict]: - """Get the glossary for the NHL API. + """Gets the full NHL glossary of statistical terms and abbreviations. + + Returns a list of approximately 321 glossary entries that define every + abbreviation and term used across the NHL stats API. Returns: - dict: NHL API glossary data + List[dict]: List of glossary entries. Each dict contains: + + - ``id`` (int): Unique glossary entry identifier. + - ``abbreviation`` (str): Short-form abbreviation (e.g., "GP", "SOG"). + - ``definition`` (str): Human-readable definition of the term. + - ``fullName`` (str): Full name of the term. + + See Also: + https://api.nhle.com/stats/rest/en/glossary """ response = self.client.get(endpoint=Endpoint.API_CORE, resource="stats/rest/en/glossary?sort=fullName").json() return response.get("data", []) def config(self) -> dict: - """Get available filter options. + """Gets the stats API configuration, including available report types and filters. + + Returns a dictionary describing the report types available for players, + goalies, and teams, along with their supported filter options. Returns: - dict: Dictionary of filter options + dict: Configuration data with the following top-level keys: + + - ``playerReportData`` (dict): Report type names as keys, + each mapping to supported filters and sort options. + - ``goalieReportData`` (dict): Same structure for goalie reports. + - ``teamReportData`` (dict): Same structure for team reports. + + See Also: + https://api.nhle.com/stats/rest/en/config """ return self.client.get(endpoint=Endpoint.API_CORE, resource="stats/rest/en/config").json() def countries(self) -> List[dict]: - """Get list of countries from NHL API. + """Gets the list of countries recognized by the NHL. + + Returns approximately 49 countries that have had players in the NHL, + including both full names and ISO-style codes. Returns: - dict: Dictionary of country data + List[dict]: List of country entries. Each dict contains: + + - ``id`` (str): Three-letter country code (e.g., "CAN", "USA"). + - ``countryName`` (str): Full country name (e.g., "Canada"). + - ``nationalityName`` (str): Nationality label (e.g., "Canadian"). + - ``countryCode`` (str): Two-letter country code (e.g., "CA", "US"). + + See Also: + https://api.nhle.com/stats/rest/en/country """ response = self.client.get(endpoint=Endpoint.API_CORE, resource="stats/rest/en/country").json() return response.get("data", []) def season_specific_rules_and_info(self) -> List[dict]: - """Get NHL season rules and information. + """Gets rules and metadata for every NHL season on record. + + Returns a list of approximately 108 seasons, each describing the + number of games, conference/division usage, and other rule variations + for that particular season. Returns: - dict: Dictionary containing season-specific rules and information + List[dict]: List of season entries. Each dict contains: + + - ``id`` (int): Season identifier (e.g., 20232024). + - ``formattedSeasonId`` (str): Human-readable season label + (e.g., "2023-24"). + - ``numberOfGames`` (int): Number of regular-season games. + - ``conferencesInUse`` (int): Whether conferences were active. + + See Also: + https://api.nhle.com/stats/rest/en/season """ response = self.client.get(endpoint=Endpoint.API_CORE, resource="stats/rest/en/season").json() return response.get("data", []) def draft_year_and_rounds(self) -> List[dict]: - """Get NHL draft year and round information. + """Gets the number of rounds for each NHL draft year. + + Returns a list of approximately 63 entries covering every draft year + on record, useful for validating draft round filters in queries. Returns: - dict: Draft data containing 'id', 'draftYear', and 'rounds count' + List[dict]: List of draft year entries. Each dict contains: + + - ``id`` (int): Unique identifier for the draft year record. + - ``draftYear`` (int): The calendar year of the draft (e.g., 2023). + - ``rounds`` (int): Number of rounds held in that draft. + + See Also: + https://api.nhle.com/stats/rest/en/draft """ response = self.client.get(endpoint=Endpoint.API_CORE, resource="stats/rest/en/draft").json() return response.get("data", []) diff --git a/nhlpy/api/players.py b/nhlpy/api/players.py index 9993250..d4a3de7 100644 --- a/nhlpy/api/players.py +++ b/nhlpy/api/players.py @@ -8,28 +8,61 @@ def __init__(self, http_client: HttpClient): self.client = http_client def prospects_by_team(self, team_abbr: str) -> dict: - """Gets prospects for a specific team. + """Gets prospects for a specific team, grouped by position. + + Retrieves the current prospect pool for a given NHL team, returning + players organized into positional groups. Args: - team_abbr (str): Team abbreviation (e.g., BUF, TOR) + team_abbr (str): Team abbreviation (e.g., "BUF", "TOR"). Returns: - dict: Prospects data for the specified team. + dict: Prospect data grouped by position with the following structure: + + - ``forwards`` (list[dict]): Forward prospects. + - ``defensemen`` (list[dict]): Defenseman prospects. + - ``goalies`` (list[dict]): Goalie prospects. + + Each player dict contains: + + - ``id`` (int): Player ID. + - ``firstName`` (dict): ``{"default": "..."}`` first name. + - ``lastName`` (dict): ``{"default": "..."}`` last name. + - ``positionCode`` (str): Position code (e.g., "C", "L", "R", "D", "G"). + - ``birthDate`` (str): Date of birth in YYYY-MM-DD format. + - ``birthCountry`` (str): Three-letter country code. + + See Also: + https://api-web.nhle.com/v1/prospects/{team_abbr} """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"prospects/{team_abbr}").json() def players_by_team(self, team_abbr: str, season: str) -> Dict[str, Any]: - """Get the roster/players for the given team and season. This is the same as teams.roster_by_team(), - but it's a separate endpoint to avoid confusion. + """Gets the roster for a given team and season, grouped by position. - This method provides the same functionality as teams.roster_by_team(), - offering a convenient way to access team rosters through the Players API. + Provides the same data as ``teams.team_roster()``, exposed through the + Players API for convenience. Args: - team_abbr (str): Team abbreviation (e.g., BUF, TOR) - season (str): Season in format YYYYYYYY (e.g., 20202021, 20212022) + team_abbr (str): Team abbreviation (e.g., "BUF", "TOR"). + season (str): Season in YYYYYYYY format (e.g., "20232024"). Returns: - Dict[str, Any]: Dictionary containing roster information for the specified team and season. + Dict[str, Any]: Roster data grouped by position with the following structure: + + - ``forwards`` (list[dict]): Forward players. + - ``defensemen`` (list[dict]): Defenseman players. + - ``goalies`` (list[dict]): Goalie players. + + Each player dict contains: + + - ``id`` (int): Player ID. + - ``firstName`` (dict): ``{"default": "..."}`` first name. + - ``lastName`` (dict): ``{"default": "..."}`` last name. + - ``sweaterNumber`` (int): Jersey number. + - ``positionCode`` (str): Position code (e.g., "C", "L", "R", "D", "G"). + + See Also: + https://api-web.nhle.com/v1/roster/{team_abbr}/{season} """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"roster/{team_abbr}/{season}").json() diff --git a/nhlpy/api/schedule.py b/nhlpy/api/schedule.py index 0770d62..15b0fcc 100644 --- a/nhlpy/api/schedule.py +++ b/nhlpy/api/schedule.py @@ -11,11 +11,33 @@ def __init__(self, http_client: HttpClient) -> None: def daily_schedule(self, date: Optional[str] = None) -> dict: """Gets NHL schedule for a specific date. + This method transforms the raw API response by extracting only the + matching day from the ``gameWeek`` list and flattening it into a + single-date payload. + Args: - date (str): Date in YYYY-MM-DD format. + date (str): Date in YYYY-MM-DD format. Defaults to today's date. Returns: - dict: Game schedule data for the specified date. + dict: Transformed schedule data for the specified date. + + Key Response Fields: + nextStartDate (str): Next date with scheduled games. + previousStartDate (str): Previous date with scheduled games. + date (str): The requested date. + games (list): List of game objects for the date. + games[].id (int): Unique game identifier. + games[].awayTeam.abbrev (str): Away team abbreviation. + games[].homeTeam.abbrev (str): Home team abbreviation. + games[].gameState (str): Game state code (e.g., ``"FUT"``, + ``"LIVE"``, ``"OFF"``). + numberOfGames (int): Total number of games on the date. + + Response Docs: + https://api-web.nhle.com/v1/schedule/{date} + + Example: + client.schedule.daily_schedule(date="2024-02-10") """ try: if not date: @@ -48,100 +70,206 @@ def weekly_schedule(self, date: Optional[str] = None) -> dict: """Gets NHL schedule for a week starting from the specified date. Args: - date (str, optional): Date in YYYY-MM-DD format. Defaults to today's date. - Note: NHL's "today" typically shifts around 12:00 EST. + date (str, optional): Date in YYYY-MM-DD format. Defaults to today's + date. Note: NHL's "today" typically shifts around 12:00 EST. Returns: dict: Weekly game schedule data. + + Key Response Fields: + nextStartDate (str): Start date of the following week. + previousStartDate (str): Start date of the preceding week. + gameWeek (list): List of 7 day objects spanning the week. + gameWeek[].date (str): Date string for the day (``YYYY-MM-DD``). + gameWeek[].games (list): List of game objects for that day. + numberOfGames (int): Total number of games across the week. + + Response Docs: + https://api-web.nhle.com/v1/schedule/{date} + + Example: + client.schedule.weekly_schedule(date="2024-02-10") """ res = date if date else "now" return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"schedule/{res}").json() def team_monthly_schedule(self, team_abbr: str, month: Optional[str] = None) -> List[dict]: - """Gets monthly schedule for specified team or the given month. If no month is supplied it will default to now. + """Gets monthly schedule for a specified team. + + If no month is supplied it defaults to the current month. Args: - team_abbr (str): Three-letter team abbreviation (e.g., BUF, TOR) - month (str, optional): Month in YYYY-MM format (e.g., 2021-10). Defaults to current month. + team_abbr (str): Three-letter team abbreviation (e.g., ``"BUF"``, + ``"TOR"``). + month (str, optional): Month in ``YYYY-MM`` format (e.g., + ``"2021-10"``). Defaults to current month. Returns: - List[dict]: List of games in the monthly schedule. + List[dict]: List of game dicts for the monthly schedule. + + Key Response Fields (per game dict): + id (int): Unique game identifier. + gameDate (str): Date of the game. + awayTeam.abbrev (str): Away team abbreviation. + homeTeam.abbrev (str): Home team abbreviation. + gameState (str): Game state code (e.g., ``"FUT"``, ``"OFF"``). + winningGoalie (dict or None): Winning goalie info, if applicable. + + Response Docs: + https://api-web.nhle.com/v1/club-schedule/{team}/month/{month} + + Example: + client.schedule.team_monthly_schedule(team_abbr="TOR", month="2024-01") """ resource = f"club-schedule/{team_abbr}/month/{month if month else 'now'}" response = self.client.get(endpoint=Endpoint.API_WEB_V1, resource=resource).json() return response.get("games", []) def team_weekly_schedule(self, team_abbr: str, date: Optional[str] = None) -> List[dict]: - """Gets weekly schedule for specified team. If no date is supplied it will default to current week. + """Gets weekly schedule for a specified team. + + If no date is supplied it defaults to the current week. Args: - team_abbr (str): Three-letter team abbreviation (e.g., BUF, TOR) - date (str, optional): Date in YYYY-MM-DD format. Gets schedule for week containing this date. - Defaults to current week. + team_abbr (str): Three-letter team abbreviation (e.g., ``"BUF"``, + ``"TOR"``). + date (str, optional): Date in ``YYYY-MM-DD`` format. Returns + the schedule for the week containing this date. Defaults to + current week. Returns: - List[dict]: List of games in the weekly schedule. + List[dict]: List of game dicts for the weekly schedule. + + Key Response Fields (per game dict): + id (int): Unique game identifier. + gameDate (str): Date of the game. + awayTeam.abbrev (str): Away team abbreviation. + homeTeam.abbrev (str): Home team abbreviation. + gameState (str): Game state code (e.g., ``"FUT"``, ``"OFF"``). + winningGoalie (dict or None): Winning goalie info, if applicable. + + Response Docs: + https://api-web.nhle.com/v1/club-schedule/{team}/week/{date} + + Example: + client.schedule.team_weekly_schedule(team_abbr="BUF", date="2024-02-10") """ resource = f"club-schedule/{team_abbr}/week/{date if date else 'now'}" response = self.client.get(endpoint=Endpoint.API_WEB_V1, resource=resource).json() return response.get("games", []) def team_season_schedule(self, team_abbr: str, season: str) -> dict: - """Gets full season schedule for specified team. + """Gets the full season schedule for a specified team. Args: - team_abbr (str): Three-letter team abbreviation (e.g., BUF, TOR) - season (str): Season in YYYYYYYY format (e.g., 20232024) + team_abbr (str): Three-letter team abbreviation (e.g., ``"BUF"``, + ``"TOR"``). + season (str): Season in ``YYYYYYYY`` format (e.g., ``"20232024"``). Returns: dict: Complete season schedule data including metadata. + + Key Response Fields: + previousSeason (int): Previous season identifier. + currentSeason (int): Current season identifier. + nextSeason (int): Next season identifier. + clubTimezone (str): Team's local timezone (e.g., + ``"America/New_York"``). + games (list): List of game dicts for the entire season. + + Response Docs: + https://api-web.nhle.com/v1/club-schedule-season/{team}/{season} + + Example: + client.schedule.team_season_schedule(team_abbr="TOR", season="20232024") """ request = self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"club-schedule-season/{team_abbr}/{season}") return request.json() def calendar_schedule(self, date: str) -> dict: - """Gets schedule in calendar format for specified date. Im not really sure - how this is diff from the other endppoints. + """Gets the schedule in calendar format for a specified date. + + Returns a high-level calendar view of the schedule, including a list + of all 32 teams and their metadata. - Args: - date (str): Date in YYYY-MM-DD format (e.g., 2023-11-23) + Args: + date (str): Date in ``YYYY-MM-DD`` format (e.g., ``"2023-11-23"``). - Returns: - dict: Calendar-formatted schedule data. + Returns: + dict: Calendar-formatted schedule data. - Example: - API endpoint: https://api-web.nhle.com/v1/schedule-calendar/2023-11-08 + Key Response Fields: + startDate (str): Start date of the calendar window. + endDate (str): End date of the calendar window. + teams (list): List of all 32 NHL teams. + teams[].abbrev (str): Team abbreviation. + teams[].commonName.default (str): Common team name. + + Response Docs: + https://api-web.nhle.com/v1/schedule-calendar/{date} + + Example: + client.schedule.calendar_schedule(date="2023-11-08") """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"schedule-calendar/{date}").json() def playoff_carousel(self, season: str) -> dict: - """Gets list of all series games up to current playoff round. + """Gets all playoff series information up to the current round. Args: - season (str): Season in YYYYYYYY format (e.g., "20232024") + season (str): Season in ``YYYYYYYY`` format (e.g., ``"20232024"``). Returns: - dict: Playoff series data for the specified season. + dict: Playoff series data for the specified season. + + Key Response Fields: + seasonId (int): Season identifier. + currentRound (int): The current active playoff round number. + rounds (list): List of round objects. + rounds[].series (list): List of series within each round. + + Response Docs: + https://api-web.nhle.com/v1/playoff-series/carousel/{season} Example: - API endpoint: https://api-web.nhle.com/v1/playoff-series/carousel/20232024/ + client.schedule.playoff_carousel(season="20232024") """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"playoff-series/carousel/{season}").json() def playoff_series_schedule(self, season: str, series: str) -> dict: - """Returns the schedule for a specified playoff series. + """Returns the schedule and results for a specified playoff series matchup. Args: - season (str): Season in YYYYYYYY format (e.g., "20232024") - series (str): Series identifier (a-h) for Round 1 + season (str): Season in ``YYYYYYYY`` format (e.g., ``"20252026"``). + series (str): Series letter identifier (``"a"``-``"h"`` for Round 1, + ``"i"``-``"l"`` for Round 2, ``"m"``-``"n"`` for CF, ``"o"`` for SCF). Returns: - dict: Schedule data for the specified playoff series. + dict: Series schedule data for the specified playoff matchup. + + Key Response Fields: + round (int): Playoff round number. + seriesLetter (str): Series letter identifier (e.g., "B"). + neededToWin (int): Wins required to advance (4). + length (int): Total games played in the series. + topSeedTeam.abbrev (str): Top seed team abbreviation. + topSeedTeam.seed (int): Seed number. + topSeedTeam.record (str): Series record (e.g., "3-4"). + bottomSeedTeam.abbrev (str): Bottom seed team abbreviation. + bottomSeedTeam.seriesWins (int): Series wins for the bottom seed. + games (list): List of game objects in the series. + games[].gameNumber (int): Game number within the series (1-7). + games[].ifNecessary (bool): Whether the game was an "if necessary" game. + games[].seriesStatus.topSeedWins (int): Top seed wins after this game. + games[].seriesStatus.bottomSeedWins (int): Bottom seed wins after this game. + + Response Docs: + docs/schedule.md Example: - API endpoint: https://api-web.nhle.com/v1/schedule/playoff-series/20232024/a/ + client.schedule.playoff_series_schedule(season="20252026", series="b") """ return self.client.get( @@ -149,16 +277,26 @@ def playoff_series_schedule(self, season: str, series: str) -> dict: ).json() def playoff_bracket(self, year: str) -> dict: - """Returns the playoff bracket. + """Returns the full playoff bracket for a given year. Args: - year (str): Year playoffs take place (e.g., "2024") + year (str): Year the playoffs take place (e.g., ``"2024"``). Returns: - dict: Playoff bracket data. + dict: Playoff bracket data. + + Key Response Fields: + bracketLogo (str): URL of the playoff bracket logo. + series (list): List of all 15 playoff series. + series[].topSeedTeam.abbrev (str): Top-seed team abbreviation. + series[].bottomSeedTeam.abbrev (str): Bottom-seed team abbreviation. + series[].topSeedWins (int): Number of wins for the top seed. + + Response Docs: + https://api-web.nhle.com/v1/playoff-bracket/{year} Example: - API endpoint: https://api-web.nhle.com/v1/playoff-bracket/2024 + client.schedule.playoff_bracket(year="2024") """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"playoff-bracket/{year}").json() diff --git a/nhlpy/api/standings.py b/nhlpy/api/standings.py index 0be282a..93c5cea 100644 --- a/nhlpy/api/standings.py +++ b/nhlpy/api/standings.py @@ -8,18 +8,45 @@ def __init__(self, http_client): self.client = http_client def league_standings(self, date: Optional[str] = None, season: Optional[str] = None) -> dict: - """Gets league standings for a specified season or date. + """Gets NHL league standings for a specific date or season. - Retrieves NHL standings either for a specific date or for the end of a season. - If both parameters are provided, season takes precedence. + Retrieves the full league standings snapshot. When ``season`` is + provided, the method resolves the last day of that season via + ``season_standing_manifest()`` and uses it as the date. If both + ``date`` and ``season`` are supplied, ``season`` takes precedence. + Passing neither returns today's standings. Args: - date (str, optional): Date in YYYY-MM-DD format. Defaults to current date. - season (str, optional): Season identifier to get final standings. - Takes precedence over date parameter if both are provided. + date (str, optional): Date in YYYY-MM-DD format. + Defaults to the current date when neither param is provided. + season (str, optional): Season identifier (e.g., "20232024"). + Overrides ``date`` -- the final standings date for the season + is looked up automatically. Returns: - dict: Dictionary containing league standings data + dict: Standings response with the following key fields: + + - ``wildCardIndicator`` (bool): Whether the wild-card format + is in effect for this snapshot. + - ``standings`` (list[dict]): List of 32 team standing entries. + Each entry contains: + + - ``teamName`` (dict): ``{"default": "..."}`` team name. + - ``teamAbbrev`` (dict): ``{"default": "..."}`` abbreviation. + - ``points`` (int): Total standings points. + - ``wins`` (int): Wins. + - ``losses`` (int): Losses. + - ``otLosses`` (int): Overtime losses. + - ``gamesPlayed`` (int): Games played. + - ``conferenceSequence`` (int): Rank within conference. + - ``divisionSequence`` (int): Rank within division. + + Raises: + ValueError: If the provided ``season`` is not found in the + season standing manifest. + + See Also: + https://api-web.nhle.com/v1/standings/{date} """ # We need to look up the last date of the season and use that as the date, since it doesnt seem to take @@ -37,29 +64,31 @@ def league_standings(self, date: Optional[str] = None, season: Optional[str] = N return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"standings/{res}").json() def season_standing_manifest(self) -> List[dict]: - """Gets metadata for all NHL seasons. - Returns information about what seems like every season. Start date, end date, etc. + """Gets metadata for every historical NHL season. - Args: - None + Returns a list of all seasons with their date ranges, structural + flags (conferences, divisions, ties), and scoring-rule indicators. + Used internally by ``league_standings()`` to resolve a season to its + final standings date. Returns: - dict: Season metadata including dates, conference/division usage, and scoring rules. - - Example: - Response format: - [{ - "id": 20232024, - "conferencesInUse": true, - "divisionsInUse": true, - "pointForOTlossInUse": true, - "regulationWinsInUse": true, - "rowInUse": true, - "standingsEnd": "2023-11-10", - "standingsStart": "2023-10-10", - "tiesInUse": false, - "wildcardInUse": true - }] + List[dict]: List of season metadata dicts. Each entry contains: + + - ``id`` (int): Season identifier (e.g., 20232024). + - ``conferencesInUse`` (bool): Whether conferences were active. + - ``divisionsInUse`` (bool): Whether divisions were active. + - ``pointForOTlossInUse`` (bool): OT-loss point rule in effect. + - ``regulationWinsInUse`` (bool): Regulation-wins tiebreaker. + - ``rowInUse`` (bool): ROW (regulation + overtime wins) in use. + - ``standingsEnd`` (str): Last date of the standings period + (YYYY-MM-DD). + - ``standingsStart`` (str): First date of the standings period + (YYYY-MM-DD). + - ``tiesInUse`` (bool): Whether ties were possible. + - ``wildcardInUse`` (bool): Wild-card playoff format in effect. + + See Also: + https://api-web.nhle.com/v1/standings-season """ response = self.client.get(endpoint=Endpoint.API_WEB_V1, resource="standings-season").json() return response.get("seasons", []) diff --git a/nhlpy/api/stats.py b/nhlpy/api/stats.py index 5082574..93dc77a 100644 --- a/nhlpy/api/stats.py +++ b/nhlpy/api/stats.py @@ -22,6 +22,13 @@ def gametypes_per_season_directory_by_team(self, team_abbr: str) -> dict: Returns: dict: A mapping of seasons to game types played by the team + Key Response Fields: + season (int): The season identifier in YYYYYYYY format (e.g., 20242025) + gameTypes (list[int]): List of game type codes played that season (1=Preseason, 2=Regular, 3=Playoffs) + + Response Docs: + docs/stats.md + Example: https://api-web.nhle.com/v1/club-stats-season/TOR @@ -48,6 +55,23 @@ def player_career_stats(self, player_id: str) -> dict: Returns: dict: A dictionary containing the player's career statistics and personal information + Key Response Fields: + playerId (int): Unique NHL player identifier + firstName.default (str): Player's first name + lastName.default (str): Player's last name + position (str): Player's position code (e.g., 'C', 'L', 'R', 'D', 'G') + currentTeamAbbrev (str): Three-letter abbreviation of the player's current team + careerTotals.regularSeason.goals (int): Career regular season goals + careerTotals.regularSeason.assists (int): Career regular season assists + careerTotals.regularSeason.points (int): Career regular season points + careerTotals.regularSeason.gamesPlayed (int): Career regular season games played + last5Games (list): Statistics from the player's last 5 games + seasonTotals (list): Per-season statistical breakdowns + awards (list): List of awards and trophies won + + Response Docs: + docs/stats.md + Example: Full Example: https://github.com/coreyjs/nhl-api-py/wiki/Player-Career-Stats-%E2%80%90-Example-Payload @@ -86,6 +110,21 @@ def player_game_log(self, player_id: str, season_id: str, game_type: int) -> Lis Returns: dict: A dictionary containing the player's game-by-game statistics for the specified parameters + Key Response Fields: + gameId (int): Unique game identifier + gameDate (str): Date of the game in YYYY-MM-DD format + goals (int): Goals scored in the game + assists (int): Assists recorded in the game + points (int): Total points in the game + plusMinus (int): Plus/minus rating for the game + shots (int): Shots on goal + toi (str): Time on ice in MM:SS format + opponentAbbrev (str): Three-letter abbreviation of the opposing team + teamAbbrev (str): Three-letter abbreviation of the player's team + + Response Docs: + docs/stats.md + Example: Full example here https://github.com/coreyjs/nhl-api-py/wiki/Stats.Player-Game-Log-%E2%80%90-Example-Response [ @@ -162,6 +201,21 @@ def team_summary( Returns: List[dict]: List of dictionaries containing team summary statistics + Key Response Fields: + teamFullName (str): Full display name of the team (e.g., 'Florida Panthers') + teamId (int): Unique team identifier + gamesPlayed (int): Total games played in the period + wins (int): Total wins + losses (int): Total losses + points (int): Standings points accumulated + goalsFor (int): Total goals scored + goalsAgainst (int): Total goals allowed + powerPlayPct (float): Power play conversion percentage + penaltyKillPct (float): Penalty kill success percentage + + Response Docs: + docs/stats.md + Examples: Full Response Example: https://github.com/coreyjs/nhl-api-py/wiki/Stats.Team-Summary-%E2%80%90-Example-Response c.stats.team_summary(start_season="20202021", end_season="20212022", game_type_id=2) @@ -261,6 +315,22 @@ def skater_stats_summary( Returns: List[dict]: List of dictionaries containing skater statistics + Key Response Fields: + skaterFullName (str): Full display name of the skater (e.g., 'Artemi Panarin') + playerId (int): Unique player identifier + teamAbbrevs (str): Three-letter team abbreviation(s) + gamesPlayed (int): Total games played + goals (int): Total goals scored + assists (int): Total assists + points (int): Total points (goals + assists) + plusMinus (int): Plus/minus rating + pointsPerGame (float): Average points per game + shots (int): Total shots on goal + shootingPct (float): Shooting percentage + + Response Docs: + docs/stats.md + Examples: Full Response Example: https://github.com/coreyjs/nhl-api-py/wiki/Stats.Skater-Stats-Summary-Simple c.stats.skater_stats_summary_simple(start_season="20232024", end_season="20232024") @@ -356,6 +426,22 @@ def skater_stats_with_query_context( Returns: dict: Dictionary containing skater statistics based on the specified report type + Key Response Fields (common across all report types): + playerId (int): Unique player identifier. + skaterFullName (str): Full display name of the skater. + teamAbbrevs (str): Three-letter team abbreviation(s). + seasonId (int): Season identifier. + gamesPlayed (int): Total games played. + + Note: + Response fields vary by report_type. For example, "summary" returns + goals/assists/points, "realtime" returns hits/blocks/giveaways, + "penalties" returns minorPenalties/majorPenalties. Use + client.misc.config() to discover available fields per report type. + + Response Docs: + docs/stats.md + Example: Full example here: https://github.com/coreyjs/nhl-api-py/wiki/Stats.Skater-Stats-with-Query-Context @@ -461,6 +547,20 @@ def goalie_stats_summary( Returns: dict: Dictionary containing goalie statistics based on the specified parameters + Key Response Fields: + goalieFullName (str): Full display name of the goalie (e.g., 'Connor Hellebuyck') + playerId (int): Unique player identifier + teamAbbrevs (str): Three-letter team abbreviation(s) + gamesPlayed (int): Total games played + wins (int): Total wins + losses (int): Total losses + savePct (float): Save percentage (e.g., 0.92612) + goalsAgainstAverage (float): Goals against average per game + shutouts (int): Total shutouts + + Response Docs: + docs/stats.md + Example: client.stats.goalie_stats_summary_simple(start_season="20242025", stats_type="summary") diff --git a/nhlpy/api/teams.py b/nhlpy/api/teams.py index ad444bc..0f0f058 100644 --- a/nhlpy/api/teams.py +++ b/nhlpy/api/teams.py @@ -96,27 +96,45 @@ def _find_franchise_id(self, team_name: str, franchise_lookup: Dict[str, int]) - return None def teams(self, date: str = "now") -> List[Dict[str, Any]]: - """Get a list of all NHL teams with their conference, division, and franchise information. + """Get a list of all NHL teams with conference, division, and franchise info. + + This method transforms the raw API response by aggregating team data + from the standings endpoint and enriching it with franchise IDs. Args: - date: Date in format YYYY-MM-DD. Defaults to "now". - Note that while the NHL API uses "now" to default to the current date, - during preseason this may default to last year's season. To get accurate - teams for the current season, supply a date (YYYY-MM-DD) at the start of - the upcoming season. For example: - - 2024-04-18 for season 2023-2024 - - 2024-10-04 for season 2024-2025 + date (str): Date in ``YYYY-MM-DD`` format. Defaults to ``"now"``. + Note that while the NHL API uses ``"now"`` to default to the + current date, during preseason this may default to last year's + season. To get accurate teams for the current season, supply a + date at the start of the upcoming season. For example: + + - ``"2024-04-18"`` for season 2023-2024 + - ``"2024-10-04"`` for season 2024-2025 Returns: - List of dictionaries containing team information including conference, - division, and franchise ID. Data is aggregated from the current standings - API and joined with franchise information. + List[Dict[str, Any]]: List of team dicts. + + Key Response Fields (per team dict): + name (str): Full team name (e.g., ``"Buffalo Sabres"``). + common_name (str): Common team name (e.g., ``"Sabres"``). + abbr (str): Three-letter team abbreviation (e.g., ``"BUF"``). + logo (str): URL of the team logo. + franchise_id (int): Numeric franchise identifier. + conference.name (str): Conference name (e.g., ``"Eastern"``). + division.name (str): Division name (e.g., ``"Atlantic"``). Note: - Updated in 2.10.0: Now pulls from current standings API, aggregates team - conference/division data, and joins with franchise ID. This workaround is - necessary due to NHL API limitations preventing this data from being retrieved - in a single request. + Updated in 2.10.0: Now pulls from the standings API, aggregates + team conference/division data, and joins with franchise IDs. This + workaround is necessary due to NHL API limitations preventing this + data from being retrieved in a single request. + + Response Docs: + https://api-web.nhle.com/v1/standings/{date} + + Example: + client.teams.teams() + client.teams.teams(date="2024-10-04") """ standings_data = self._fetch_standings_data(date) teams = self._parse_teams_from_standings(standings_data) @@ -127,11 +145,31 @@ def team_roster(self, team_abbr: str, season: str) -> Dict[str, Any]: """Get the roster for the given team and season. Args: - team_abbr: Team abbreviation (e.g., BUF, TOR) - season: Season in format YYYYYYYY (e.g., 20202021, 20212022) + team_abbr (str): Team abbreviation (e.g., ``"BUF"``, ``"TOR"``). + season (str): Season in ``YYYYYYYY`` format (e.g., ``"20202021"``). Returns: - Dictionary containing roster information for the specified team and season. + Dict[str, Any]: Dictionary keyed by position group. + + Key Response Fields: + forwards (list): List of forward player dicts. + defensemen (list): List of defenseman player dicts. + goalies (list): List of goalie player dicts. + + Key Player Fields (per player dict): + id (int): Unique player identifier. + firstName.default (str): Player's first name. + lastName.default (str): Player's last name. + sweaterNumber (int): Jersey number. + positionCode (str): Position code (e.g., ``"C"``, ``"D"``, ``"G"``). + birthDate (str): Date of birth (``YYYY-MM-DD``). + birthCountry (str): Three-letter country code. + + Response Docs: + https://api-web.nhle.com/v1/roster/{team}/{season} + + Example: + client.teams.team_roster(team_abbr="BUF", season="20232024") """ return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=f"roster/{team_abbr}/{season}").json() @@ -139,7 +177,21 @@ def franchises(self) -> List[Dict[str, Any]]: """Get a list of all past and current NHL franchises. Returns: - List of all NHL franchises, including historical/defunct teams. + List[Dict[str, Any]]: List of franchise dicts, including + historical and defunct teams. + + Key Response Fields (per franchise dict): + id (int): Unique franchise identifier. + fullName (str): Full franchise name (e.g., + ``"Buffalo Sabres"``). + teamCommonName (str): Common name (e.g., ``"Sabres"``). + teamPlaceName (str): Place name (e.g., ``"Buffalo"``). + + Response Docs: + https://api.nhle.com/stats/rest/en/franchise + + Example: + client.teams.franchises() """ # franchise_url = f"{self.NHL_STATS_API_BASE}/en/franchise" response = self.client.get(endpoint=Endpoint.API_STATS, resource="en/franchise").json() diff --git a/pyproject.toml b/pyproject.toml index 941e796..e7f5802 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "nhl-api-py" -version = "3.2.3" +version = "3.3.0" description = "NHL API (Updated for 2025/2026) and EDGE Stats. For standings, team stats, outcomes, player information. Contains each individual API endpoint as well as convience methods as well as pythonic query builder for more indepth EDGE stats." authors = ["Corey Schaf "] readme = "README.md"