Spaces:
Sleeping
Sleeping
| """Pydantic models for player and game data.""" | |
| from typing import Any, ClassVar | |
| from pydantic import BaseModel, Field, field_validator | |
| from src.config import DIFFICULTY_PRESETS | |
| class PlayerStats(BaseModel): | |
| """Model representing a player's career statistics.""" | |
| full_name: str = Field(..., min_length=1, max_length=100) | |
| ast: int = Field(..., ge=0, description="Career assists") | |
| blk: int = Field(..., ge=0, description="Career blocks") | |
| dreb: int = Field(..., ge=0, description="Career defensive rebounds") | |
| fg3a: int = Field(..., ge=0, description="Career 3-point attempts") | |
| fg3m: int = Field(..., ge=0, description="Career 3-pointers made") | |
| fg3_pct: float = Field(..., ge=0.0, le=1.0, description="3-point percentage") | |
| fga: int = Field(..., ge=0, description="Career field goal attempts") | |
| fgm: int = Field(..., ge=0, description="Career field goals made") | |
| fg_pct: float = Field(..., ge=0.0, le=1.0, description="Field goal percentage") | |
| fta: int = Field(..., ge=0, description="Career free throw attempts") | |
| ftm: int = Field(..., ge=0, description="Career free throws made") | |
| ft_pct: float = Field(..., ge=0.0, le=1.0, description="Free throw percentage") | |
| gp: int = Field(..., ge=0, description="Games played") | |
| gs: int = Field(..., ge=0, description="Games started") | |
| min: int = Field(..., ge=0, description="Career minutes") | |
| oreb: int = Field(..., ge=0, description="Career offensive rebounds") | |
| pf: int = Field(..., ge=0, description="Career personal fouls") | |
| pts: int = Field(..., ge=0, description="Career points") | |
| reb: int = Field(..., ge=0, description="Career rebounds") | |
| stl: int = Field(..., ge=0, description="Career steals") | |
| tov: int = Field(..., ge=0, description="Career turnovers") | |
| first_name: str = Field(..., max_length=50) | |
| last_name: str = Field(..., max_length=50) | |
| full_name_lower: str = Field(..., max_length=100) | |
| first_name_lower: str = Field(..., max_length=50) | |
| last_name_lower: str = Field(..., max_length=50) | |
| is_active: bool = Field(default=False) | |
| def from_db_row(cls, row: tuple[Any, ...]) -> "PlayerStats": | |
| """Create PlayerStats from a database row tuple. | |
| Args: | |
| row: Database row tuple in PLAYER_COLUMNS order | |
| Returns: | |
| PlayerStats instance | |
| """ | |
| return cls( | |
| full_name=row[0], | |
| ast=row[1], | |
| blk=row[2], | |
| dreb=row[3], | |
| fg3a=row[4], | |
| fg3m=row[5], | |
| fg3_pct=row[6] or 0.0, | |
| fga=row[7], | |
| fgm=row[8], | |
| fg_pct=row[9] or 0.0, | |
| fta=row[10], | |
| ftm=row[11], | |
| ft_pct=row[12] or 0.0, | |
| gp=row[13], | |
| gs=row[14], | |
| min=row[15], | |
| oreb=row[16], | |
| pf=row[17], | |
| pts=row[18], | |
| reb=row[19], | |
| stl=row[20], | |
| tov=row[21], | |
| first_name=row[22], | |
| last_name=row[23], | |
| full_name_lower=row[24], | |
| first_name_lower=row[25], | |
| last_name_lower=row[26], | |
| is_active=bool(row[27]) if row[27] is not None else False, | |
| ) | |
| class DifficultySettings(BaseModel): | |
| """Model for game difficulty settings.""" | |
| VALID_PRESETS: ClassVar[set[str]] = set(DIFFICULTY_PRESETS.keys()) | |
| name: str = Field(..., min_length=1) | |
| pts_threshold: int = Field(..., ge=0, description="Minimum career points") | |
| reb_threshold: int = Field(..., ge=0, description="Minimum career rebounds") | |
| ast_threshold: int = Field(..., ge=0, description="Minimum career assists") | |
| stl_threshold: int = Field(..., ge=0, description="Minimum career steals") | |
| def validate_preset_name(cls, v: str) -> str: | |
| """Validate that preset name is recognized.""" | |
| if v not in cls.VALID_PRESETS: | |
| raise ValueError( | |
| f"Unknown difficulty preset: {v}. " | |
| f"Valid options: {', '.join(sorted(cls.VALID_PRESETS))}" | |
| ) | |
| return v | |
| def from_preset(cls, preset_name: str) -> "DifficultySettings": | |
| """Create DifficultySettings from a named preset. | |
| Args: | |
| preset_name: Name of difficulty preset (e.g., "Regular", "Dream Team") | |
| Returns: | |
| DifficultySettings instance | |
| Raises: | |
| ValueError: If preset_name is not valid | |
| """ | |
| if preset_name not in DIFFICULTY_PRESETS: | |
| raise ValueError( | |
| f"Unknown difficulty preset: {preset_name}. " | |
| f"Valid options: {', '.join(sorted(DIFFICULTY_PRESETS.keys()))}" | |
| ) | |
| pts, reb, ast, stl = DIFFICULTY_PRESETS[preset_name] | |
| return cls( | |
| name=preset_name, | |
| pts_threshold=pts, | |
| reb_threshold=reb, | |
| ast_threshold=ast, | |
| stl_threshold=stl, | |
| ) | |
| def as_tuple(self) -> tuple[int, int, int, int]: | |
| """Return thresholds as tuple for backward compatibility. | |
| Returns: | |
| Tuple of (pts, reb, ast, stl) thresholds | |
| """ | |
| return ( | |
| self.pts_threshold, | |
| self.reb_threshold, | |
| self.ast_threshold, | |
| self.stl_threshold, | |
| ) | |