Coverage for models/post_match.py: 100.00%
31 statements
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-13 11:37 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2026-04-13 11:37 +0000
1"""
2Post-Match Stats Pydantic models.
4Models for recording goals, substitutions, and player stats
5after a match has been completed.
6"""
8from pydantic import BaseModel, Field
11class PostMatchGoal(BaseModel):
12 """Model for recording a post-match goal event."""
14 team_id: int = Field(..., description="ID of the team that scored")
15 player_id: int | None = Field(None, description="ID of the goal scorer from roster (preferred)")
16 player_name: str | None = Field(None, max_length=200, description="Name of goal scorer (when no roster)")
17 match_minute: int = Field(..., ge=1, le=130, description="Minute the goal was scored")
18 extra_time: int | None = Field(None, ge=1, description="Stoppage time minutes (e.g., 3 for 45+3)")
19 message: str | None = Field(None, max_length=500, description="Optional goal description")
22class PostMatchSubstitution(BaseModel):
23 """Model for recording a post-match substitution event."""
25 team_id: int = Field(..., description="ID of the team making the substitution")
26 player_in_id: int = Field(..., description="ID of the player coming on")
27 player_out_id: int = Field(..., description="ID of the player coming off")
28 match_minute: int = Field(..., ge=1, le=130, description="Minute the substitution occurred")
29 extra_time: int | None = Field(None, ge=1, description="Stoppage time minutes")
32class PostMatchCard(BaseModel):
33 """Model for recording a post-match card event (yellow or red)."""
35 team_id: int = Field(..., description="ID of the team the player belongs to")
36 player_id: int | None = Field(None, description="ID of the carded player from roster (preferred)")
37 player_name: str | None = Field(None, max_length=200, description="Name of player (when no roster)")
38 card_type: str = Field(..., pattern="^(yellow_card|red_card)$", description="Type of card: yellow_card or red_card")
39 match_minute: int = Field(..., ge=1, le=130, description="Minute the card was given")
40 extra_time: int | None = Field(None, ge=1, description="Stoppage time minutes")
41 message: str | None = Field(None, max_length=500, description="Optional description (e.g., reason for card)")
44class PlayerStatEntry(BaseModel):
45 """Model for a single player's match stats update."""
47 player_id: int = Field(..., description="Player ID from roster")
48 started: bool = Field(..., description="Whether the player started the match")
49 played: bool = Field(..., description="Whether the player participated in the match")
50 minutes_played: int = Field(..., ge=0, le=130, description="Total minutes played")
51 yellow_cards: int = Field(0, ge=0, le=2, description="Yellow cards received (0-2)")
52 red_cards: int = Field(0, ge=0, le=1, description="Red cards received (0-1)")
55class BatchPlayerStatsUpdate(BaseModel):
56 """Model for batch-updating player stats for a team in a match."""
58 players: list[PlayerStatEntry] = Field(..., min_length=1, description="List of player stat entries")