Source code for gamesheet_sdk.admin.games.models

# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT

"""Pydantic models for games, locations, broadcasters, and related entities."""

from __future__ import annotations

from typing import Any

from pydantic import BaseModel, Field


[docs] class Broadcaster(BaseModel): """A broadcaster/streaming service. :var key: Broadcaster key identifier (e.g., "LIVEBARN"). :var title: Display name of the broadcaster. :var url: Broadcaster website URL. """ key: str = Field(description="Broadcaster key identifier.") title: str = Field(description="Display name of the broadcaster.") url: str = Field(description="Broadcaster website URL.")
[docs] class Location(BaseModel): """A game location/venue with surface. :var id: Location identifier (UUID). :var location_name: Venue name (e.g., "140 Ice Den"). :var surface_name: Surface/rink name (e.g., "Rink #1"). :var city: City where the location is located. :var province_state: Province or state. :var country: Country. """ id: str = Field(description="Location identifier (UUID).") location_name: str = Field(description="Venue name.") surface_name: str = Field(description="Surface/rink name.") city: str = Field(description="City where the location is located.") province_state: str = Field(description="Province or state.") country: str = Field(description="Country.")
[docs] def full_name(self: Location) -> str: """Return the full location name as location_name + surface_name. :returns: Combined location and surface name. :rtype: str """ return f"{self.location_name} {self.surface_name}"
[docs] class TeamInfo(BaseModel): """Team information within a game. :var id: Team identifier. :var title: Team name. :var division_id: Division identifier. :var division_title: Division name. """ id: int = Field(description="Team identifier.") title: str = Field(description="Team name.") division_id: int | None = Field( default=None, alias="divisionId", description="Division identifier.", ) division_title: str | None = Field( default=None, alias="divisionTitle", description="Division name.", )
[docs] class Game(BaseModel): """A single game. Maps the game objects from the BFF API response. :var id: Game identifier. :var status: Game status (e.g., completed, scheduled). :var date: Game date (YYYY-MM-DD). :var time: Game start time. :var end_time: Game end time. :var time_zone_name: Time zone name. :var location: Venue/location of the game. :var game_number: Game number or identifier. :var game_type: Game type (regular, playoff, etc.). :var visitor: Visiting team information. :var home: Home team information. :var visitor_score: Visitor team score. :var home_score: Home team score. :var has_shootout: Whether game had a shootout. :var has_overtime: Whether game had overtime. :var viewed: Whether the user has viewed this game. """ id: int = Field(description="Game identifier.") status: str = Field(description="Game status (e.g., completed, scheduled).") date: str = Field(description="Game date (YYYY-MM-DD).") time: str | None = Field(default=None, description="Game start time.") end_time: str | None = Field( default=None, alias="endTime", description="Game end time.", ) time_zone_name: str | None = Field( default=None, alias="timeZoneName", description="Time zone name.", ) location: str | None = Field( default=None, description="Venue/location of the game.", ) game_number: str | None = Field( default=None, alias="gameNumber", description="Game number or identifier.", ) game_type: str | None = Field( default=None, alias="gameType", description="Game type (regular, playoff, etc.).", ) visitor: TeamInfo = Field(description="Visiting team information.") home: TeamInfo = Field(description="Home team information.") visitor_score: int | None = Field( default=None, alias="visitorScore", description="Visitor team score.", ) home_score: int | None = Field( default=None, alias="homeScore", description="Home team score.", ) has_shootout: bool | None = Field( default=None, alias="hasShootout", description="Whether game had a shootout.", ) has_overtime: bool | None = Field( default=None, alias="hasOvertime", description="Whether game had overtime.", ) viewed: bool | None = Field( default=None, description="Whether the user has viewed this game.", ) model_config = {"populate_by_name": True}
[docs] class Scorekeeper(BaseModel): """Scorekeeper information for a scheduled game. :var name: Scorekeeper's full name. :var phone: Scorekeeper's phone number. """ name: str = Field(description="Scorekeeper's full name.") phone: str = Field(description="Scorekeeper's phone number.")
[docs] class GameData(BaseModel): """Additional game metadata. :var vendors: Vendor information (typically empty dict). :var is_valid: Game validation status. :var broadcaster: Broadcast provider name. :var location_id: Location identifier. :var broadcaster_id: Broadcaster identifier. :var home_label: Home team label override. :var visitor_label: Visitor team label override. """ vendors: dict[str, Any] = Field( default_factory=dict, description="Vendor information.", ) is_valid: bool = Field( default=False, alias="isValid", description="Game validation status.", ) broadcaster: str = Field(default="", description="Broadcast provider name.") location_id: int = Field( default=0, alias="locationId", description="Location identifier.", ) broadcaster_id: int = Field( default=0, alias="broadcasterId", description="Broadcaster identifier.", ) home_label: str = Field( default="", alias="homeLabel", description="Home team label override.", ) visitor_label: str = Field( default="", alias="visitorLabel", description="Visitor team label override.", ) model_config = {"populate_by_name": True}
[docs] class RelationshipData(BaseModel): """JSON:API relationship data. :var id: Related resource identifier. :var type: Related resource type. """ id: str = Field(description="Related resource identifier.") type: str = Field(description="Related resource type.")
[docs] class Relationship(BaseModel): """JSON:API relationship wrapper. :var data: Relationship data. """ data: RelationshipData = Field(description="Relationship data.")
[docs] class ScheduledGameRelationships(BaseModel): """Relationships for a scheduled game (JSON:API format). :var association: Parent association. :var home_division: Home team's division. :var home_team: Home team. :var league: Parent league. :var season: Parent season. :var visitor_division: Visitor team's division. :var visitor_team: Visitor team. """ association: Relationship | None = Field( default=None, description="Parent association.", ) home_division: Relationship = Field( alias="home_division", description="Home team's division.", ) home_team: Relationship = Field(alias="home_team", description="Home team.") league: Relationship | None = Field(default=None, description="Parent league.") season: Relationship | None = Field(default=None, description="Parent season.") visitor_division: Relationship = Field( alias="visitor_division", description="Visitor team's division.", ) visitor_team: Relationship = Field( alias="visitor_team", description="Visitor team.", ) model_config = {"populate_by_name": True}
[docs] class ScheduledGameAttributes(BaseModel): """Attributes for a scheduled game (JSON:API format). :var status: Game status. :var number: Game number. :var scheduled_start_time: Scheduled start time (ISO 8601). :var scheduled_time_gmt: Scheduled time in GMT (ISO 8601). :var scheduled_end_time: Scheduled end time (ISO 8601). :var time_zone_name: IANA time zone name. :var location: Venue/location. :var category: Game category. :var game_type: Game type (exhibition, regular_season, etc.). :var scorekeeper: Scorekeeper information. :var data: Additional game metadata. :var created_at: Creation timestamp (ISO 8601). :var updated_at: Last update timestamp (ISO 8601). """ status: str = Field(description="Game status.") number: str = Field(description="Game number.") scheduled_start_time: str = Field(description="Scheduled start time (ISO 8601).") scheduled_time_gmt: str | None = Field( default=None, description="Scheduled time in GMT (ISO 8601).", ) scheduled_end_time: str = Field(description="Scheduled end time (ISO 8601).") time_zone_name: str = Field(description="IANA time zone name.") location: str = Field(description="Venue/location.") category: str = Field(default="", description="Game category.") game_type: str = Field(description="Game type (exhibition, regular_season, etc.).") scorekeeper: Scorekeeper = Field(description="Scorekeeper information.") data: GameData = Field(description="Additional game metadata.") created_at: str | None = Field( default=None, description="Creation timestamp (ISO 8601).", ) updated_at: str | None = Field( default=None, description="Last update timestamp (ISO 8601).", )
[docs] class ScheduledGameData(BaseModel): """JSON:API data wrapper for a scheduled game. :var type: Resource type (always 'scheduled-games'). :var id: Game identifier. :var attributes: Game attributes. :var relationships: Game relationships. """ type: str = Field(description="Resource type.") id: str = Field(description="Game identifier.") attributes: ScheduledGameAttributes = Field(description="Game attributes.") relationships: ScheduledGameRelationships = Field(description="Game relationships.")
[docs] class ScheduledGame(BaseModel): """A scheduled game (JSON:API format). Used for create/get/update operations via the /api/seasons/{id}/schedule endpoint. :var data: Game data wrapper. """ data: ScheduledGameData = Field(description="Game data wrapper.")