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 Any

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.session import Session
from gamesheet_sdk.common.shared import handle_response


[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. :param session: An authenticated :class:`Session`. :type session: Session :param season_id: The season identifier whose scheduled games to list. :type season_id: str :returns: A list of :class:`Game`, in the order the server returned them. The list may be empty if the season has no scheduled games. :rtype: list[Game] """ 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. :param session: An authenticated :class:`Session`. :type session: Session :param season_id: The parent season identifier. :type season_id: str :param scheduled_start_time: Scheduled start time (ISO 8601 format). :type scheduled_start_time: str :param scheduled_end_time: Scheduled end time (ISO 8601 format). :type scheduled_end_time: str :param home_team_id: Home team identifier. :type home_team_id: str :param home_division_id: Home team division identifier. :type home_division_id: str :param visitor_team_id: Visitor team identifier. :type visitor_team_id: str :param visitor_division_id: Visitor team division identifier. :type visitor_division_id: str :param location: Game location/venue (default: empty string). Must match format '<location_name> <surface_name>' from the API (case-insensitive match, but stored with correct casing). :type location: str :param scorekeeper_name: Scorekeeper's full name. :type scorekeeper_name: str :param scorekeeper_phone: Scorekeeper's phone number. :type scorekeeper_phone: str :param game_type: Game type. Must be one of: playoff, exhibition, tournament, regular_season. :type game_type: str :param time_zone_name: IANA time zone name. :type time_zone_name: str :param time_zone_offset: Time zone offset in minutes. :type time_zone_offset: int :param number: Game number. :type number: str :param broadcaster: Broadcast provider name (default: empty string). Must match a valid broadcaster key from the API (case-insensitive match, but stored with correct casing). :type broadcaster: str :param home_label: Home team label override (default: empty string). :type home_label: str :param visitor_label: Visitor team label override (default: empty string). :type visitor_label: str :returns: The created :class:`ScheduledGame`. :rtype: ScheduledGame :raises AuthenticationError: If the server returns 401. :raises GameSheetError: If the game_type, location, or broadcaster is invalid, or for any other non-2xx response. """ # Import here to avoid circular dependency from gamesheet_sdk.admin.games.broadcasters import validate_broadcaster_key from gamesheet_sdk.admin.games.locations import validate_location # Validate game type validate_game_type(game_type) # Validate location if provided if location: location = validate_location(session, location) # Validate broadcaster if provided if broadcaster: broadcaster = 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. :param session: An authenticated :class:`Session`. :type session: Session :param season_id: The parent season identifier. :type season_id: str :param game_id: The game identifier to retrieve. :type game_id: str :returns: The :class:`ScheduledGame` with the specified ID. :rtype: ScheduledGame :raises AuthenticationError: If the server returns 401. :raises GameSheetError: For any other non-2xx response, including 404 if the game is not found. """ 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)
# pylint: disable-next=too-many-positional-arguments
[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. :param session: An authenticated :class:`Session`. :type session: Session :param season_id: The parent season identifier. :type season_id: str :param game_id: The game identifier to update. :type game_id: str :param scheduled_start_time: Scheduled start time (ISO 8601 format). :type scheduled_start_time: str :param scheduled_end_time: Scheduled end time (ISO 8601 format). :type scheduled_end_time: str :param home_team_id: Home team identifier. :type home_team_id: str :param home_division_id: Home team division identifier. :type home_division_id: str :param visitor_team_id: Visitor team identifier. :type visitor_team_id: str :param visitor_division_id: Visitor team division identifier. :type visitor_division_id: str :param location: Game location/venue. Must match format '<location_name> <surface_name>' from the API (case-insensitive match, but stored with correct casing). :type location: str :param scorekeeper_name: Scorekeeper's full name. :type scorekeeper_name: str :param scorekeeper_phone: Scorekeeper's phone number. :type scorekeeper_phone: str :param game_type: Game type. Must be one of: playoff, exhibition, tournament, regular_season. :type game_type: str :param time_zone_name: IANA time zone name. :type time_zone_name: str :param time_zone_offset: Time zone offset in minutes. :type time_zone_offset: int :param number: Game number. :type number: str :param status: Game status. :type status: str :param broadcaster: Broadcast provider name (default: empty string). Must match a valid broadcaster key from the API (case-insensitive match, but stored with correct casing). :type broadcaster: str :param home_label: Home team label override (default: empty string). :type home_label: str :param visitor_label: Visitor team label override (default: empty string). :type visitor_label: str :returns: The updated :class:`ScheduledGame`. :rtype: ScheduledGame :raises AuthenticationError: If the server returns 401. :raises GameSheetError: If the game_type, location, or broadcaster is invalid, or for any other non-2xx response, including 404 if the game is not found. """ # Import here to avoid circular dependency from gamesheet_sdk.admin.games.broadcasters import validate_broadcaster_key from gamesheet_sdk.admin.games.locations import validate_location # Validate game type validate_game_type(game_type) # Validate location (always provided in update, even if empty) if location: location = validate_location(session, location) # Validate broadcaster if provided if broadcaster: broadcaster = 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. :param session: An authenticated :class:`Session`. :type session: Session :param season_id: The parent season identifier. :type season_id: str :param game_id: The game identifier to delete. :type game_id: str :raises AuthenticationError: If the server returns 401. :raises GameSheetError: For any other non-2xx response, including 404 if the game is not found. """ 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")