From 8b998140c5dba70b0f56a35144056578e04798b7 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Sun, 23 Aug 2026 12:57:05 -0700 Subject: [PATCH 01/17] docs: add current async usage guide --- docs/async.md | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 docs/async.md diff --git a/docs/async.md b/docs/async.md new file mode 100644 index 0000000..fc59625 --- /dev/null +++ b/docs/async.md @@ -0,0 +1,153 @@ +# Async Usage + +`AsyncMlb` is the public asynchronous client for `python-mlb-statsapi` 1.1. +It requires the optional `async` extra. + +## Installation + +```bash +python3 -m pip install "python-mlb-statsapi[async]" +``` + +A synchronous-only install remains unchanged and does not require HTTPX. + +## Quick start + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + player = await mlb.get_person(664034) + team = await mlb.get_team(136) + + print(player.full_name) + print(team.name) + + +asyncio.run(main()) +``` + +Use `async with` when possible so library-owned HTTP resources are closed when +the block exits. If a context manager is not practical, explicit cleanup is +also supported: + +```python +mlb = AsyncMlb() +try: + player = await mlb.get_person(664034) +finally: + await mlb.aclose() +``` + +Repeated `aclose()` calls are safe. + +## Concurrent requests + +One `AsyncMlb` instance supports concurrent in-flight requests on the same +event loop. Concurrency is controlled by the caller. + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + player, team = await asyncio.gather( + mlb.get_person(664034), + mlb.get_team(136), + ) + + return player, team + + +player, team = asyncio.run(main()) +``` + +`AsyncMlb` does not create hidden background tasks or automatic request fanout. +Cross-event-loop use of the same client is not promised. + +## Supported endpoints + +The async surface is intentionally smaller than the synchronous `Mlb` surface +while 1.1 support is being expanded. The currently supported awaitable endpoint +methods on `release/1.1.0` are: + +```text +get_team(...) +get_teams(...) +get_person(...) +get_people(...) +get_schedule(...) +``` + +Where an async endpoint is supported, it returns the same Pydantic model types +and follows the same public HTTP/error behavior as the matching synchronous +method. + +For the authoritative list and signatures, see the +[public API contract](public-api.md#asyncmlb-public-client). + +## Error handling + +The public exception hierarchy is shared with the synchronous client: + +```python +from mlbstatsapi import ( + AsyncMlb, + MlbDecodeError, + MlbHttpError, + MlbTimeoutError, + MlbTransportError, +) + + +async def get_player(): + try: + async with AsyncMlb() as mlb: + return await mlb.get_person(664034) + except MlbTimeoutError: + print("The MLB API timed out") + except MlbTransportError: + print("The request could not reach the MLB API") + except MlbHttpError as exc: + print(exc.status_code, exc.reason) + except MlbDecodeError: + print("The MLB API returned invalid JSON") +``` + +`strict_http=True` is the default. Existing endpoint-specific 404 behavior is +preserved. See the [HTTP transport documentation](http-transport.md) for the +complete status, timeout, retry, and compatibility-mode contract. + +## Custom HTTPX client + +Advanced callers may inject their own `httpx.AsyncClient`: + +```python +import httpx + +from mlbstatsapi import AsyncMlb + + +client = httpx.AsyncClient() +try: + async with AsyncMlb(client=client) as mlb: + player = await mlb.get_person(664034) +finally: + await client.aclose() +``` + +An injected client remains caller-owned and is not closed by `AsyncMlb`. + +## Documentation boundaries + +- [README](../README.md) — installation and quick-start examples +- [Usage examples](examples.md) — longer synchronous examples +- [Public API contract](public-api.md) — supported symbols, signatures, and endpoint coverage +- [HTTP transport](http-transport.md) — timeouts, retries, errors, and compatibility behavior From faf2ab4a6adb23f1f3379057fac3d342144f97eb Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Sun, 23 Aug 2026 12:57:31 -0700 Subject: [PATCH 02/17] docs: restore focused usage examples --- docs/examples.md | 173 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 docs/examples.md diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 0000000..817afd8 --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,173 @@ +# Usage Examples + +This document collects the longer usage examples that previously lived in the README. The README keeps a short quick start; this guide is the extended tour. + +Every example in this file uses the synchronous `Mlb` client. Async usage is documented separately in [async.md](async.md). + +For return-object structure and endpoint details see the [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki). For the supported method list, parameters, and return shapes see the [public API contract](public-api.md). For transport behavior see the [HTTP transport documentation](http-transport.md). + +## Working with Pydantic Models + +All returned objects are Pydantic models, giving you access to serialization and validation helpers. + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + player = mlb.get_person(664034) + +print(player.full_name) +print(player.model_dump(exclude_none=True)) +print(player.model_dump_json(indent=2)) +``` + +## Players and teams + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + player_id = mlb.get_people_id("Ty France")[0] + team_id = mlb.get_team_id("Seattle Mariners")[0] + + player = mlb.get_person(player_id) + team = mlb.get_team(team_id) + +print(player.full_name) +print(team.name) +``` + +## Player stats + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + player_id = mlb.get_people_id("Ty France")[0] + stats = mlb.get_player_stats( + player_id, + stats=["season", "career"], + groups=["hitting", "pitching"], + season=2022, + ) + +season_hitting = stats["hitting"]["season"] +for split in season_hitting.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +## Team stats + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + team_id = mlb.get_team_id("Seattle Mariners")[0] + stats = mlb.get_team_stats( + team_id, + stats=["season", "seasonAdvanced"], + groups=["hitting"], + season=2022, + ) + +season_hitting = stats["hitting"]["season"] +for split in season_hitting.splits: + print(split.stat.model_dump_json(indent=2, exclude_none=True)) +``` + +## Schedule + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + schedule = mlb.get_schedule(date="2022-10-13") + +for date in schedule.dates: + for game in date.games: + print(game.game_pk, game.status.detailed_state) +``` + +## Game data + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + game = mlb.get_game(662242) + play_by_play = mlb.get_game_play_by_play(662242) + line_score = mlb.get_game_line_score(662242) + box_score = mlb.get_game_box_score(662242) +``` + +## Rosters + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + players = mlb.get_team_roster(136) + coaches = mlb.get_team_coaches(136) + +for player in players: + print(f"#{player.jersey_number} {player.person.full_name}") + +for coach in coaches: + print(f"{coach.person.full_name}: {coach.title}") +``` + +## Draft + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + draft = mlb.get_draft("2019") + +for pick in draft[0].picks: + print(f"Round {pick.pick_round}, Pick {pick.pick_number}: {pick.person.full_name}") +``` + +## Awards + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + retired_numbers = mlb.get_awards(award_id="RETIREDUNI_108") + +for recipient in retired_numbers.awards: + print(f"{recipient.player.full_name}: {recipient.name} ({recipient.date})") +``` + +## Venue, division, league, and season + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + venue_id = mlb.get_venue_id("PNC Park")[0] + venue = mlb.get_venue(venue_id) + division = mlb.get_division(200) + league = mlb.get_league(103) + season = mlb.get_season(2018) + +print(venue.name) +print(division.name) +print(league.name) +print(season.season_id) +``` + +## Standings + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + standings = mlb.get_standings(103, 2018) + +for record in standings: + print(f"Division: {record.division.name}") + for team in record.team_records: + print(f" {team.team.name}: {team.wins}-{team.losses}") +``` From a8b38e61fe6855199779d2ca71edbc9d63a49346 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Sun, 23 Aug 2026 12:58:19 -0700 Subject: [PATCH 03/17] docs: rebase README refactor onto 1.1 async surface --- README.md | 843 ++++++++---------------------------------------------- 1 file changed, 125 insertions(+), 718 deletions(-) diff --git a/README.md b/README.md index 141379d..c23d18f 100644 --- a/README.md +++ b/README.md @@ -9,833 +9,240 @@ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-mlb-statsapi) ![GitHub](https://img.shields.io/github/license/zero-sum-seattle/python-mlb-statsapi) -
+### [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [Examples](docs/examples.md) | [Async](docs/async.md) | [Public API](docs/public-api.md) | [MLB Stats API](https://statsapi.mlb.com/) -### *Copyright Notice* -This package and its authors are not affiliated with MLB or any MLB team. This API wrapper interfaces with MLB's Stats API. Use of MLB data is subject to the notice posted at http://gdx.mlb.com/components/copyright.txt. +
-###### This is an educational project - Not for commercial use. +`python-mlb-statsapi` provides Python access to the MLB Stats API for teams, players, schedules, games, stats, and more. +Returned objects are built with [Pydantic](https://docs.pydantic.dev/), and model fields use Python `snake_case` names. -![MLB Stats API](https://user-images.githubusercontent.com/2068393/203456246-dfdbdf0f-1e43-4329-aaa9-1c4008f9800d.jpg) +Version 1.1 adds first-class async support through `AsyncMlb` while keeping the existing synchronous `Mlb` API available without code changes for sync users. -## Getting Started +### Copyright Notice -*Python-mlb-statsapi* is a Python library that provides access to the MLB Stats API, allowing developers to retrieve information related to MLB teams, players, stats, and more. Written in Python 3.10+. +This package and its authors are not affiliated with MLB or any MLB team. This API wrapper interfaces with MLB's Stats API. Use of MLB data is subject to the notice posted at http://gdx.mlb.com/components/copyright.txt. -All models are built with [Pydantic](https://docs.pydantic.dev/) for robust data validation and serialization. Field names follow Python's `snake_case` convention for a more Pythonic experience. +###### This is an educational project - Not for commercial use. -For detailed documentation, check out the [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) which contains information on return objects, endpoint structure, usage examples, and more. +![MLB Stats API](https://user-images.githubusercontent.com/2068393/203456246-dfdbdf0f-1e43-4329-aaa9-1c4008f9800d.jpg) +## Installation -
+### Synchronous client + +```bash +python3 -m pip install python-mlb-statsapi +``` -### [Examples](#examples) | [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [API](https://statsapi.mlb.com/) +### Async support -
+Install the optional `async` extra to use `AsyncMlb` and `AsyncMlbDataAdapter`: -## Installation ```bash -python3 -m pip install python-mlb-statsapi +python3 -m pip install "python-mlb-statsapi[async]" ``` -### Python support +The async extra installs HTTPX. Python 3.10 or newer is required. | Claim | Value | | --- | --- | -| Minimum declared Python version (`Requires-Python`) | `>=3.10` | +| Minimum Python version | `>=3.10` | | CI-validated versions | 3.10, 3.11, 3.12, 3.13, 3.14 | -The minimum declared Python version is 3.10 and the CI-validated versions are -3.10 through 3.14. There is no upper Python bound. Prerelease interpreters are -excluded from the required test matrix and are not claimed as supported. +See [Python support](docs/public-api.md#python-support) for the complete policy. ## Quick Start -```python ->>> import mlbstatsapi ->>> mlb = mlbstatsapi.Mlb() - ->>> mlb.get_people_id("Ty France") -[664034] ->>> player = mlb.get_person(664034) ->>> print(player.full_name) -Ty France +### Sync ->>> stats = ['season', 'seasonAdvanced'] ->>> groups = ['hitting'] ->>> params = {'season': 2022} ->>> mlb.get_player_stats(664034, stats, groups, **params) -{'hitting': {'season': Stat, 'seasonAdvanced': Stat }} +```python +from mlbstatsapi import Mlb ->>> mlb.get_team_id("Seattle Mariners") -[136] +with Mlb() as mlb: + player = mlb.get_person(664034) + team = mlb.get_team(136) ->>> team = mlb.get_team(136) ->>> print(team.name, team.franchise_name) -Seattle Mariners Seattle +print(player.full_name) +print(team.name) ``` -## HTTP Sessions, Timeouts, Retries, and Error Behavior - -Version 0.8.0 added shared HTTP Sessions, explicit timeouts, optional Session injection, bounded retries, and structured transport exceptions. Version 0.9.0 made that transport configurable with a public retry policy, richer `MlbHttpError` context, compatibility warnings, and a versioned User-Agent. Version 1.0.0 makes strict HTTP handling the default and documents the stable public API contract. +### Async -The `Mlb` client remains synchronous. Shared Sessions pool reusable connections; they do not cache MLB response bodies, and the client does not enable response caching by default. +```python +import asyncio -For the complete reference see the [HTTP transport documentation](docs/http-transport.md). For what changed in this release see the [1.0.0 release notes](docs/releases/1.0.0.md). For the stable public API boundary see the [public API contract](docs/public-api.md). +from mlbstatsapi import AsyncMlb -### Upgrading to version 1.0 -`Mlb()` now uses strict HTTP handling by default. It is equivalent to `Mlb(strict_http=True)`. +async def main(): + async with AsyncMlb() as mlb: + player = await mlb.get_person(664034) + team = await mlb.get_team(136) -```text -Mlb() now uses strict HTTP handling by default -Final non-404 4xx responses raise MlbHttpError -404 keeps endpoint-specific None / [] / {} behavior -Final 5xx still raises MlbHttpError -Timeouts still raise MlbTimeoutError -Transport failures still raise MlbTransportError -Successful invalid JSON still raises MlbDecodeError -``` + print(player.full_name) + print(team.name) -Recommended version 1.0 usage: -```python -import mlbstatsapi - -try: - with mlbstatsapi.Mlb() as mlb: - player = mlb.get_person(664034) -except mlbstatsapi.MlbHttpError as exc: - print(exc.status_code) - print(exc.reason) - print(exc.url) +asyncio.run(main()) ``` -Temporary compatibility opt-out while migrating: +See [Async usage](docs/async.md) for lifecycle, concurrency, custom HTTPX clients, and the current async endpoint list. -```python -import mlbstatsapi +## Sync or Async? -with mlbstatsapi.Mlb(strict_http=False) as mlb: - player = mlb.get_person(664034) -``` +| | `Mlb` | `AsyncMlb` | +| --- | --- | --- | +| HTTP library | Requests | HTTPX | +| Context manager | `with Mlb()` | `async with AsyncMlb()` | +| Request | `mlb.get_team(...)` | `await mlb.get_team(...)` | +| Explicit cleanup | `mlb.close()` | `await mlb.aclose()` | -`strict_http=False` is a temporary migration opt-out and an explicit request for historical 0.9 behavior. It is not the recommended long-term 1.0 configuration. See [Migrating from 0.9.x to 1.0](docs/http-transport.md#migrating-from-09x-to-10) for the full process, warning-as-error guidance, and before-and-after examples. +Where an async endpoint is supported, both clients return the same Pydantic models and follow the same public HTTP/error behavior. -### Recommended context-manager usage +The async surface is still smaller than the full synchronous API while 1.1 coverage is expanded. The [public API contract](docs/public-api.md#asyncmlb-public-client) is the authoritative list of supported async methods. -Prefer a context manager so library-owned HTTP resources are closed when the block exits, including when the block exits because of an exception: +## Concurrent Async Requests -```python -import mlbstatsapi +`AsyncMlb` supports concurrent requests on the same event loop. Concurrency is controlled by the caller. -with mlbstatsapi.Mlb() as mlb: - player = mlb.get_person(664034) - team = mlb.get_team(136) -``` - -One `Mlb` client uses one shared `requests.Session`. The v1 and v1.1 adapters share that Session, so repeated requests can reuse pooled connections. A Session manages a pool of reusable connections; it is not one permanent network connection. +```python +import asyncio -Callers who do not use a context manager may call `mlb.close()` instead. Repeated `close()` calls are safe. Closing a client only closes a Session the library created; a caller-injected Session is left open for its owner. +from mlbstatsapi import AsyncMlb -### Compatibility mode -Callers who need historical 0.9 empty-result behavior for final non-404 4xx responses can pass `strict_http=False`. That path emits `MlbHttpCompatibilityWarning` exactly once per suppressed final response, does not change 404 handling, and does not suppress final 5xx, timeout, transport, or decode failures. +async def main(): + async with AsyncMlb() as mlb: + player, team = await asyncio.gather( + mlb.get_person(664034), + mlb.get_team(136), + ) -The category inherits from `FutureWarning`, so it stays visible under default Python warning filters. Applications can promote only this package category to an error: + return player, team -```python -import warnings -import mlbstatsapi -warnings.filterwarnings( - "error", - category=mlbstatsapi.MlbHttpCompatibilityWarning, -) +player, team = asyncio.run(main()) ``` -Filter on `mlbstatsapi.MlbHttpCompatibilityWarning` specifically rather than disabling all warnings or all `FutureWarning` instances, which would also hide unrelated notices from other libraries. Prefer removing `strict_http=False` and catching `MlbHttpError` over permanently ignoring the warning. - -### Custom timeouts - -Every request uses an explicit timeout. The defaults are: +`AsyncMlb` does not create hidden background tasks or automatic request fanout. -```text -Connection timeout: 3.05 seconds -Read timeout: 30 seconds -``` - -The read timeout is the maximum wait while reading response data. It is not one absolute total duration for the complete request. +## Common Methods -Use a scalar to apply the same value to both connect and read phases: +### Players ```python -import mlbstatsapi - -with mlbstatsapi.Mlb(timeout=10) as mlb: - player = mlb.get_person(664034) +player = mlb.get_person(664034) +players = mlb.get_people() +player_ids = mlb.get_people_id("Ty France") ``` -Or provide separate connection and read timeouts: +### Teams ```python -import mlbstatsapi - -with mlbstatsapi.Mlb( - timeout=(5.0, 60.0), -) as mlb: - player = mlb.get_person(664034) +team = mlb.get_team(136) +teams = mlb.get_teams() +team_ids = mlb.get_team_id("Seattle Mariners") ``` -```text -5.0 seconds: connection timeout -60.0 seconds: read timeout -``` - -### Injecting a custom Session - -Advanced callers may inject a caller-owned Session: +### Stats ```python -import requests -import mlbstatsapi - -session = requests.Session() -session.headers.update({ - "User-Agent": "my-baseball-project/1.0", -}) - -try: - with mlbstatsapi.Mlb(session=session) as mlb: - player = mlb.get_person(664034) -finally: - session.close() -``` - -Ownership rules: - -```text -Library-created Session - The library configures and closes it -Caller-injected Session - The caller configures and closes it +stats = mlb.get_player_stats( + 664034, + stats=["season", "career"], + groups=["hitting"], + season=2022, +) ``` -`Mlb.close()` does not close a caller-injected Session, and exiting `with Mlb(session=session)` does not close the injected Session either. The library does not replace or reconfigure adapters or headers on an injected Session. Callers control custom retry, TLS, proxy, header, and adapter configuration. - -### Reusing the retry policy on a caller-managed Session +Higher-level stats helpers remain on the synchronous `Mlb` client in the current 1.1 async surface. -`create_retry_policy()` remains public. It returns a new instance of the same tested policy the library mounts on Sessions it creates, so a caller-managed Session can opt in to identical retry behavior: +### Schedule ```python -import requests -import mlbstatsapi - -session = requests.Session() -adapter = requests.adapters.HTTPAdapter( - max_retries=mlbstatsapi.create_retry_policy(), -) -session.mount("https://", adapter) -session.mount("http://", adapter) - -try: - with mlbstatsapi.Mlb(session=session) as mlb: - player = mlb.get_person(664034) -finally: - session.close() +schedule = mlb.get_schedule(date="2022-10-13") ``` -* The caller mounts the adapters -* The caller closes the injected Session -* The library never reconfigures an injected Session +`get_schedule` is available on both `Mlb` and `AsyncMlb`. -### Versioned User-Agent +Longer runnable examples live in [docs/examples.md](docs/examples.md). -A Session created by the library sends a package-specific User-Agent: +## HTTP and Error Behavior -```text -python-mlb-statsapi/ -``` - -For this release's currently declared package metadata that resolves to `python-mlb-statsapi/1.0.1`. The version is read from the installed distribution metadata, so it always matches the installed release. Only the `User-Agent` header is set; other Requests defaults such as `Accept-Encoding` remain intact, and the header carries no identifiers beyond the package name and version. +Both clients use explicit timeouts, structured exceptions, and pooled HTTP connections. `strict_http=True` is the default. Final non-404 4xx responses raise `MlbHttpError`, while existing endpoint-specific 404 behavior is preserved. -Headers on a caller-injected Session are left untouched, so applications that set their own User-Agent keep it. +The main transport exceptions are: -### Structured exception handling +* `MlbHttpError` +* `MlbTimeoutError` +* `MlbTransportError` +* `MlbDecodeError` ```python -import mlbstatsapi +from mlbstatsapi import Mlb, MlbHttpError, MlbTimeoutError try: - with mlbstatsapi.Mlb() as mlb: + with Mlb() as mlb: player = mlb.get_person(664034) -except mlbstatsapi.MlbTimeoutError: +except MlbTimeoutError: print("The MLB API timed out") -except mlbstatsapi.MlbTransportError: - print("The request could not reach the MLB API") -except mlbstatsapi.MlbHttpError as exc: - print(exc.method) - print(exc.status_code) - print(exc.reason) - print(exc.url) - print(exc.response_data) - print(exc.body_excerpt) -except mlbstatsapi.MlbDecodeError: - print("The MLB API returned invalid JSON") +except MlbHttpError as exc: + print(exc.status_code, exc.reason) ``` -* `MlbTimeoutError` represents connection and read timeouts -* `MlbTransportError` represents other request transport failures -* `MlbHttpError` represents an unexpected final HTTP response -* `MlbDecodeError` represents invalid JSON in a successful response +For timeouts, retries, compatibility mode, ownership rules, and transport details, see [docs/http-transport.md](docs/http-transport.md). -`MlbHttpError` exposes `method`, `status_code`, `reason`, `url`, `response_data`, and `body_excerpt`. `response_data` holds the decoded JSON dictionary or list when the error body contains one, and is `None` otherwise. `body_excerpt` is a bounded excerpt of the response text, capped at 500 characters. Complete response bodies are never automatically logged, and `str(exc)` stays concise. +## Working with Models -### Backward-compatible exception handling - -All new transport exceptions inherit from `TheMlbStatsApiException`, so existing broad exception handling remains compatible: +Every returned model object uses Pydantic and Python-style `snake_case` fields: ```python -import mlbstatsapi - -try: - with mlbstatsapi.Mlb() as mlb: - player = mlb.get_person(664034) -except mlbstatsapi.TheMlbStatsApiException: - print("The MLB request failed") -``` - -### Default retry behavior - -Library-created Sessions automatically retry temporary GET failures for: - -```text -429 -500 -502 -503 -504 -``` - -```text -Initial request: 1 -Maximum retries: 3 -Maximum total attempts: 4 -Backoff factor: 0.5 -Retry-After respected: yes -``` - -Only GET requests are retried, and retries are bounded. Ordinary client errors such as 400, 401, 403, and 404 are not retried. Invalid JSON and Pydantic validation failures are not retried. Retries improve resilience for transient failures, but they do not guarantee success. The retry values are unchanged from versions 0.8.0 and 0.9.0. The version 1.0 strict default does not change retry or Session behavior. - -### Existing 404 compatibility - -Version 1.0.0 preserves existing endpoint-specific not-found behavior under both the default and `strict_http=False`. Depending on the endpoint, a 404 may still produce: - -```text -None -[] -{} -``` - -Not every 404 raises `MlbHttpError`, and the strict default does not change that. - -### HTTP behavior at a glance +from mlbstatsapi import Mlb -| Final response | Default 1.0 behavior | Explicit compatibility mode | -| -------------- | -------------------- | --------------------------- | -| Successful 2xx | Normal result | Normal result | -| Non-404 4xx | `MlbHttpError` | Warning and historical empty result | -| 404 | Existing endpoint behavior | Existing endpoint behavior | -| Final 429 | `MlbHttpError` after retries | Warning and historical empty result after retries | -| Final 5xx | `MlbHttpError` | `MlbHttpError` | - -See the [HTTP transport documentation](docs/http-transport.md) for the complete retry policy, Session ownership rules, warning behavior, cleanup behavior, and migration guidance, and the [1.0.0 release notes](docs/releases/1.0.0.md) for the release summary. - -## Working with Pydantic Models - -All returned objects are Pydantic models, giving you access to powerful serialization and validation features. - -### Convert to Dictionary -```python ->>> player = mlb.get_person(664034) ->>> player.model_dump() -{'id': 664034, 'full_name': 'Ty France', 'link': '/api/v1/people/664034', ...} - -# Exclude None values ->>> player.model_dump(exclude_none=True) -{'id': 664034, 'full_name': 'Ty France', 'link': '/api/v1/people/664034', ...} - -# Include only specific fields ->>> player.model_dump(include={'id', 'full_name', 'primary_position'}) -{'id': 664034, 'full_name': 'Ty France', 'primary_position': Position(...)} -``` - -### Convert to JSON -```python ->>> player = mlb.get_person(664034) ->>> player.model_dump_json() -'{"id": 664034, "full_name": "Ty France", "link": "/api/v1/people/664034", ...}' - -# Pretty print with indentation ->>> print(player.model_dump_json(indent=2)) -{ - "id": 664034, - "full_name": "Ty France", - "link": "/api/v1/people/664034", - ... -} -``` +with Mlb() as mlb: + player = mlb.get_person(664034) -### Access Fields with Snake Case Names -```python ->>> player = mlb.get_person(664034) ->>> player.full_name # Not fullName -'Ty France' ->>> player.primary_position # Not primaryPosition -Position(code='3', name='First Base', ...) ->>> player.bat_side # Not batSide -CodeDesc(code='R', description='Right') +print(player.full_name) # not fullName +print(player.model_dump(exclude_none=True)) +print(player.model_dump_json(indent=2)) ``` ## Documentation -### [People, Person, Players, Coaches](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-People) -* `Mlb.get_people_id(self, fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params)` - Return Person Id(s) from fullname -* `Mlb.get_person(self, player_id: int, **params)` - Return Person Object from Id -* `Mlb.get_people(self, sport_id: int = 1, **params)` - Return all Players from Sport -### [Draft](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Draft(round)) -* `Mlb.get_draft(self, year_id: int, **params)` - Return a draft for a given year -### [Awards](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Award) -* `Mlb.get_awards(self, award_id: int, **params)` - Return award recipients for a given award -### [Teams](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Team) -* `Mlb.get_team_id(self, team_name: str, search_key: str = 'name', **params)` - Return Team Id(s) from name -* `Mlb.get_team(self, team_id: int, **params)` - Return Team Object from Team Id -* `Mlb.get_teams(self, sport_id: int = 1, **params)` - Return all Teams for Sport -* `Mlb.get_team_coaches(self, team_id: int, **params)` - Return coaching roster for team for current or specified season -* `Mlb.get_team_roster(self, team_id: int, **params)` - Return player roster for team for current or specified season -### [Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) -* `Mlb.get_player_stats(self, person_id: int, stats: list, groups: list, **params)` - Return stats by player id, stat type and groups -* `Mlb.get_team_stats(self, team_id: int, stats: list, groups: list, **params)` - Return stats by team id, stat types and groups -* `Mlb.get_stats(self, stats: list, groups: list, **params: dict)` - Return stats by stat type and group args -* `Mlb.get_players_stats_for_game(self, person_id: int, game_id: int, **params)` - Return player stats for a game -### [Gamepace](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Gamepace) -* `Mlb.get_gamepace(self, season: str, sport_id=1, **params)` - Return pace of game metrics for specific sport, league or team. -### [Venues](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Venue) -* `Mlb.get_venue_id(self, venue_name: str, search_key: str = 'name', **params)` - Return Venue Id(s) -* `Mlb.get_venue(self, venue_id: int, **params)` - Return Venue Object from venue Id -* `Mlb.get_venues(self, **params)` - Return all Venues -### [Sports](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Sport) -* `Mlb.get_sport(self, sport_id: int, **params)` - Return a Sport object from Id -* `Mlb.get_sports(self, **params)` - Return all Sports -* `Mlb.get_sport_id(self, sport_name: str, search_key: str = 'name', **params)`- Return Sport Id from name -### [Schedules](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) -* `Mlb.get_schedule(self, date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params)` - Return a Schedule -### [Divisions](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Division) -* `Mlb.get_division(self, division_id: int, **params)` - Return a Division -* `Mlb.get_divisions(self, **params)` - Return all Divisions -* `Mlb.get_division_id(self, division_name: str, search_key: str = 'name', **params)` - Return Division Id(s) from name -### [Leagues](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-League) -* `Mlb.get_league(self, league_id: int, **params)` - Return a League from Id -* `Mlb.get_leagues(self, **params)` - Return all Leagues -* `Mlb.get_league_id(self, league_name: str, search_key: str = 'name', **params)` - Return League Id(s) -### [Seasons](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Season) -* `Mlb.get_season(self, season_id: str, sport_id: int = None, **params)` - Return a season -* `Mlb.get_seasons(self, sportid: int = None, **params)` - Return all seasons -### [Standings](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Standings) -* `Mlb.get_standings(self, league_id: int, season: str, **params)` - Return standings -### [Schedules](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) -* `Mlb.get_schedule(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params)` - Return a Schedule from dates -* `Mlb.get_scheduled_games_by_date(self, date: str = None,start_date: str = None, end_date: str = None, sport_id: int = 1, **params)` - Return game ids from dates -### [Games](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) -* `Mlb.get_game(self, game_id: int, **params)` - Return the Game for a specific Game Id -* `Mlb.get_game_play_by_play(self, game_id: int, **params)` - Return Play by play data for a game -* `Mlb.get_game_line_score(self, game_id: int, **params)` - Return a Linescore for a game -* `Mlb.get_game_box_score(self, game_id: int, **params)` - Return a Boxscore for a game - +| Document | Contents | +| --- | --- | +| [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | Endpoint reference, return objects, and model documentation | +| [Usage examples](docs/examples.md) | Extended synchronous examples | +| [Async usage](docs/async.md) | Async installation, lifecycle, concurrency, and examples | +| [HTTP transport](docs/http-transport.md) | Timeouts, retries, strict HTTP, exceptions, and ownership | +| [Public API contract](docs/public-api.md) | Supported symbols, signatures, endpoint methods, and stability policy | +| [Release notes](docs/releases/) | Release-specific changes and migration notes | ## Contributing -Contributions are welcome! Whether it's bug fixes, new features, or documentation improvements, we appreciate your help. - -### Getting Started - -1. Fork the repository -2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/python-mlb-statsapi.git` -3. Install dependencies: `poetry install` -4. Create a branch: `git checkout -b feat/your-feature` - -### Development - -Offline tests are deterministic and should run before every pull request: +Contributions, bug fixes, tests, and documentation improvements are welcome. ```bash -poetry run pytest \ - tests/ \ - --ignore=tests/external_tests +git clone https://github.com/YOUR_USERNAME/python-mlb-statsapi.git +cd python-mlb-statsapi +poetry install -E async ``` -External tests contact the live MLB API. They require internet access and are separate from normal offline CI: +Run the deterministic offline suite before a pull request: ```bash -poetry run pytest \ - tests/external_tests/ +poetry run pytest tests/ --ignore=tests/external_tests ``` -These live tests may fail because the MLB service is unavailable or because MLB changes undocumented payloads. - -Full local validation: +External tests contact the live MLB API and are separate from normal offline CI: ```bash -poetry run pytest tests/ -rm -rf dist -poetry build -python3 scripts/validate_release.py -poetry run twine check dist/* -``` - -`scripts/validate_release.py` is the same release check offline CI runs. It inspects the built wheel and source distribution, clean-installs each artifact into its own temporary virtual environment, and runs the same public-API smoke test against both installed artifacts. The smoke test verifies the declared metadata, the supported package-root imports, the strict HTTP default, explicit strict and compatibility modes, the versioned `User-Agent`, and injected-Session ownership. Every response it observes comes from an injected fake Session, so it never contacts the MLB API. - -Offline CI is the normal pull-request gate. External tests are available manually, on a weekly schedule, and before releases. - -### Pull Request Guidelines - -- Run offline tests before submitting a PR -- Use the [PR template](.github/pull_request_template.md) when creating your pull request -- Follow the branch naming convention: - - `feat/` - New features - - `fix/` - Bug fixes - - `docs/` - Documentation updates - - `refactor/` - Code improvements - -### Reporting Issues - -Found a bug or have a feature request? Please [open an issue](https://github.com/zero-sum-seattle/python-mlb-statsapi/issues/new) with: - -- A clear description of the problem or feature -- Steps to reproduce (for bugs) -- Expected vs actual behavior -- Python version and package version - - -## Examples - -Let's show some examples of getting stat objects from the API. What is baseball without stats, right? - -### Player Stats -Get the Id(s) of the players you want stats for and set stat types and groups. -```python ->>> mlb = mlbstatsapi.Mlb() ->>> player_id = mlb.get_people_id("Ty France")[0] ->>> stats = ['season', 'career'] ->>> groups = ['hitting', 'pitching'] ->>> params = {'season': 2022} -``` - -Use player id with stat types and groups to return a stats dictionary -```python ->>> stat_dict = mlb.get_player_stats(player_id, stats=stats, groups=groups, **params) ->>> season_hitting_stat = stat_dict['hitting']['season'] ->>> career_pitching_stat = stat_dict['pitching']['career'] -``` - -Print season hitting stats using Pydantic's `model_dump()` -```python ->>> for split in season_hitting_stat.splits: -... print(split.stat.model_dump(exclude_none=True)) -{'games_played': 140, 'groundouts': 163, 'airouts': 148, 'runs': 65, 'doubles': 27, ...} -``` - -Or access individual fields directly -```python ->>> for split in season_hitting_stat.splits: -... print(f"Games: {split.stat.games_played}") -... print(f"Home Runs: {split.stat.home_runs}") -... print(f"Batting Avg: {split.stat.avg}") -Games: 140 -Home Runs: 20 -Batting Avg: .274 -``` - -### Team Stats -Get the Team Id(s) -```python ->>> mlb = mlbstatsapi.Mlb() ->>> team_id = mlb.get_team_id('Seattle Mariners')[0] -``` - -Set the stat types and groups -```python ->>> stats = ['season', 'seasonAdvanced'] ->>> groups = ['hitting'] ->>> params = {'season': 2022} -``` - -Use team id and the stat types and groups to return season hitting stats -```python ->>> stats = mlb.get_team_stats(team_id, stats=stats, groups=groups, **params) ->>> season_hitting = stats['hitting']['season'] ->>> advanced_hitting = stats['hitting']['seasonAdvanced'] -``` - -Print stats as JSON -```python ->>> for split in season_hitting.splits: -... print(split.stat.model_dump_json(indent=2, exclude_none=True)) -{ - "games_played": 162, - "groundouts": 1273, - "runs": 690, - "doubles": 229, - ... -} -``` - -### Expected Stats -```python ->>> player_id = mlb.get_people_id('Ty France')[0] ->>> stats = ['expectedStatistics'] ->>> group = ['hitting'] ->>> params = {'season': 2022} - ->>> stats = mlb.get_player_stats(player_id, stats=stats, groups=group, **params) ->>> expected = stats['hitting']['expectedStatistics'] ->>> for split in expected.splits: -... print(f"Expected AVG: {split.stat.avg}") -... print(f"Expected SLG: {split.stat.slg}") -Expected AVG: .259 -Expected SLG: .394 -``` - -### vsPlayer Stats -Get pitcher and batter player Ids -```python ->>> ty_france_id = mlb.get_people_id('Ty France')[0] ->>> shohei_ohtani_id = mlb.get_people_id('Shohei Ohtani')[0] -``` - -Set stat type, stat groups, and params -```python ->>> stats = ['vsPlayer'] ->>> group = ['hitting'] ->>> params = {'opposingPlayerId': shohei_ohtani_id, 'season': 2022} -``` - -Get stats -```python ->>> stats = mlb.get_player_stats(ty_france_id, stats=stats, groups=group, **params) ->>> vs_player = stats['hitting']['vsPlayer'] ->>> for split in vs_player.splits: -... print(f"Games: {split.stat.games_played}, Hits: {split.stat.hits}") -Games: 2, Hits: 2 -``` - -### Hot/Cold Zones -```python ->>> ty_france_id = mlb.get_people_id('Ty France')[0] ->>> stats = ['hotColdZones'] ->>> hitting_group = ['hitting'] ->>> params = {'season': 2022} - ->>> hotcoldzones = mlb.get_player_stats(ty_france_id, stats=stats, groups=hitting_group, **params) ->>> zones = hotcoldzones['stats']['hotColdZones'] - ->>> for split in zones.splits: -... print(f"Stat: {split.stat.name}") -... for zone in split.stat.zones: -... print(f" Zone {zone.zone}: {zone.value}") -Stat: battingAverage - Zone 01: .226 - Zone 02: .400 - ... -``` - -### Schedule Examples -Get a schedule for a given date -```python ->>> mlb = mlbstatsapi.Mlb() ->>> schedule = mlb.get_schedule(date='2022-10-13') ->>> dates = schedule.dates - ->>> for date in dates: -... for game in date.games: -... print(f"Game: {game.game_pk}") -... print(f"Status: {game.status.detailed_state}") -... print(f"Home: {game.teams.home.team.name}") -... print(f"Away: {game.teams.away.team.name}") -``` - -### Game Examples -Get a Game for a given game id -```python ->>> mlb = mlbstatsapi.Mlb() ->>> game = mlb.get_game(662242) -``` - -Get the weather for a game -```python ->>> weather = game.game_data.weather ->>> print(f"Condition: {weather.condition}") ->>> print(f"Temperature: {weather.temp}") ->>> print(f"Wind: {weather.wind}") -``` - -Get the current status of a game -```python ->>> linescore = game.live_data.linescore ->>> home_info = game.game_data.teams.home ->>> away_info = game.game_data.teams.away ->>> home_status = linescore.teams.home ->>> away_status = linescore.teams.away - ->>> print(f"Home: {home_info.franchise_name} {home_info.club_name}") ->>> print(f" Runs: {home_status.runs}, Hits: {home_status.hits}, Errors: {home_status.errors}") ->>> print(f"Away: {away_info.franchise_name} {away_info.club_name}") ->>> print(f" Runs: {away_status.runs}, Hits: {away_status.hits}, Errors: {away_status.errors}") ->>> print(f"Inning: {linescore.inning_half} {linescore.current_inning_ordinal}") -``` - -Get play by play, line score, and box score objects -```python ->>> play_by_play = game.live_data.plays ->>> line_score = game.live_data.linescore ->>> box_score = game.live_data.boxscore -``` - -#### Play by Play -Get only the play by play for a given game id -```python ->>> playbyplay = mlb.get_game_play_by_play(662242) +poetry run pytest tests/external_tests/ ``` -#### Line Score -Get only the line score for a given game id -```python ->>> linescore = mlb.get_game_line_score(662242) -``` +See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development and pull request workflow. -#### Box Score -Get only the box score for a given game id -```python ->>> boxscore = mlb.get_game_box_score(662242) -``` - -### Gamepace Examples -Get pace of game metrics for a specific season -```python ->>> mlb = mlbstatsapi.Mlb() ->>> gamepace = mlb.get_gamepace(season=2021) ->>> print(f"Hits per game: {gamepace.sports[0].sport_game_pace.hits_per_game}") -``` - -### People Examples -Get all Players for a given sport id -```python ->>> mlb = mlbstatsapi.Mlb() ->>> players = mlb.get_people(sport_id=1) ->>> for player in players: -... print(f"{player.id}: {player.full_name}") -``` - -Get a player id -```python ->>> player_id = mlb.get_people_id("Ty France") ->>> print(player_id[0]) -664034 -``` - -### Team Examples -Get a Team -```python ->>> mlb = mlbstatsapi.Mlb() ->>> team_id = mlb.get_team_id("Seattle Mariners")[0] ->>> team = mlb.get_team(team_id) ->>> print(f"{team.id}: {team.name}") ->>> print(f"Venue: {team.venue.name}") -``` - -Get a Player Roster -```python ->>> mlb = mlbstatsapi.Mlb() ->>> players = mlb.get_team_roster(136) ->>> for player in players: -... print(f"#{player.jersey_number} {player.person.full_name}") -``` +## License -Get a Coach Roster -```python ->>> mlb = mlbstatsapi.Mlb() ->>> coaches = mlb.get_team_coaches(136) ->>> for coach in coaches: -... print(f"{coach.person.full_name}: {coach.title}") -``` - -### Draft Examples -Get a draft for a year -```python ->>> mlb = mlbstatsapi.Mlb() ->>> draft = mlb.get_draft('2019') -``` - -Get Players from Draft -```python ->>> draftpicks = draft[0].picks ->>> for pick in draftpicks: -... print(f"Round {pick.pick_round}, Pick {pick.pick_number}: {pick.person.full_name}") -``` - -### Award Examples -Get awards for a given award id -```python ->>> mlb = mlbstatsapi.Mlb() ->>> retired_numbers = mlb.get_awards(award_id='RETIREDUNI_108') ->>> for recipient in retired_numbers.awards: -... print(f"{recipient.player.full_name}: {recipient.name} ({recipient.date})") -``` - -### Venue Examples -Get a Venue -```python ->>> mlb = mlbstatsapi.Mlb() ->>> venue_id = mlb.get_venue_id('PNC Park')[0] ->>> venue = mlb.get_venue(venue_id) ->>> print(f"{venue.name} - {venue.location.city}, {venue.location.state}") -``` - -### Division Examples -Get a division -```python ->>> mlb = mlbstatsapi.Mlb() ->>> division = mlb.get_division(200) ->>> print(division.name) -American League West -``` - -### League Examples -Get a league -```python ->>> mlb = mlbstatsapi.Mlb() ->>> league = mlb.get_league(103) ->>> print(league.name) -American League -``` - -### Season Examples -Get a Season -```python ->>> mlb = mlbstatsapi.Mlb() ->>> season = mlb.get_season(2018) ->>> print(f"Season: {season.season_id}") ->>> print(f"Regular Season: {season.regular_season_start_date} to {season.regular_season_end_date}") -``` - -### Standings Examples -Get Standings -```python ->>> mlb = mlbstatsapi.Mlb() ->>> standings = mlb.get_standings(103, 2018) ->>> for record in standings: -... print(f"Division: {record.division.name}") -... for team in record.team_records: -... print(f" {team.team.name}: {team.wins}-{team.losses}") -``` +Released under the [MIT License](LICENSE). From 6992c36ddc6f52673ea5f44aba4f96a2b13f6223 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Sun, 23 Aug 2026 12:58:39 -0700 Subject: [PATCH 04/17] docs: restore contributor workflow after rebase --- CONTRIBUTING.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73cc389..aaeacb1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,11 +19,60 @@ Pull requests are the best way to propose changes to the codebase. We actively w 4. Ensure the test suite passes. 5. Issue that pull request! +## Development + +Install dependencies: + +```bash +poetry install -E async +``` + +Offline tests are deterministic and should run before every pull request: + +```bash +poetry run pytest \ + tests/ \ + --ignore=tests/external_tests +``` + +External tests contact the live MLB API. They require internet access and are separate from normal offline CI: + +```bash +poetry run pytest \ + tests/external_tests/ +``` + +These live tests may fail because the MLB service is unavailable or because MLB changes undocumented payloads. + +Full local validation: + +```bash +poetry run pytest tests/ +rm -rf dist +poetry build +python3 scripts/validate_release.py +poetry run twine check dist/* +``` + +`scripts/validate_release.py` is the same release check offline CI runs. It inspects the built wheel and source distribution, clean-installs each artifact into its own temporary virtual environment, and runs the same public-API smoke test against both installed artifacts. Every response it observes comes from injected fake HTTP clients, so it never contacts the MLB API. + +Offline CI is the normal pull-request gate. External tests are available manually, on a weekly schedule, and before releases. + +## Pull Request Guidelines + +- Run offline tests before submitting a PR +- Use the [PR template](.github/pull_request_template.md) when creating your pull request +- Follow the branch naming convention: + - `feat/` - New features + - `fix/` - Bug fixes + - `docs/` - Documentation updates + - `refactor/` - Code improvements + ## Any contributions you make will be under the MIT Software License In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern. ## Report bugs using Github's [issues](https://github.com/zero-sum-seattle/python-mlb-statsapi/issues) -We use GitHub issues to track public bugs. Report a bug by [opening a new issue](); it's that easy! +We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://github.com/zero-sum-seattle/python-mlb-statsapi/issues/new). ## Write bug reports with detail, background, and sample code **Great Bug Reports** tend to have: @@ -37,7 +86,7 @@ We use GitHub issues to track public bugs. Report a bug by [opening a new issue] - Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) ## Use a Consistent Coding Style -* Adhere to this projects coding style +* Adhere to this project's coding style ## License -By contributing, you agree that your contributions will be licensed under its MIT License. \ No newline at end of file +By contributing, you agree that your contributions will be licensed under its MIT License. From 0ded087b03b38dd4fef3811f52dae44e9247d3e5 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Sun, 23 Aug 2026 14:14:25 -0700 Subject: [PATCH 05/17] docs: restore method reference from README --- README.md | 5 ++- docs/methods.md | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 docs/methods.md diff --git a/README.md b/README.md index c23d18f..4b18e79 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-mlb-statsapi) ![GitHub](https://img.shields.io/github/license/zero-sum-seattle/python-mlb-statsapi) -### [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [Examples](docs/examples.md) | [Async](docs/async.md) | [Public API](docs/public-api.md) | [MLB Stats API](https://statsapi.mlb.com/) +### [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [Methods](docs/methods.md) | [Examples](docs/examples.md) | [Async](docs/async.md) | [Public API](docs/public-api.md) | [MLB Stats API](https://statsapi.mlb.com/)
@@ -166,7 +166,7 @@ schedule = mlb.get_schedule(date="2022-10-13") `get_schedule` is available on both `Mlb` and `AsyncMlb`. -Longer runnable examples live in [docs/examples.md](docs/examples.md). +See the [method reference](docs/methods.md) for the full method documentation that previously lived in the README. Longer runnable examples live in [docs/examples.md](docs/examples.md). ## HTTP and Error Behavior @@ -213,6 +213,7 @@ print(player.model_dump_json(indent=2)) | Document | Contents | | --- | --- | | [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | Endpoint reference, return objects, and model documentation | +| [Method reference](docs/methods.md) | Method signatures and short descriptions from the original README reference | | [Usage examples](docs/examples.md) | Extended synchronous examples | | [Async usage](docs/async.md) | Async installation, lifecycle, concurrency, and examples | | [HTTP transport](docs/http-transport.md) | Timeouts, retries, strict HTTP, exceptions, and ownership | diff --git a/docs/methods.md b/docs/methods.md new file mode 100644 index 0000000..1b33569 --- /dev/null +++ b/docs/methods.md @@ -0,0 +1,112 @@ +# Method Reference + +This page contains the method reference that previously lived in the README. + +For detailed return-object and model documentation, follow the linked Wiki pages. For the stable 1.x public API contract and current async endpoint coverage, see [public-api.md](public-api.md). + +## People, Person, Players, Coaches + +[Wiki: People](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-People) + +* `Mlb.get_people_id(self, fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params)` - Return Person Id(s) from fullname +* `Mlb.get_person(self, player_id: int, **params)` - Return Person Object from Id +* `Mlb.get_people(self, sport_id: int = 1, **params)` - Return all Players from Sport + +## Draft + +[Wiki: Draft](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Draft(round)) + +* `Mlb.get_draft(self, year_id: int, **params)` - Return a draft for a given year + +## Awards + +[Wiki: Award](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Award) + +* `Mlb.get_awards(self, award_id: int, **params)` - Return award recipients for a given award + +## Teams + +[Wiki: Team](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Team) + +* `Mlb.get_team_id(self, team_name: str, search_key: str = 'name', **params)` - Return Team Id(s) from name +* `Mlb.get_team(self, team_id: int, **params)` - Return Team Object from Team Id +* `Mlb.get_teams(self, sport_id: int = 1, **params)` - Return all Teams for Sport +* `Mlb.get_team_coaches(self, team_id: int, **params)` - Return coaching roster for team for current or specified season +* `Mlb.get_team_roster(self, team_id: int, **params)` - Return player roster for team for current or specified season + +## Stats + +[Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) + +* `Mlb.get_player_stats(self, person_id: int, stats: list, groups: list, **params)` - Return stats by player id, stat type and groups +* `Mlb.get_team_stats(self, team_id: int, stats: list, groups: list, **params)` - Return stats by team id, stat types and groups +* `Mlb.get_stats(self, stats: list, groups: list, **params: dict)` - Return stats by stat type and group args +* `Mlb.get_players_stats_for_game(self, person_id: int, game_id: int, **params)` - Return player stats for a game + +## Gamepace + +[Wiki: Gamepace](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Gamepace) + +* `Mlb.get_gamepace(self, season: str, sport_id=1, **params)` - Return pace of game metrics for specific sport, league or team. + +## Venues + +[Wiki: Venue](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Venue) + +* `Mlb.get_venue_id(self, venue_name: str, search_key: str = 'name', **params)` - Return Venue Id(s) +* `Mlb.get_venue(self, venue_id: int, **params)` - Return Venue Object from venue Id +* `Mlb.get_venues(self, **params)` - Return all Venues + +## Sports + +[Wiki: Sport](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Sport) + +* `Mlb.get_sport(self, sport_id: int, **params)` - Return a Sport object from Id +* `Mlb.get_sports(self, **params)` - Return all Sports +* `Mlb.get_sport_id(self, sport_name: str, search_key: str = 'name', **params)` - Return Sport Id from name + +## Schedules + +[Wiki: Schedule](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) + +* `Mlb.get_schedule(self, date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params)` - Return a Schedule +* `Mlb.get_schedule(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params)` - Return a Schedule from dates +* `Mlb.get_scheduled_games_by_date(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, **params)` - Return game ids from dates + +## Divisions + +[Wiki: Division](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Division) + +* `Mlb.get_division(self, division_id: int, **params)` - Return a Division +* `Mlb.get_divisions(self, **params)` - Return all Divisions +* `Mlb.get_division_id(self, division_name: str, search_key: str = 'name', **params)` - Return Division Id(s) from name + +## Leagues + +[Wiki: League](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-League) + +* `Mlb.get_league(self, league_id: int, **params)` - Return a League from Id +* `Mlb.get_leagues(self, **params)` - Return all Leagues +* `Mlb.get_league_id(self, league_name: str, search_key: str = 'name', **params)` - Return League Id(s) + +## Seasons + +[Wiki: Season](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Season) + +* `Mlb.get_season(self, season_id: str, sport_id: int = None, **params)` - Return a season +* `Mlb.get_seasons(self, sportid: int = None, **params)` - Return all seasons + +## Standings + +[Wiki: Standings](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Standings) + +* `Mlb.get_standings(self, league_id: int, season: str, **params)` - Return standings + +## Games + +[Wiki: Game](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) + +* `Mlb.get_game(self, game_id: int, **params)` - Return the Game for a specific Game Id +* `Mlb.get_game_play_by_play(self, game_id: int, **params)` - Return Play by play data for a game +* `Mlb.get_game_line_score(self, game_id: int, **params)` - Return a Linescore for a game +* `Mlb.get_game_box_score(self, game_id: int, **params)` - Return a Boxscore for a game From 55ed8f9df1ca375b40a5c156e7a52f58c22911a3 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 17:53:30 -0700 Subject: [PATCH 06/17] docs: add explicit client cleanup examples --- README.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.md b/README.md index 4b18e79..0f1502e 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,49 @@ async def main(): print(team.name) +asyncio.run(main()) +``` + +### Without a context manager + +Context managers are recommended, but both clients can also be created directly. When doing that, close library-owned HTTP resources explicitly. + +#### Sync + +```python +from mlbstatsapi import Mlb + +mlb = Mlb() +try: + player = mlb.get_person(664034) + team = mlb.get_team(136) + + print(player.full_name) + print(team.name) +finally: + mlb.close() +``` + +#### Async + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + mlb = AsyncMlb() + try: + player = await mlb.get_person(664034) + team = await mlb.get_team(136) + + print(player.full_name) + print(team.name) + finally: + await mlb.aclose() + + asyncio.run(main()) ``` From 23b0e55648f3caa3c3318d42d6a879e5ecd79856 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 17:53:50 -0700 Subject: [PATCH 07/17] docs: make async explicit cleanup example runnable --- docs/async.md | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/async.md b/docs/async.md index fc59625..85eefa8 100644 --- a/docs/async.md +++ b/docs/async.md @@ -32,15 +32,32 @@ asyncio.run(main()) ``` Use `async with` when possible so library-owned HTTP resources are closed when -the block exits. If a context manager is not practical, explicit cleanup is -also supported: +the block exits. + +## Without a context manager + +If a context manager is not practical, create `AsyncMlb` directly and call +`await mlb.aclose()` when finished: ```python -mlb = AsyncMlb() -try: - player = await mlb.get_person(664034) -finally: - await mlb.aclose() +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + mlb = AsyncMlb() + try: + player = await mlb.get_person(664034) + team = await mlb.get_team(136) + + print(player.full_name) + print(team.name) + finally: + await mlb.aclose() + + +asyncio.run(main()) ``` Repeated `aclose()` calls are safe. From 09870301401e913f8cfd7e757bd64a23b14d58b9 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 17:54:12 -0700 Subject: [PATCH 08/17] docs: add sync explicit cleanup example --- docs/examples.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/examples.md b/docs/examples.md index 817afd8..6c2ce5f 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -6,6 +6,24 @@ Every example in this file uses the synchronous `Mlb` client. Async usage is doc For return-object structure and endpoint details see the [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki). For the supported method list, parameters, and return shapes see the [public API contract](public-api.md). For transport behavior see the [HTTP transport documentation](http-transport.md). +## Without a context manager + +A context manager is recommended, but `Mlb` can also be created directly. Call `mlb.close()` when finished so library-owned HTTP resources are released. + +```python +from mlbstatsapi import Mlb + +mlb = Mlb() +try: + player = mlb.get_person(664034) + team = mlb.get_team(136) + + print(player.full_name) + print(team.name) +finally: + mlb.close() +``` + ## Working with Pydantic Models All returned objects are Pydantic models, giving you access to serialization and validation helpers. From a6c92cedf373f45cbeefe38eebd3232a806a55da Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:02:04 -0700 Subject: [PATCH 09/17] docs: clean up method reference formatting --- docs/methods.md | 97 ++++++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 37 deletions(-) diff --git a/docs/methods.md b/docs/methods.md index 1b33569..7a17286 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -8,105 +8,128 @@ For detailed return-object and model documentation, follow the linked Wiki pages [Wiki: People](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-People) -* `Mlb.get_people_id(self, fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params)` - Return Person Id(s) from fullname -* `Mlb.get_person(self, player_id: int, **params)` - Return Person Object from Id -* `Mlb.get_people(self, sport_id: int = 1, **params)` - Return all Players from Sport +`Mlb.get_people_id(self, fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params)` - Return Person Id(s) from fullname + +`Mlb.get_person(self, player_id: int, **params)` - Return Person Object from Id + +`Mlb.get_people(self, sport_id: int = 1, **params)` - Return all Players from Sport ## Draft [Wiki: Draft](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Draft(round)) -* `Mlb.get_draft(self, year_id: int, **params)` - Return a draft for a given year +`Mlb.get_draft(self, year_id: int, **params)` - Return a draft for a given year ## Awards [Wiki: Award](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Award) -* `Mlb.get_awards(self, award_id: int, **params)` - Return award recipients for a given award +`Mlb.get_awards(self, award_id: int, **params)` - Return award recipients for a given award ## Teams [Wiki: Team](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Team) -* `Mlb.get_team_id(self, team_name: str, search_key: str = 'name', **params)` - Return Team Id(s) from name -* `Mlb.get_team(self, team_id: int, **params)` - Return Team Object from Team Id -* `Mlb.get_teams(self, sport_id: int = 1, **params)` - Return all Teams for Sport -* `Mlb.get_team_coaches(self, team_id: int, **params)` - Return coaching roster for team for current or specified season -* `Mlb.get_team_roster(self, team_id: int, **params)` - Return player roster for team for current or specified season +`Mlb.get_team_id(self, team_name: str, search_key: str = 'name', **params)` - Return Team Id(s) from name + +`Mlb.get_team(self, team_id: int, **params)` - Return Team Object from Team Id + +`Mlb.get_teams(self, sport_id: int = 1, **params)` - Return all Teams for Sport + +`Mlb.get_team_coaches(self, team_id: int, **params)` - Return coaching roster for team for current or specified season + +`Mlb.get_team_roster(self, team_id: int, **params)` - Return player roster for team for current or specified season ## Stats [Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) -* `Mlb.get_player_stats(self, person_id: int, stats: list, groups: list, **params)` - Return stats by player id, stat type and groups -* `Mlb.get_team_stats(self, team_id: int, stats: list, groups: list, **params)` - Return stats by team id, stat types and groups -* `Mlb.get_stats(self, stats: list, groups: list, **params: dict)` - Return stats by stat type and group args -* `Mlb.get_players_stats_for_game(self, person_id: int, game_id: int, **params)` - Return player stats for a game +`Mlb.get_player_stats(self, person_id: int, stats: list, groups: list, **params)` - Return stats by player id, stat type and groups + +`Mlb.get_team_stats(self, team_id: int, stats: list, groups: list, **params)` - Return stats by team id, stat types and groups + +`Mlb.get_stats(self, stats: list, groups: list, **params: dict)` - Return stats by stat type and group args + +`Mlb.get_players_stats_for_game(self, person_id: int, game_id: int, **params)` - Return player stats for a game ## Gamepace [Wiki: Gamepace](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Gamepace) -* `Mlb.get_gamepace(self, season: str, sport_id=1, **params)` - Return pace of game metrics for specific sport, league or team. +`Mlb.get_gamepace(self, season: str, sport_id=1, **params)` - Return pace of game metrics for specific sport, league or team. ## Venues [Wiki: Venue](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Venue) -* `Mlb.get_venue_id(self, venue_name: str, search_key: str = 'name', **params)` - Return Venue Id(s) -* `Mlb.get_venue(self, venue_id: int, **params)` - Return Venue Object from venue Id -* `Mlb.get_venues(self, **params)` - Return all Venues +`Mlb.get_venue_id(self, venue_name: str, search_key: str = 'name', **params)` - Return Venue Id(s) + +`Mlb.get_venue(self, venue_id: int, **params)` - Return Venue Object from venue Id + +`Mlb.get_venues(self, **params)` - Return all Venues ## Sports [Wiki: Sport](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Sport) -* `Mlb.get_sport(self, sport_id: int, **params)` - Return a Sport object from Id -* `Mlb.get_sports(self, **params)` - Return all Sports -* `Mlb.get_sport_id(self, sport_name: str, search_key: str = 'name', **params)` - Return Sport Id from name +`Mlb.get_sport(self, sport_id: int, **params)` - Return a Sport object from Id + +`Mlb.get_sports(self, **params)` - Return all Sports + +`Mlb.get_sport_id(self, sport_name: str, search_key: str = 'name', **params)` - Return Sport Id from name ## Schedules [Wiki: Schedule](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) -* `Mlb.get_schedule(self, date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params)` - Return a Schedule -* `Mlb.get_schedule(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params)` - Return a Schedule from dates -* `Mlb.get_scheduled_games_by_date(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, **params)` - Return game ids from dates +`Mlb.get_schedule(self, date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params)` - Return a Schedule + +`Mlb.get_schedule(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params)` - Return a Schedule from dates + +`Mlb.get_scheduled_games_by_date(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, **params)` - Return game ids from dates ## Divisions [Wiki: Division](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Division) -* `Mlb.get_division(self, division_id: int, **params)` - Return a Division -* `Mlb.get_divisions(self, **params)` - Return all Divisions -* `Mlb.get_division_id(self, division_name: str, search_key: str = 'name', **params)` - Return Division Id(s) from name +`Mlb.get_division(self, division_id: int, **params)` - Return a Division + +`Mlb.get_divisions(self, **params)` - Return all Divisions + +`Mlb.get_division_id(self, division_name: str, search_key: str = 'name', **params)` - Return Division Id(s) from name ## Leagues [Wiki: League](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-League) -* `Mlb.get_league(self, league_id: int, **params)` - Return a League from Id -* `Mlb.get_leagues(self, **params)` - Return all Leagues -* `Mlb.get_league_id(self, league_name: str, search_key: str = 'name', **params)` - Return League Id(s) +`Mlb.get_league(self, league_id: int, **params)` - Return a League from Id + +`Mlb.get_leagues(self, **params)` - Return all Leagues + +`Mlb.get_league_id(self, league_name: str, search_key: str = 'name', **params)` - Return League Id(s) ## Seasons [Wiki: Season](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Season) -* `Mlb.get_season(self, season_id: str, sport_id: int = None, **params)` - Return a season -* `Mlb.get_seasons(self, sportid: int = None, **params)` - Return all seasons +`Mlb.get_season(self, season_id: str, sport_id: int = None, **params)` - Return a season + +`Mlb.get_seasons(self, sportid: int = None, **params)` - Return all seasons ## Standings [Wiki: Standings](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Standings) -* `Mlb.get_standings(self, league_id: int, season: str, **params)` - Return standings +`Mlb.get_standings(self, league_id: int, season: str, **params)` - Return standings ## Games [Wiki: Game](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) -* `Mlb.get_game(self, game_id: int, **params)` - Return the Game for a specific Game Id -* `Mlb.get_game_play_by_play(self, game_id: int, **params)` - Return Play by play data for a game -* `Mlb.get_game_line_score(self, game_id: int, **params)` - Return a Linescore for a game -* `Mlb.get_game_box_score(self, game_id: int, **params)` - Return a Boxscore for a game +`Mlb.get_game(self, game_id: int, **params)` - Return the Game for a specific Game Id + +`Mlb.get_game_play_by_play(self, game_id: int, **params)` - Return Play by play data for a game + +`Mlb.get_game_line_score(self, game_id: int, **params)` - Return a Linescore for a game + +`Mlb.get_game_box_score(self, game_id: int, **params)` - Return a Boxscore for a game From 9b8e88849af3ad0c2dce5345b631d7a7568c5fa7 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:13:51 -0700 Subject: [PATCH 10/17] docs: make method reference easier to scan --- docs/methods.md | 217 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 151 insertions(+), 66 deletions(-) diff --git a/docs/methods.md b/docs/methods.md index 7a17286..51c5d3a 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -4,132 +4,217 @@ This page contains the method reference that previously lived in the README. For detailed return-object and model documentation, follow the linked Wiki pages. For the stable 1.x public API contract and current async endpoint coverage, see [public-api.md](public-api.md). +**Jump to:** [People](#people-person-players-coaches) · [Teams](#teams) · [Stats](#stats) · [Games](#games) · [Schedules](#schedules) · [Venues](#venues) · [Sports](#sports) · [Leagues](#leagues) · [Divisions](#divisions) · [Seasons](#seasons) · [Standings](#standings) · [Draft](#draft) · [Awards](#awards) · [Gamepace](#gamepace) + ## People, Person, Players, Coaches [Wiki: People](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-People) -`Mlb.get_people_id(self, fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params)` - Return Person Id(s) from fullname - -`Mlb.get_person(self, player_id: int, **params)` - Return Person Object from Id - -`Mlb.get_people(self, sport_id: int = 1, **params)` - Return all Players from Sport - -## Draft - -[Wiki: Draft](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Draft(round)) +| Method | Description | +| --- | --- | +| `get_people_id()` | Return person ID(s) from a full name | +| `get_person()` | Return a person from an ID | +| `get_people()` | Return all players for a sport | -`Mlb.get_draft(self, year_id: int, **params)` - Return a draft for a given year - -## Awards - -[Wiki: Award](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Award) - -`Mlb.get_awards(self, award_id: int, **params)` - Return award recipients for a given award +```text +Mlb.get_people_id(fullname: str, sport_id: int = 1, search_key: str = 'fullname', **params) +Mlb.get_person(player_id: int, **params) +Mlb.get_people(sport_id: int = 1, **params) +``` ## Teams [Wiki: Team](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Team) -`Mlb.get_team_id(self, team_name: str, search_key: str = 'name', **params)` - Return Team Id(s) from name - -`Mlb.get_team(self, team_id: int, **params)` - Return Team Object from Team Id +| Method | Description | +| --- | --- | +| `get_team_id()` | Return team ID(s) from a name | +| `get_team()` | Return a team from a team ID | +| `get_teams()` | Return all teams for a sport | +| `get_team_coaches()` | Return the coaching roster for a team | +| `get_team_roster()` | Return the player roster for a team | + +```text +Mlb.get_team_id(team_name: str, search_key: str = 'name', **params) +Mlb.get_team(team_id: int, **params) +Mlb.get_teams(sport_id: int = 1, **params) +Mlb.get_team_coaches(team_id: int, **params) +Mlb.get_team_roster(team_id: int, **params) +``` -`Mlb.get_teams(self, sport_id: int = 1, **params)` - Return all Teams for Sport +## Stats -`Mlb.get_team_coaches(self, team_id: int, **params)` - Return coaching roster for team for current or specified season +[Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) -`Mlb.get_team_roster(self, team_id: int, **params)` - Return player roster for team for current or specified season +| Method | Description | +| --- | --- | +| `get_player_stats()` | Return stats for a player | +| `get_team_stats()` | Return stats for a team | +| `get_stats()` | Return stats by stat type and group | +| `get_players_stats_for_game()` | Return player stats for a game | -## Stats +```text +Mlb.get_player_stats(person_id: int, stats: list, groups: list, **params) +Mlb.get_team_stats(team_id: int, stats: list, groups: list, **params) +Mlb.get_stats(stats: list, groups: list, **params: dict) +Mlb.get_players_stats_for_game(person_id: int, game_id: int, **params) +``` -[Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) +## Games -`Mlb.get_player_stats(self, person_id: int, stats: list, groups: list, **params)` - Return stats by player id, stat type and groups +[Wiki: Game](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) -`Mlb.get_team_stats(self, team_id: int, stats: list, groups: list, **params)` - Return stats by team id, stat types and groups +| Method | Description | +| --- | --- | +| `get_game()` | Return a game for a game ID | +| `get_game_play_by_play()` | Return play-by-play data for a game | +| `get_game_line_score()` | Return a linescore for a game | +| `get_game_box_score()` | Return a boxscore for a game | -`Mlb.get_stats(self, stats: list, groups: list, **params: dict)` - Return stats by stat type and group args +```text +Mlb.get_game(game_id: int, **params) +Mlb.get_game_play_by_play(game_id: int, **params) +Mlb.get_game_line_score(game_id: int, **params) +Mlb.get_game_box_score(game_id: int, **params) +``` -`Mlb.get_players_stats_for_game(self, person_id: int, game_id: int, **params)` - Return player stats for a game +## Schedules -## Gamepace +[Wiki: Schedule](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) -[Wiki: Gamepace](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Gamepace) +| Method | Description | +| --- | --- | +| `get_schedule()` | Return a schedule from a date or date range | +| `get_scheduled_games_by_date()` | Return scheduled games from dates | -`Mlb.get_gamepace(self, season: str, sport_id=1, **params)` - Return pace of game metrics for specific sport, league or team. +```text +Mlb.get_schedule(date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params) +Mlb.get_schedule(date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params) +Mlb.get_scheduled_games_by_date(date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, **params) +``` ## Venues [Wiki: Venue](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Venue) -`Mlb.get_venue_id(self, venue_name: str, search_key: str = 'name', **params)` - Return Venue Id(s) - -`Mlb.get_venue(self, venue_id: int, **params)` - Return Venue Object from venue Id +| Method | Description | +| --- | --- | +| `get_venue_id()` | Return venue ID(s) from a name | +| `get_venue()` | Return a venue from an ID | +| `get_venues()` | Return all venues | -`Mlb.get_venues(self, **params)` - Return all Venues +```text +Mlb.get_venue_id(venue_name: str, search_key: str = 'name', **params) +Mlb.get_venue(venue_id: int, **params) +Mlb.get_venues(**params) +``` ## Sports [Wiki: Sport](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Sport) -`Mlb.get_sport(self, sport_id: int, **params)` - Return a Sport object from Id - -`Mlb.get_sports(self, **params)` - Return all Sports +| Method | Description | +| --- | --- | +| `get_sport()` | Return a sport from an ID | +| `get_sports()` | Return all sports | +| `get_sport_id()` | Return sport ID(s) from a name | -`Mlb.get_sport_id(self, sport_name: str, search_key: str = 'name', **params)` - Return Sport Id from name +```text +Mlb.get_sport(sport_id: int, **params) +Mlb.get_sports(**params) +Mlb.get_sport_id(sport_name: str, search_key: str = 'name', **params) +``` -## Schedules - -[Wiki: Schedule](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Schedule) +## Leagues -`Mlb.get_schedule(self, date: str, start_date: str, end_date: str, sport_id: int, team_id: int, **params)` - Return a Schedule +[Wiki: League](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-League) -`Mlb.get_schedule(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, team_id: int = None, **params)` - Return a Schedule from dates +| Method | Description | +| --- | --- | +| `get_league()` | Return a league from an ID | +| `get_leagues()` | Return all leagues | +| `get_league_id()` | Return league ID(s) from a name | -`Mlb.get_scheduled_games_by_date(self, date: str = None, start_date: str = None, end_date: str = None, sport_id: int = 1, **params)` - Return game ids from dates +```text +Mlb.get_league(league_id: int, **params) +Mlb.get_leagues(**params) +Mlb.get_league_id(league_name: str, search_key: str = 'name', **params) +``` ## Divisions [Wiki: Division](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Division) -`Mlb.get_division(self, division_id: int, **params)` - Return a Division +| Method | Description | +| --- | --- | +| `get_division()` | Return a division from an ID | +| `get_divisions()` | Return all divisions | +| `get_division_id()` | Return division ID(s) from a name | -`Mlb.get_divisions(self, **params)` - Return all Divisions +```text +Mlb.get_division(division_id: int, **params) +Mlb.get_divisions(**params) +Mlb.get_division_id(division_name: str, search_key: str = 'name', **params) +``` -`Mlb.get_division_id(self, division_name: str, search_key: str = 'name', **params)` - Return Division Id(s) from name +## Seasons -## Leagues +[Wiki: Season](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Season) -[Wiki: League](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-League) +| Method | Description | +| --- | --- | +| `get_season()` | Return a season | +| `get_seasons()` | Return all seasons | -`Mlb.get_league(self, league_id: int, **params)` - Return a League from Id +```text +Mlb.get_season(season_id: str, sport_id: int = None, **params) +Mlb.get_seasons(sportid: int = None, **params) +``` -`Mlb.get_leagues(self, **params)` - Return all Leagues +## Standings -`Mlb.get_league_id(self, league_name: str, search_key: str = 'name', **params)` - Return League Id(s) +[Wiki: Standings](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Standings) -## Seasons +| Method | Description | +| --- | --- | +| `get_standings()` | Return standings for a league and season | -[Wiki: Season](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Season) +```text +Mlb.get_standings(league_id: int, season: str, **params) +``` + +## Draft -`Mlb.get_season(self, season_id: str, sport_id: int = None, **params)` - Return a season +[Wiki: Draft](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Draft(round)) -`Mlb.get_seasons(self, sportid: int = None, **params)` - Return all seasons +| Method | Description | +| --- | --- | +| `get_draft()` | Return a draft for a given year | -## Standings +```text +Mlb.get_draft(year_id: int, **params) +``` -[Wiki: Standings](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Standings) +## Awards -`Mlb.get_standings(self, league_id: int, season: str, **params)` - Return standings +[Wiki: Award](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Award) -## Games +| Method | Description | +| --- | --- | +| `get_awards()` | Return award recipients for an award | -[Wiki: Game](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) +```text +Mlb.get_awards(award_id: int, **params) +``` -`Mlb.get_game(self, game_id: int, **params)` - Return the Game for a specific Game Id +## Gamepace -`Mlb.get_game_play_by_play(self, game_id: int, **params)` - Return Play by play data for a game +[Wiki: Gamepace](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Gamepace) -`Mlb.get_game_line_score(self, game_id: int, **params)` - Return a Linescore for a game +| Method | Description | +| --- | --- | +| `get_gamepace()` | Return pace-of-game metrics for a sport, league, or team | -`Mlb.get_game_box_score(self, game_id: int, **params)` - Return a Boxscore for a game +```text +Mlb.get_gamepace(season: str, sport_id=1, **params) +``` From d416124d8be4f2eacc05d5a5becb8b422f9d7178 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:23:05 -0700 Subject: [PATCH 11/17] docs: add dedicated stats usage guide --- docs/stats.md | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 docs/stats.md diff --git a/docs/stats.md b/docs/stats.md new file mode 100644 index 0000000..0a30184 --- /dev/null +++ b/docs/stats.md @@ -0,0 +1,272 @@ +# Stats Guide + +The stats methods return MLB statistics grouped by **stat group** and then by **stat type**. Both `Mlb` and `AsyncMlb` return the same structure. + +## Stats methods + +| Method | Use | +| --- | --- | +| `get_player_stats()` | Stats for one player | +| `get_team_stats()` | Stats for one team | +| `get_stats()` | General stats query across the Stats API | +| `get_players_stats_for_game()` | Stats for one player in one game | + +The synchronous and asynchronous signatures match. With `AsyncMlb`, await the method call. + +## Understanding the return value + +The four stats methods return a nested dictionary: + +```text +stats[group][type] -> Stat +``` + +For example: + +```python +stats = mlb.get_player_stats( + 664034, + stats=["season"], + groups=["hitting"], + season=2022, +) + +season_hitting = stats["hitting"]["season"] +``` + +`season_hitting` is a `Stat` model. Its `splits` field contains the returned stat splits. + +```python +for split in season_hitting.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +A query can request multiple groups and stat types at once: + +```python +stats = mlb.get_player_stats( + 664034, + stats=["season", "career"], + groups=["hitting", "fielding"], + season=2022, +) + +for group_name, group_stats in stats.items(): + for stat_type, stat in group_stats.items(): + print(group_name, stat_type, stat.total_splits) +``` + +If the API response contains no usable stats, these methods return `{}`. + +## Player stats + +Use `get_player_stats()` when you know the MLB person ID and want one or more stat types for that player. + +### Sync + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + stats = mlb.get_player_stats( + 664034, + stats=["season", "career"], + groups=["hitting"], + season=2022, + ) + +season = stats["hitting"]["season"] +for split in season.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +### Async + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + stats = await mlb.get_player_stats( + 664034, + stats=["season", "career"], + groups=["hitting"], + season=2022, + ) + + season = stats["hitting"]["season"] + for split in season.splits: + print(split.stat.model_dump(exclude_none=True)) + + +asyncio.run(main()) +``` + +## Team stats + +Use `get_team_stats()` for stat data scoped to one team. + +### Sync + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + stats = mlb.get_team_stats( + 136, + stats=["season", "seasonAdvanced"], + groups=["hitting"], + season=2022, + ) + +for stat_type, stat in stats["hitting"].items(): + print(stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +### Async + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + stats = await mlb.get_team_stats( + 136, + stats=["season", "seasonAdvanced"], + groups=["hitting"], + season=2022, + ) + + for stat_type, stat in stats["hitting"].items(): + print(stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) + + +asyncio.run(main()) +``` + +## General stats queries + +`get_stats()` queries the general `/stats` endpoint. Additional keyword arguments can narrow the request by season, team, league, game type, sport, and other Stats API parameters. + +### Sync + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + stats = mlb.get_stats( + stats=["season"], + groups=["hitting"], + season=2022, + sportIds=1, + ) + +for group_name, group_stats in stats.items(): + for stat_type, stat in group_stats.items(): + print(group_name, stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +### Async + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + stats = await mlb.get_stats( + stats=["season"], + groups=["hitting"], + season=2022, + sportIds=1, + ) + + for group_name, group_stats in stats.items(): + for stat_type, stat in group_stats.items(): + print(group_name, stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) + + +asyncio.run(main()) +``` + +## Player stats for a game + +Use `get_players_stats_for_game()` when you have both the player's MLB person ID and the game's `gamePk`. + +### Sync + +```python +from mlbstatsapi import Mlb + +with Mlb() as mlb: + stats = mlb.get_players_stats_for_game( + person_id=663728, + game_id=715757, + ) + +for group_name, group_stats in stats.items(): + for stat_type, stat in group_stats.items(): + print(group_name, stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) +``` + +### Async + +```python +import asyncio + +from mlbstatsapi import AsyncMlb + + +async def main(): + async with AsyncMlb() as mlb: + stats = await mlb.get_players_stats_for_game( + person_id=663728, + game_id=715757, + ) + + for group_name, group_stats in stats.items(): + for stat_type, stat in group_stats.items(): + print(group_name, stat_type) + for split in stat.splits: + print(split.stat.model_dump(exclude_none=True)) + + +asyncio.run(main()) +``` + +## Finding valid stat types and groups + +The MLB Stats API publishes the available values directly: + +- Stat types: +- Stat groups: +- Event types: +- Game types: + +Common stat groups include `hitting`, `pitching`, and `fielding`. Available stat types depend on the group and endpoint. Examples include `season`, `career`, `seasonAdvanced`, `gameLog`, and `playLog`. + +## Related documentation + +- [Method reference](methods.md) +- [General usage examples](examples.md) +- [Async usage](async.md) +- [Public API contract](public-api.md) +- [Stats model Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) From bafb12580cd96425adaffaac69ccbb953344517c Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:23:40 -0700 Subject: [PATCH 12/17] docs: point stat examples to dedicated guide --- docs/examples.md | 40 +++------------------------------------- 1 file changed, 3 insertions(+), 37 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 6c2ce5f..442dfb7 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -2,7 +2,7 @@ This document collects the longer usage examples that previously lived in the README. The README keeps a short quick start; this guide is the extended tour. -Every example in this file uses the synchronous `Mlb` client. Async usage is documented separately in [async.md](async.md). +Every example in this file uses the synchronous `Mlb` client. Async usage is documented separately in [async.md](async.md). Stats have their own detailed [stats guide](stats.md) with both sync and async examples. For return-object structure and endpoint details see the [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki). For the supported method list, parameters, and return shapes see the [public API contract](public-api.md). For transport behavior see the [HTTP transport documentation](http-transport.md). @@ -55,43 +55,9 @@ print(player.full_name) print(team.name) ``` -## Player stats +## Stats -```python -from mlbstatsapi import Mlb - -with Mlb() as mlb: - player_id = mlb.get_people_id("Ty France")[0] - stats = mlb.get_player_stats( - player_id, - stats=["season", "career"], - groups=["hitting", "pitching"], - season=2022, - ) - -season_hitting = stats["hitting"]["season"] -for split in season_hitting.splits: - print(split.stat.model_dump(exclude_none=True)) -``` - -## Team stats - -```python -from mlbstatsapi import Mlb - -with Mlb() as mlb: - team_id = mlb.get_team_id("Seattle Mariners")[0] - stats = mlb.get_team_stats( - team_id, - stats=["season", "seasonAdvanced"], - groups=["hitting"], - season=2022, - ) - -season_hitting = stats["hitting"]["season"] -for split in season_hitting.splits: - print(split.stat.model_dump_json(indent=2, exclude_none=True)) -``` +Player, team, general, and per-game stat examples live in the dedicated [Stats Guide](stats.md). It also explains the nested `stats[group][type]` return structure and includes matching `Mlb` and `AsyncMlb` examples. ## Schedule From 225f10e7c56ff0bb0601e44460bf1790138d9510 Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:24:06 -0700 Subject: [PATCH 13/17] docs: link method reference to stats guide --- docs/methods.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/methods.md b/docs/methods.md index 51c5d3a..5b26f39 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -44,7 +44,7 @@ Mlb.get_team_roster(team_id: int, **params) ## Stats -[Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) +[Wiki: Stats](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Stats) · [Stats Guide](stats.md) | Method | Description | | --- | --- | @@ -60,6 +60,8 @@ Mlb.get_stats(stats: list, groups: list, **params: dict) Mlb.get_players_stats_for_game(person_id: int, game_id: int, **params) ``` +The [Stats Guide](stats.md) includes runnable `Mlb` and `AsyncMlb` examples and explains the nested `stats[group][type]` return structure. + ## Games [Wiki: Game](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki/Data-Types:-Game) From 77ead307eac25208c723ee9644ea6b3f8b321ebc Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 18:24:34 -0700 Subject: [PATCH 14/17] docs: link dedicated stats guide from README --- README.md | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0f1502e..fb5af28 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/python-mlb-statsapi) ![GitHub](https://img.shields.io/github/license/zero-sum-seattle/python-mlb-statsapi) -### [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [Methods](docs/methods.md) | [Examples](docs/examples.md) | [Async](docs/async.md) | [Public API](docs/public-api.md) | [MLB Stats API](https://statsapi.mlb.com/) +### [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | [Methods](docs/methods.md) | [Examples](docs/examples.md) | [Stats](docs/stats.md) | [Async](docs/async.md) | [Public API](docs/public-api.md) | [MLB Stats API](https://statsapi.mlb.com/)
@@ -143,7 +143,7 @@ See [Async usage](docs/async.md) for lifecycle, concurrency, custom HTTPX client Where an async endpoint is supported, both clients return the same Pydantic models and follow the same public HTTP/error behavior. -The async surface is still smaller than the full synchronous API while 1.1 coverage is expanded. The [public API contract](docs/public-api.md#asyncmlb-public-client) is the authoritative list of supported async methods. +The [public API contract](docs/public-api.md#asyncmlb-public-client) is the authoritative list of supported async methods. ## Concurrent Async Requests @@ -190,16 +190,7 @@ team_ids = mlb.get_team_id("Seattle Mariners") ### Stats -```python -stats = mlb.get_player_stats( - 664034, - stats=["season", "career"], - groups=["hitting"], - season=2022, -) -``` - -Higher-level stats helpers remain on the synchronous `Mlb` client in the current 1.1 async surface. +The stats API has several entry points and returns a nested `stats[group][type]` structure. See the dedicated [Stats Guide](docs/stats.md) for `get_player_stats()`, `get_team_stats()`, `get_stats()`, and `get_players_stats_for_game()` examples using both `Mlb` and `AsyncMlb`. ### Schedule @@ -258,6 +249,7 @@ print(player.model_dump_json(indent=2)) | [Wiki](https://github.com/zero-sum-seattle/python-mlb-statsapi/wiki) | Endpoint reference, return objects, and model documentation | | [Method reference](docs/methods.md) | Method signatures and short descriptions from the original README reference | | [Usage examples](docs/examples.md) | Extended synchronous examples | +| [Stats guide](docs/stats.md) | Player, team, general, and per-game stat queries with sync and async examples | | [Async usage](docs/async.md) | Async installation, lifecycle, concurrency, and examples | | [HTTP transport](docs/http-transport.md) | Timeouts, retries, strict HTTP, exceptions, and ownership | | [Public API contract](docs/public-api.md) | Supported symbols, signatures, endpoint methods, and stability policy | From 509567c4db1e85cef3d860fc4cb1fd983e6bbbeb Mon Sep 17 00:00:00 2001 From: Matthew Spah Date: Mon, 24 Aug 2026 21:00:09 -0700 Subject: [PATCH 15/17] docs: align README with release validation --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fb5af28..2ea6568 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ The async extra installs HTTPX. Python 3.10 or newer is required. | Claim | Value | | --- | --- | | Minimum Python version | `>=3.10` | -| CI-validated versions | 3.10, 3.11, 3.12, 3.13, 3.14 | +| CI-validated versions | Python 3.10 through 3.14 | See [Python support](docs/public-api.md#python-support) for the complete policy. @@ -206,6 +206,8 @@ See the [method reference](docs/methods.md) for the full method documentation th Both clients use explicit timeouts, structured exceptions, and pooled HTTP connections. `strict_http=True` is the default. Final non-404 4xx responses raise `MlbHttpError`, while existing endpoint-specific 404 behavior is preserved. +Library-created clients send a versioned User-Agent. The current package version sends `python-mlb-statsapi/1.0.1`. See the [HTTP transport documentation](docs/http-transport.md) for the full transport contract. + The main transport exceptions are: * `MlbHttpError` From 7bef3133fb91b8a10e40e3cb30b0489f4ceabd1d Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 04:24:01 +0000 Subject: [PATCH 16/17] docs: avoid main()-shaped entry point in custom HTTPX client example Wraps the reusable async logic in a plain function so it stays valid Python without prescribing a main() entry point; the asyncio.run() wrapper is now clearly marked as just one way to invoke it. Co-authored-by: Matthew Spah <2068393+Mattsface@users.noreply.github.com> --- docs/async.md | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/async.md b/docs/async.md index 85eefa8..79079bb 100644 --- a/docs/async.md +++ b/docs/async.md @@ -152,15 +152,37 @@ import httpx from mlbstatsapi import AsyncMlb -client = httpx.AsyncClient() -try: +async def get_person_with_custom_client(client: httpx.AsyncClient, person_id: int): async with AsyncMlb(client=client) as mlb: - player = await mlb.get_person(664034) -finally: - await client.aclose() + return await mlb.get_person(person_id) +``` + +`async with` and `await` are only valid inside an `async def`, so this is +written as a plain, reusable function rather than a top-level script. Call it +however your application already enters async code — `asyncio.run(...)`, a +web framework's request handler, an existing event loop, and so on. Nothing +here requires restructuring your application around a `main()` entry point; +`get_person_with_custom_client()` itself has no opinion on how it is invoked. + +For a minimal, runnable entry point: + +```python +import asyncio + + +async def main(): + async with httpx.AsyncClient() as client: + return await get_person_with_custom_client(client, 664034) + + +asyncio.run(main()) ``` -An injected client remains caller-owned and is not closed by `AsyncMlb`. +An injected client remains caller-owned and is not closed by `AsyncMlb`. In a +real application the client is typically created once, reused across calls, +and closed by whatever code owns its lifecycle — the entry point above is +only there to show one way to run the example, not the required shape of +your application. ## Documentation boundaries From 7f5b796fad842bec0de75214aecfb935a1bb7af6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 05:01:44 +0000 Subject: [PATCH 17/17] docs: add multiple invocation examples for custom HTTPX client section Wrapping every advanced async example in a main()/asyncio.run() entry point isn't practical for readers integrating into an existing app. Show a script entry point alongside patterns for an already-running event loop, FastAPI, and interactive/notebook use with top-level await. Co-authored-by: Matthew Spah <2068393+Mattsface@users.noreply.github.com> --- docs/async.md | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/async.md b/docs/async.md index 79079bb..16af897 100644 --- a/docs/async.md +++ b/docs/async.md @@ -164,7 +164,10 @@ web framework's request handler, an existing event loop, and so on. Nothing here requires restructuring your application around a `main()` entry point; `get_person_with_custom_client()` itself has no opinion on how it is invoked. -For a minimal, runnable entry point: +Below are a few ways to invoke it, depending on how your application already +enters async code. + +**Script entry point** ```python import asyncio @@ -178,11 +181,43 @@ async def main(): asyncio.run(main()) ``` +**Inside an application that already runs on an event loop** — a web +framework's request handler, a worker task, and so on — just `await` it +directly with a client your application already owns: + +```python +async def handle_request(client: httpx.AsyncClient, person_id: int): + return await get_person_with_custom_client(client, person_id) +``` + +**FastAPI (or another ASGI framework)** + +```python +from fastapi import FastAPI + +app = FastAPI() +http_client = httpx.AsyncClient() + + +@app.get("/players/{person_id}") +async def read_player(person_id: int): + return await get_person_with_custom_client(http_client, person_id) +``` + +**Interactively, with no wrapper at all** — Jupyter/IPython and the +`python -m asyncio` REPL both support top-level `await`: + +```pycon +>>> import httpx +>>> client = httpx.AsyncClient() +>>> player = await get_person_with_custom_client(client, 664034) +>>> await client.aclose() +``` + An injected client remains caller-owned and is not closed by `AsyncMlb`. In a real application the client is typically created once, reused across calls, -and closed by whatever code owns its lifecycle — the entry point above is -only there to show one way to run the example, not the required shape of -your application. +and closed by whatever code owns its lifecycle — the examples above show a +few ways to run this, not the required shape of your application. ## Documentation boundaries