feat(async): complete AsyncMlb endpoint coverage (stats, persons, schedule, gamepace) - #327
Merged
Merged
Conversation
Ports the last four stats methods to AsyncMlb at strict parity with Mlb:
get_stats, get_player_stats, get_team_stats, and get_players_stats_for_game.
All four sync methods ended in the same copy-pasted tail -- short-circuit on
400-499, then create_split_data(data['stats']) if present and truthy, else {}.
That block existed four times in mlb_api.py. It moves to a shared
_parsers/stats.py::parse_split_stats(), following the pattern the rest of the
async port already uses, and both clients now call the one copy.
Also fixes a real bug on the sync side while collapsing those copies:
get_players_stats_for_game accepted **params and never passed ep_params to the
adapter, so every caller-supplied keyword was silently discarded before the
request was built. Both clients now forward them, covered by a named
regression test in the parity suite.
No new types, constants, or validation: an unrecognized stat type or group
still yields {} rather than raising, matching sync exactly. docs/public-api.md
notes that sharp edge alongside the newly supported methods.
Docstring corrections on Mlb.get_players_stats_for_game: it described game_id
as "list of stat types", person_id as "the team id", and its example called
get_player_stats_for_game, which is not a method.
Tests: 1016 passed (up from 974). tests/external_tests/stats/ 30 passed
against the live API, confirming the sync refactor did not move behavior.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ports get_persons, get_scheduled_games_by_date, and get_gamepace. AsyncMlb now
exposes every endpoint method Mlb does; the only remaining public difference is
that close() is spelled aclose().
Two more shared parsers, following the established pattern:
_parsers/schedules.py gains parse_scheduled_games(), and _parsers/gamepace.py
is new. Both replace inline loops/conditionals in mlb_api.py, so the two
clients share one copy.
Fixes an httpx/requests divergence that would have silently broken get_gamepace
on the async side. Mlb builds that request as endpoint="gamePace?season=2021"
with ep_params={"sportId": 1} and relies on Requests merging the endpoint's
query with the params. HTTPX does not merge -- passing params replaces a query
already on the URL -- so copying the sync idiom drops the season entirely and
silently returns whatever the unfiltered endpoint gives back. AsyncMlb passes
the season as an ordinary param instead, which produces a byte-identical
request. Verified against the live API: async and sync return equal GamePace
objects for season 2021.
tests/test_async_mlb.py's assert_matches_sync() had the same blind spot -- it
compared url.path against the raw endpoint string and would not have caught
this. It now splits an endpoint's embedded query and folds it into the expected
params, which is what Requests does, so the expectation is the merged query
either client must end up sending. This also subsumes the get_awards trailing-?
special case it previously carried.
get_scheduled_games_by_date preserves Mlb's quirk of returning None rather than
the [] its annotation promises when no date selector was given, asserted
explicitly in the parity suite rather than left implicit.
Tests: 1057 passed (up from 1016). tests/external_tests/ 148 passed, 1 skipped
against the live API.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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
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.
Closes #305.
Ports the last seven
Mlbmethods toAsyncMlb. Both clients now expose 41public methods; the only remaining difference is that
close()is spelledaclose().What's here
Two commits.
7d2f0ec— the stats group.get_stats,get_player_stats,get_team_stats,get_players_stats_for_game.113a8c0— the last three.get_persons,get_scheduled_games_by_date,get_gamepace.Scope was deliberately held to strict parity. No new types, constants, or
validation — the usability problems these endpoints have are real but are
tracked separately in #326 rather than mixed into a port.
The bug worth reviewing carefully
Mlb.get_gamepacebuilds its request like this:The season rides in the endpoint string;
sportIdand everything else arrivevia
ep_params. That works on the sync side because Requests merges anendpoint's existing query with the params it's given. HTTPX replaces it:
Copying the sync idiom into
AsyncMlbwould therefore have dropped the seasonsilently — no exception, just game pace data for the wrong scope.
AsyncMlbpasses the season as an ordinary param instead, producing an identical request.
Two follow-on notes:
get_awardsis the only other method that embeds a query in its endpointstring (
awards/{id}/recipients?). That query is empty, so merge-vs-replacemakes no difference there and it was never affected.
Mlbis left alone. Its idiom is fragile but correct under Requests, andchanging it is out of scope for a parity port.
The test helper had the same blind spot
tests/test_async_mlb.py::assert_matches_syncderives each expected requestfrom
Mlbitself, which is what makes these ports trustworthy. But it comparedurl.pathagainst the raw endpoint string, sogamePace?season=2021was neverparsed as a query and the drift above would have passed review.
It now splits an endpoint's embedded query and folds it into the expected
params — the same thing Requests does — so the expectation is the merged query
either client has to end up sending, regardless of how it built the URL. That
also subsumes the
get_awardstrailing-?special case it had been carrying.Other changes
Three new shared parsers, following the pattern the rest of the async port
uses:
_parsers/stats.py::parse_split_stats,_parsers/schedules.py::parse_scheduled_games, and_parsers/gamepace.py.Each replaces inline logic that existed only in
mlb_api.py; the stats onealone collapses four copy-pasted blocks into one.
A sync bugfix.
Mlb.get_players_stats_for_gameaccepted**paramsandnever passed
ep_params, so every caller-supplied keyword was silentlydiscarded. Both clients now forward them. This changes sync behavior, but in
the direction its own signature already advertised — agreed on before
implementing.
Two preserved quirks, both documented rather than corrected:
get_scheduled_games_by_dateis annotatedlist[ScheduleGames]but returnsNonewhen nothing selects a date. Asserted explicitly in the parity suite.{}for a 404, for a body with no stats, and foran unrecognized stat type or group. That last case is the subject of Make the stats endpoints easier to use #326.
Docstring corrections on
Mlb.get_players_stats_for_game, which describedperson_idas "the team id",game_idas "list of stat types", and whoseexample called
get_player_stats_for_game— not a method.Testing
148 passed, 1 skipped against the live API — this is what covers the sync
refactors, since
create_split_dataand the schedule/gamepace parsers now runthrough new code paths on real payloads.
Also verified directly against the live API that
get_gamepace,get_persons,and
get_scheduled_games_by_datereturn objects equal to their synccounterparts, rather than trusting the canned fixtures alone.
New coverage: 8 stats-parser tests, 7 gamepace-parser tests, 4
scheduled-games-parser tests, 24 async client tests, and 33 parity tests.
Risk
Low for the async additions — new methods, nothing existing changes shape.
Moderate for the two sync-side changes: the
get_players_stats_for_gameparamfix is a real behavior change, and the four stats methods plus
get_scheduled_games_by_date/get_gamepacenow route through extractedparsers. The external suite is the check that matters there and it's green.
🤖 Generated with Claude Code