Source code for gamesheet_sdk.admin.games.locations

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

"""Location operations for games."""

from __future__ import annotations

from typing import Any

from gamesheet_sdk.admin.games.models import Location
from gamesheet_sdk.common import errors
from gamesheet_sdk.common.constants import API_LOCATIONS, DEFAULT_BASE_URL
from gamesheet_sdk.common.exceptions import GameSheetError
from gamesheet_sdk.common.session import Session
from gamesheet_sdk.common.shared import handle_response


[docs] def list_locations(session: Session) -> list[Location]: """Return the list of valid locations. Fetches the current list of locations/venues from the main API. The returned locations include venue name and surface name which together form the location identifier used when creating or updating scheduled games. :param session: An authenticated :class:`Session`. :type session: Session :returns: A list of :class:`Location` objects. :rtype: list[Location] :raises AuthenticationError: If the server returns 401 or 403. :raises GameSheetError: For any other non-2xx response. """ url = f"{DEFAULT_BASE_URL}{API_LOCATIONS}" response = session.get(url) handle_response(response, url, "GET locations") body: dict[str, Any] = response.json() return [Location(**loc) for loc in body.get("data", [])]
[docs] def get_location(session: Session, location_id: str) -> Location: """Get a specific location by ID. Fetches the list of all locations and returns the one matching the given ID. :param session: An authenticated :class:`Session`. :type session: Session :param location_id: The location UUID to retrieve. :type location_id: str :returns: The :class:`Location` with the specified ID. :rtype: Location :raises GameSheetError: If the location ID is not found. """ locations = list_locations(session) for loc in locations: if loc.id == location_id: return loc msg = errors.ERROR_MSG_LOCATION_NOT_FOUND.format(location_id=location_id) raise GameSheetError(msg)
[docs] def validate_location(session: Session, location: str) -> str: """Validate a location and return the correctly-cased version. Fetches the list of valid locations and performs a case-insensitive match against the concatenation of location_name + " " + surface_name. Returns the correctly-cased full location name. :param session: An authenticated :class:`Session`. :type session: Session :param location: The location string to validate (case-insensitive). :type location: str :returns: The correctly-cased location string. :rtype: str :raises GameSheetError: If the location is not valid. """ if not location: return location locations = list_locations(session) location_lower = location.lower() for loc in locations: full_name = loc.full_name() if full_name.lower() == location_lower: return full_name # If not found, show a helpful error with examples (limited to first 5) examples = [loc.full_name() for loc in locations[:5]] joined_examples = ", ".join(examples) msg = ( f"Invalid location '{location}'. Location must match the format " f"'<location_name> <surface_name>' (case-insensitive). " f"Examples: {joined_examples}... " f"Use 'gamesheet-admin locations list' to see all valid locations." ) raise GameSheetError(msg)