# Copyright (c) 2026 bdperkin
# SPDX-License-Identifier: MIT
"""Roster data models for players and coaches."""
from __future__ import annotations
from datetime import datetime
from typing import Any
from pydantic import BaseModel, Field
from gamesheet_sdk.admin.shared import parse_jsonapi_resource
from gamesheet_sdk.common.shared.constants import (
FIELD_DESC_COACH_FIRST_NAME,
FIELD_DESC_COACH_LAST_NAME,
FIELD_DESC_PARENT_SEASON_ID,
FIELD_DESC_PLAYER_FIRST_NAME,
FIELD_DESC_PLAYER_LAST_NAME,
)
[docs]
class Player(BaseModel):
"""A single player.
Maps the ``data[*]`` items in the JSON: API response of ``GET /api/seasons/{id}/players`` to a flat typed
model. Includes both base player data and roster-specific metadata (position, jersey, etc.).
Attributes:
id (str): Player identifier (string in JSON:API).
season_id (str): Parent season identifier.
external_id (str | None): External identifier.
first_name (str | None): Player's first name.
last_name (str | None): Player's last name.
birthdate (str | None): Player's birthdate.
photo_url (str | None): URL to player photo.
biography (str | None): Player biography.
height (str | None): Player height.
weight (str | None): Player weight.
shot_hand (str | None): Player's shooting hand.
province (str | None): Player's province.
hometown (str | None): Player's hometown.
country (str | None): Player's country.
drafted_by (str | None): Team that drafted the player.
committed_to (str | None): School/team player committed to.
number (str | None): Player's jersey number (team roster only).
position (str | None): Player's position (team roster only).
duty (str | None): Player's duty (team roster only).
designation (str | None): Player's designation (team roster only).
status (str | None): Player's status (team roster only).
starting (bool | None): Whether player is starting (team roster only).
added_at_game_time (bool | None): Whether player was added at game time (team roster only).
affiliated (bool | None): Whether player is affiliated (team roster only).
created_at (datetime): When the player record was created.
updated_at (datetime): Last time the player record was updated.
"""
id: str = Field(description="Player identifier (string in JSON:API).")
season_id: str = Field(description=FIELD_DESC_PARENT_SEASON_ID)
external_id: str | None = Field(default=None, description="External identifier.")
first_name: str | None = Field(
default=None,
description=FIELD_DESC_PLAYER_FIRST_NAME,
)
last_name: str | None = Field(default=None, description=FIELD_DESC_PLAYER_LAST_NAME)
birthdate: str | None = Field(default=None, description="Player's birthdate.")
photo_url: str | None = Field(default=None, description="URL to player photo.")
biography: str | None = Field(default=None, description="Player biography.")
height: str | None = Field(default=None, description="Player height.")
weight: str | None = Field(default=None, description="Player weight.")
shot_hand: str | None = Field(default=None, description="Player's shooting hand.")
province: str | None = Field(default=None, description="Player's province.")
hometown: str | None = Field(default=None, description="Player's hometown.")
country: str | None = Field(default=None, description="Player's country.")
drafted_by: str | None = Field(
default=None,
description="Team that drafted the player.",
)
committed_to: str | None = Field(
default=None,
description="School/team player committed to.",
)
number: str | None = Field(
default=None,
description="Player's jersey number (team roster only).",
)
position: str | None = Field(
default=None,
description="Player's position (team roster only).",
)
duty: str | None = Field(
default=None,
description="Player's duty (team roster only).",
)
designation: str | None = Field(
default=None,
description="Player's designation (team roster only).",
)
status: str | None = Field(
default=None,
description="Player's status (team roster only).",
)
starting: bool | None = Field(
default=None,
description="Whether player is starting (team roster only).",
)
added_at_game_time: bool | None = Field(
default=None,
description="Whether player was added at game time (team roster only).",
)
affiliated: bool | None = Field(
default=None,
description="Whether player is affiliated (team roster only).",
)
created_at: datetime = Field(description="When the player record was created.")
updated_at: datetime = Field(description="Last time the player record was updated.")
[docs]
class Coach(BaseModel):
"""A single coach.
Maps the ``data[*]`` items in the JSON: API response of ``GET /api/seasons/{id}/coaches`` to a flat typed
model.
Attributes:
id (str): Coach identifier (string in JSON:API).
season_id (str): Parent season identifier.
external_id (str | None): External identifier.
first_name (str | None): Coach's first name.
last_name (str | None): Coach's last name.
position (str | None): Coach's position (team roster only).
status (str | None): Coach's status (team roster only).
signature (str | None): Coach's signature (team roster only).
created_at (datetime): When the coach record was created.
updated_at (datetime): Last time the coach record was updated.
"""
id: str = Field(description="Coach identifier (string in JSON:API).")
season_id: str = Field(description=FIELD_DESC_PARENT_SEASON_ID)
external_id: str | None = Field(default=None, description="External identifier.")
first_name: str | None = Field(
default=None,
description=FIELD_DESC_COACH_FIRST_NAME,
)
last_name: str | None = Field(default=None, description=FIELD_DESC_COACH_LAST_NAME)
position: str | None = Field(
default=None,
description="Coach's position (team roster only).",
)
status: str | None = Field(
default=None,
description="Coach's status (team roster only).",
)
signature: str | None = Field(
default=None,
description="Coach's signature (team roster only).",
)
created_at: datetime = Field(description="When the coach record was created.")
updated_at: datetime = Field(description="Last time the coach record was updated.")
[docs]
def parse_player(item: dict[str, Any]) -> Player:
"""Flatten a JSON:API resource object into a :class:`Player`.
Args:
item (dict[str, Any]): A JSON:API resource object with ``id``, ``attributes``, and ``relationships``
keys.
Returns:
Player: Parsed Player model instance.
"""
data = parse_jsonapi_resource(item, relationship_map={"season": "season_id"})
return Player(**data)
[docs]
def parse_coach(item: dict[str, Any]) -> Coach:
"""Flatten a JSON:API resource object into a :class:`Coach`.
Args:
item (dict[str, Any]): A JSON:API resource object with ``id``, ``attributes``, and ``relationships``
keys.
Returns:
Coach: Parsed Coach model instance.
"""
data = parse_jsonapi_resource(item, relationship_map={"season": "season_id"})
return Coach(**data)