Repository navigation
Add bulk player-season hitting ingestion #60
Description
Summary
Add a season-wide player hitting ingestion workflow so player stats can be viewed from the local database without manually importing each player with import_player_season.py --player-id ....
The existing one-player importer should remain available as a targeted repair/debug tool.
Motivation
The current player data flow requires an explicit command per player before that player's hitting statistics are available locally. That does not scale to a usable Player UI.
For an MLB season with roughly 1,400+ cataloged players, the application needs a bulk ingestion path that can populate season hitting statistics efficiently and deterministically.
Proposed command
poetry run python scripts/import_player_hitting_season.py --season 2026Proposed behavior
- Require or verify the player catalog for the requested season.
- Fetch season-wide MLB hitting statistics using the bulk stats endpoint exposed by
python-mlb-statsapi. - Paginate through the complete result set using the supported
limit/offsetparameters. - Normalize bulk rows into the existing
PlayerSeasonHittingdomain model where possible. - Upsert all valid season hitting rows into SQLite.
- Do not refetch player identity for every player; identity should come from the already-imported player catalog.
- Record enough ingestion/completeness state to distinguish a complete refresh from a partial or failed import.
- Print a concise summary of fetched, inserted, updated, unchanged, skipped, and failed rows.
Investigation required
Before implementation, perform a live audit of the bulk MLB stats response and document:
- response pagination behavior and practical page size;
- whether traded players return:
- one full-season aggregate row,
- team-specific splits,
- or both;
- how players with no usable hitting statistics are represented;
- whether duplicate player-season rows can appear;
- whether all rows contain the counting-stat fields required by
PlayerSeasonHitting.
The importer should refuse ambiguous response shapes rather than silently choosing an arbitrary split.
Architecture constraints
- Browser requests remain database-only.
- MLB network access remains explicit ingestion work.
- Reuse service-layer functions rather than putting baseball normalization logic in the CLI script.
- Keep
scripts/import_player_season.pyas a targeted single-player import/repair command. - Bulk ingestion must be idempotent.
- Missing or unavailable hitting data must not be silently converted to zero.
Acceptance criteria
- Add a documented bulk player hitting ingestion design/audit.
- Add
scripts/import_player_hitting_season.py. - Support
--season <year>. - Use season-wide bulk MLB stats retrieval rather than one network request per player.
- Implement complete pagination.
- Reuse existing catalog identity data rather than refetching identity per player.
- Correctly handle traded-player aggregate/split behavior based on audited MLB response shape.
- Skip or explicitly classify players with no hitting statistics.
- Persist player hitting rows idempotently.
- Persist/derive explicit completeness state for the season-wide hitting import.
- Exit non-zero when the season-wide refresh cannot be considered complete.
- Add offline deterministic tests for pagination, normalization, duplicates/ambiguity, partial failure, and reruns.
- Update README/player documentation with the new preferred ingestion command.
Future integration
Once this exists, the season bootstrap workflow from #59 can incorporate it:
migrations
→ league/team data
→ player catalog
→ bulk player hitting
The intended developer experience becomes:
poetry run python scripts/bootstrap_season.py --season 2026
poetry run uvicorn app.main:app --reloadAfter bootstrap, selecting a hitter in the UI should not require any additional MLB API call or manual per-player import.
Activity