Source code for gamesheet_sdk.admin.games.scheduled

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

"""Scheduled game CRUD operations."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from gamesheet_sdk.admin.games import broadcasters, locations
from gamesheet_sdk.admin.games.helpers import _make_request, validate_game_type
from gamesheet_sdk.admin.games.models import Game, ScheduledGame
from gamesheet_sdk.common.constants import (
    API_SEASONS_SCHEDULE,
    API_SEASONS_SCHEDULE_GAME,
    DEFAULT_BASE_URL,
)
from gamesheet_sdk.common.shared import handle_response

if TYPE_CHECKING:
    from gamesheet_sdk.common.session import Session


[docs] def list_scheduled(session: Session, season_id: str) -> list[Game]: """Return every scheduled game in the specified season. The supplied :class:`Session` must already carry a bearer token (e.g. via :meth:`Session.set_bearer_token`); the call is otherwise unauthenticated and will 401. Args: session (Session): An authenticated :class:`Session`. season_id (str): The season identifier whose scheduled games to list. Returns: list[Game]: A list of :class:`Game`, in the order the server returned them. The list may be empty if the season has no scheduled games. """ return _make_request(session, season_id, completed=False, scheduled=True)
[docs] def create_scheduled_game( session: Session, season_id: str, scheduled_start_time: str, scheduled_end_time: str, home_team_id: str, home_division_id: str, visitor_team_id: str, visitor_division_id: str, location: str, scorekeeper_name: str, scorekeeper_phone: str, game_type: str, time_zone_name: str, time_zone_offset: int, number: str, broadcaster: str = "", home_label: str = "", visitor_label: str = "", ) -> ScheduledGame: """Create a new scheduled game. The supplied :class:`Session` must already carry a bearer token (e.g. via :meth:`Session.set_bearer_token`); the call is otherwise unauthenticated and will 401. Args: session (Session): An authenticated :class:`Session`. season_id (str): The parent season identifier. scheduled_start_time (str): Scheduled start time (ISO 8601 format). scheduled_end_time (str): Scheduled end time (ISO 8601 format). home_team_id (str): Home team identifier. home_division_id (str): Home team division identifier. visitor_team_id (str): Visitor team identifier. visitor_division_id (str): Visitor team division identifier. location (str): Game location/venue (default: empty string). Must match format '<location_name> <surface_name>' from the API (case-insensitive match, but stored with correct casing). scorekeeper_name (str): Scorekeeper's full name. scorekeeper_phone (str): Scorekeeper's phone number. game_type (str): Game type. Must be one of: playoff, exhibition, tournament, regular_season. time_zone_name (str): IANA time zone name. time_zone_offset (int): Time zone offset in minutes. number (str): Game number. broadcaster (str): Broadcast provider name (default: empty string). Must match a valid broadcaster key from the API (case-insensitive match, but stored with correct casing). home_label (str): Home team label override (default: empty string). visitor_label (str): Visitor team label override (default: empty string). Returns: ScheduledGame: The created :class:`ScheduledGame`. """ # Validate game type validate_game_type(game_type) # Validate location if provided if location: location = locations.validate_location(session, location) # Validate broadcaster if provided if broadcaster: broadcaster = broadcasters.validate_broadcaster_key(session, broadcaster) url = f"{DEFAULT_BASE_URL}{API_SEASONS_SCHEDULE.format(season_id=season_id)}" payload = { "data": { "attributes": { "scheduled_start_time": scheduled_start_time, "scheduled_end_time": scheduled_end_time, "number": number, "location": location, "scorekeeper": {"name": scorekeeper_name, "phone": scorekeeper_phone}, "game_type": game_type, "time_zone_offset": time_zone_offset, "time_zone_name": time_zone_name, "data": { "broadcaster": broadcaster, "home_label": home_label, "visitor_label": visitor_label, }, "status": "", }, "relationships": { "home_team": {"data": {"id": home_team_id, "type": "teams"}}, "home_division": { "data": {"id": home_division_id, "type": "divisions"}, }, "visitor_team": {"data": {"id": visitor_team_id, "type": "teams"}}, "visitor_division": { "data": {"id": visitor_division_id, "type": "divisions"}, }, }, }, } response = session.post(url, json=payload) handle_response(response, url, "POST scheduled game") body: dict[str, Any] = response.json() return ScheduledGame(**body)
[docs] def get_scheduled_game(session: Session, season_id: str, game_id: str) -> ScheduledGame: """Get a single scheduled game by ID (JSON:API format). The supplied :class:`Session` must already carry a bearer token (e.g. via :meth:`Session.set_bearer_token`); the call is otherwise unauthenticated and will 401. Args: session (Session): An authenticated :class:`Session`. season_id (str): The parent season identifier. game_id (str): The game identifier to retrieve. Returns: ScheduledGame: The :class:`ScheduledGame` with the specified ID. """ url = f"{DEFAULT_BASE_URL}{API_SEASONS_SCHEDULE_GAME.format(season_id=season_id, game_id=game_id)}" response = session.get(url) handle_response(response, url, "GET scheduled game") body: dict[str, Any] = response.json() return ScheduledGame(**body)
[docs] def update_scheduled_game( session: Session, season_id: str, game_id: str, scheduled_start_time: str, scheduled_end_time: str, home_team_id: str, home_division_id: str, visitor_team_id: str, visitor_division_id: str, location: str, scorekeeper_name: str, scorekeeper_phone: str, game_type: str, time_zone_name: str, time_zone_offset: int, number: str, status: str, broadcaster: str = "", home_label: str = "", visitor_label: str = "", ) -> ScheduledGame: """Update a scheduled game. The supplied :class:`Session` must already carry a bearer token (e.g. via :meth:`Session.set_bearer_token`); the call is otherwise unauthenticated and will 401. Args: session (Session): An authenticated :class:`Session`. season_id (str): The parent season identifier. game_id (str): The game identifier to update. scheduled_start_time (str): Scheduled start time (ISO 8601 format). scheduled_end_time (str): Scheduled end time (ISO 8601 format). home_team_id (str): Home team identifier. home_division_id (str): Home team division identifier. visitor_team_id (str): Visitor team identifier. visitor_division_id (str): Visitor team division identifier. location (str): Game location/venue. Must match format '<location_name> <surface_name>' from the API (case- insensitive match, but stored with correct casing). scorekeeper_name (str): Scorekeeper's full name. scorekeeper_phone (str): Scorekeeper's phone number. game_type (str): Game type. Must be one of: playoff, exhibition, tournament, regular_season. time_zone_name (str): IANA time zone name. time_zone_offset (int): Time zone offset in minutes. number (str): Game number. status (str): Game status. broadcaster (str): Broadcast provider name (default: empty string). Must match a valid broadcaster key from the API (case-insensitive match, but stored with correct casing). home_label (str): Home team label override (default: empty string). visitor_label (str): Visitor team label override (default: empty string). Returns: ScheduledGame: The updated :class:`ScheduledGame`. """ # Validate game type validate_game_type(game_type) # Validate location (always provided in update, even if empty) if location: location = locations.validate_location(session, location) # Validate broadcaster if provided if broadcaster: broadcaster = broadcasters.validate_broadcaster_key(session, broadcaster) url = f"{DEFAULT_BASE_URL}{API_SEASONS_SCHEDULE_GAME.format(season_id=season_id, game_id=game_id)}" payload = { "data": { "attributes": { "scheduled_start_time": scheduled_start_time, "scheduled_end_time": scheduled_end_time, "number": number, "location": location, "scorekeeper": {"name": scorekeeper_name, "phone": scorekeeper_phone}, "game_type": game_type, "time_zone_offset": time_zone_offset, "time_zone_name": time_zone_name, "data": { "vendors": {}, "is_valid": False, "broadcaster": broadcaster, "location_id": 0, "broadcaster_id": 0, "home_label": home_label, "visitor_label": visitor_label, }, "status": status, }, "relationships": { "home_team": {"data": {"id": home_team_id, "type": "teams"}}, "home_division": { "data": {"id": home_division_id, "type": "divisions"}, }, "visitor_team": {"data": {"id": visitor_team_id, "type": "teams"}}, "visitor_division": { "data": {"id": visitor_division_id, "type": "divisions"}, }, }, }, } response = session.patch(url, json=payload) handle_response(response, url, "PATCH scheduled game") body: dict[str, Any] = response.json() return ScheduledGame(**body)
[docs] def delete_scheduled_game(session: Session, season_id: str, game_id: str) -> None: """Delete a scheduled game. The supplied :class:`Session` must already carry a bearer token (e.g. via :meth:`Session.set_bearer_token`); the call is otherwise unauthenticated and will 401. Args: session (Session): An authenticated :class:`Session`. season_id (str): The parent season identifier. game_id (str): The game identifier to delete. """ url = f"{DEFAULT_BASE_URL}{API_SEASONS_SCHEDULE_GAME.format(season_id=season_id, game_id=game_id)}" response = session.delete(url) handle_response(response, url, "DELETE scheduled game")