-
Notifications
You must be signed in to change notification settings - Fork 22
Refactor/pydantic model migration #237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add pydantic to project dependencies and refresh lockfile to support upcoming model migration to Pydantic v2.
- Introduce MLBBaseModel (Pydantic v2) with extra="ignore" and populate_by_name - Export MLBBaseModel from models package - Add unit tests to verify ignoring unknown fields and alias population
BREAKING CHANGES: - All model field names are now snake_case (e.g., spring_league instead of springleague) - Class names standardized to PascalCase (e.g., TeamRecords instead of Teamrecords) - Models now raise ValidationError instead of TypeError for missing required fields Models converted: - Sport, Season - Venue, Location, TimeZone, FieldInfo, VenueDefaultCoordinates - League, LeagueRecord - Division - Team, TeamRecord, Record, OverallLeagueRecord, TypeRecords, DivisionRecords, LeagueRecords, Records - Standings, TeamRecords, Streak - Attendance, AttendanceRecords, AttendanceTotals, AttendanceHighLowGame, AttendanceGameType Key improvements: - All models inherit from MLBBaseModel with extra=ignore (handles new API fields gracefully) - Field aliases maintain API compatibility (e.g., Field(alias=springleague)) - populate_by_name=True allows both old and new names in constructors - Fixed several type mismatches (season: int, active: bool, elevation: int, etc.) - Updated all affected tests to use new field names
Models converted: - people/attributes: BatSide, PitchHand, Position, Status, Home, School - people/people: Person, Player, Coach, Batter, Pitcher, DraftPick - data/data: PitchBreak, PitchCoordinates, PitchData, HitCoordinates, HitData, CodeDesc, Violation, Count, PlayDetails Key changes: - All fields use snake_case with aliases for API compatibility - Player uses model_validator to handle position -> primary_position mapping - PlayDetails uses field_validator to convert empty dicts to None - Fixed type mismatches: current_team is Team (not str), launch_angle is float - Updated person tests to use new field names
Models converted: game/ (41 classes): - Game, MetaData, GameData, GameDataGame, GameDatetime, GameStatus - GameTeams, GameWeather, GameInfo, ReviewInfo, GameReview, GameFlags - GameProbablePitchers, MoundVisits, LiveData, GameDecisions, GameLeaders - Plays, Play, PlayAbout, PlayResult, PlayReviewDetails, PlayMatchup - PlayMatchupSplits, PlayEvent, PlayRunner, RunnerMovement, RunnerDetails - RunnerCredits, PlayByInning, PlayByInningHits, HitsByTeam, HitCoordinates - BoxScore, TopPerformer, BoxScoreTeam, BoxScoreTeams, BoxScoreOfficial - BoxScoreGameStatus, PlayersDictPerson, BoxScoreVL, BoxScoreTeamInfo - Linescore, LinescoreTeamScoring, LinescoreInning, LinescoreTeams - LinescoreOffense, LinescoreDefense gamepace/ (3 classes): - GamePace, GamePaceData, PrPortalCalculatedFields homerunderby/ (11 classes): - HomeRunDerby, Info, EventType, Status, Round, Matchup, Seed - Hits, HitData, Coordinates, TrajectoryData Key changes: - All fields use snake_case with aliases for API compatibility - Class names standardized to PascalCase (Gamepace -> GamePace, etc.) - Field validators handle empty dicts from API as None - Fixed type mismatches: TrajectoryData uses float, Coordinates optional - Updated mlb_api.py imports and return types - Updated all related tests to use new class/field names
Models converted: schedules/ (4 classes): - Schedule, ScheduleDates, ScheduleGames, ScheduleHomeAndAway, ScheduleGameTeam drafts/ (4 classes): - Round, DraftPick, DraftHome, DraftSchool awards/ (2 classes): - Awards, Award Key changes: - All fields use snake_case with aliases for API compatibility - Class names: Home -> DraftHome, School -> DraftSchool (avoid conflicts) - Fixed optional fields: DraftSchool.city/state/school_class, DraftHome.state - Field validators handle empty dicts from API as None - Updated all related tests to use new Pythonic field names - Changed TypeError expectations to ValidationError in tests
Models converted (8 files, 80+ classes): stats.py (base classes): - Stat, Split, PitchArsenalSplit, ExpectedStatistics, Sabermetrics - ZoneCodes, Zones, HotColdZones, Chart, SprayCharts - PitchArsenal, OutsAboveAverage, PlayerGameLogStat hitting.py: - SimpleHittingSplit, AdvancedHittingSplit, HittingPlay - HittingWinLoss, HittingHomeAndAway, HittingCareer, HittingSeason - HittingGameLog, HittingPlayLog, HittingPitchLog, HittingByMonth - HittingVsTeam, HittingVsPlayer, HittingExpectedStatistics, etc. pitching.py: - SimplePitchingSplit, AdvancedPitchingSplit, PitchingPlay - PitchingSeason, PitchingCareer, PitchingGameLog, PitchingLog - PitchingByMonth, PitchingHomeAndAway, PitchingWinLoss - PitchingVsTeam, PitchingVsPlayer, PitchingRankings, etc. fielding.py: - SimpleFieldingSplit, FieldingSeason, FieldingCareer - FieldingHomeAndAway, FieldingGameLog, FieldingByMonth, etc. catching.py: - SimpleCatchingSplit, CatchingSeason, CatchingCareer - CatchingGameLog, CatchingHomeAndAway, CatchingWinLoss, etc. running.py: - RunningOpponentsFaced game.py: - SimpleGameStats, SeasonGame, CareerGame - CareerRegularSeasonGame, CareerPlayoffsGame Key changes: - All fields use snake_case with aliases for API compatibility - Fixed type mismatches: stolenbasepercentage, groundoutstoairouts, atbatsperhomerun, whiffpercentage are strings not ints - Game model fields made optional for stats endpoint compatibility - Field validators handle empty dicts from API as None - Updated all stats tests to use new Pythonic field names (totalsplits -> total_splits)
- Add "Working with Pydantic Models" section with model_dump() and model_dump_json() examples - Update all examples to use snake_case field names - Simplify examples using f-strings and direct field access - Fix typos and clean up language - Add note about Pydantic in Getting Started section
6af2185 to
0734694
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Why
Migrate from Python dataclasses to Pydantic v2 for:
__post_init__)snake_casefield names (while maintaining API compatibility via aliases)What
Complete migration of 150+ model classes across all modules:
MLBBaseModelbase class withextra="ignore",populate_by_name=TruecamelCasetosnake_case(e.g.,gamepk→game_pk)Field(alias="...")for API compatibility__post_init__with Pydantic's automatic model instantiationfield_validators to handle empty dicts{}from API asNonestolenbasepercentageisstrnotint)Gamepace→GamePace,Homerunderby→HomeRunDerby103 files changed, 5,196 insertions, 5,245 deletions
Tests
snake_casefield namestest_base_model.pyforMLBBaseModelbehaviorRisk and impact
Risk Level: Normal
camelCasetosnake_caseAttributeErrorif using old field names after upgrade