Metadata-Version: 2.4
Name: nflmeta
Version: 0.3.0
Summary: Official Python SDK for the NFLMeta API
Author: NFLMeta
License: MIT
Project-URL: Homepage, https://nflmeta.org/api-docs/sdk
Project-URL: Documentation, https://nflmeta.org/api-docs
Project-URL: Source, https://github.com/philippebourdon/NFLMeta
Keywords: nfl,nflmeta,sports,api,sdk,python
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# `nflmeta`

## 0.3.0: game injuries, participants and scoring

```python
injuries = client.games.injuries(22850)
participants = client.stats.players.game_participants(
    season_year=2026, week=6, position="WR", limit=50, offset=0,
)
scoring = client.games.live_player_stats(22850)
print(scoring.data.get("scoring_readiness_scopes"))
events = client.games.defense_special_teams(22850)
print(events.meta.get("scoring_readiness_scopes"))
```

Use an initialized server-side client. Game-return outcomes remain separate
from weekly designations and postgame medical reporting. Keep `observed_state`,
`confirmed_outcome`, `reported_at` and uncertainty distinct; these outcomes do
not establish future availability or a medical prognosis.

`game_participants` covers recorded REG snap participants at QB, RB, WR and TE
for seasons 2013–2026. Seasons before 2021 have at most 17 regular-season weeks;
later seasons have 18. REST/SDK pages support `limit` 1–250 and `offset` 0–10000.
Use `participant_row_key` as the stable row identity. Preserve unresolved player
keys and `None` statistics. Inspect `coverage_status`, `pending_game_ids`,
`participation_verification` and `has_more`; success does not mean a complete
week. Each returned injury or participant record costs one row; coverage
metadata costs no extra rows.

Scoring-readiness scopes have independent evidence requirements. Unknown and
pending values are not zero. Live statistics remain provisional; honor
`recommended_poll_seconds` (at least 30 seconds). Historical scoring verification
covers explicitly supported examples, not every historical game. Dictionary
responses retain all API fields and metadata unchanged.

## Current-season helpers

```python
client.teams.cap_space(season=2026, team_abbr="NE")
client.games.inactives(22773)
client.injuries.list(season=2026, week=1)
client.teams.injuries("NE", season=2026, week=1)
client.players.injuries("player-key", season=2026)
client.players.resolve(["patrick-mahomes", "josh-allen"])
client.teams.roster("NE", year=2026, count=True)
```

Use an initialized server-side client. Cap space is a daily estimate; inspect
`response.meta["observed_at"]` and `response.meta["stale"]`. Inactive status
`not_available` does not mean everyone is active. Injury
`response.meta["current_reserves"]` is current, not historical; distinguish
`reported_pending` from `confirmed` and `report_status` from `game_status`.
List totals may be None or absent. Request count=True where supported, or use
returned/has_more. Existing live and historical analytics methods are unchanged.
Bulk player resolution accepts 1–100 keys per request. Use returned
`requested_player_key` and `player_key` to update your own mapping;
`meta["unresolved"]` names keys with no match. Only returned player records
count toward your row allowance.

Official Python SDK for the NFLMeta API.

## Install

```bash
pip install nflmeta
```

## Quickstart

```python
from nflmeta import NFLMetaClient

client = NFLMetaClient(api_key="YOUR_KEY")

team = client.teams.get("PIT", season=2025)
player = client.players.identity("josh-allen-1996")
usage = client.usage.get()
live = client.live_scores.get()

print(team.data["displayName"])
print(player.data["display_name"])
print(usage.data["quota_remaining"])
```

## What The SDK Does

- sends `X-NFLMeta-Key` automatically when you provide `api_key`
- preserves the API envelope shape: `data`, optional `meta`, plus parsed rate-limit headers
- throws typed HTTP errors for common failure cases
- exposes the main public API surfaces as resource clients instead of forcing raw URL construction
- still gives you a low-level `client.get(path, query={...})` escape hatch for any route not wrapped yet

## Configuration

```python
client = NFLMetaClient(
    api_key="YOUR_KEY",
    base_url="https://nflmeta.org",
    timeout=10.0,
)
```

You can also pass default headers or a custom `transport(url, headers, timeout)` callable if you want the SDK to run through your own HTTP layer in tests or internal tooling.

## Resource Coverage

The Python SDK wraps the same main surfaces as the TypeScript package:

- `health`
- `live_scores`
- `usage`
- `metadata`
- `seasons`
- `teams`
- `players`
- `games`
- `plays`
- `playoff_games`
- `standings`
- `playoffs`
- `super_bowls`
- `history`
- `hall_of_fame`
- `contributors`
- `executives`
- `staff`
- `coaches`
- `assets`
- `all_star_games`
- `stats.players`
- `reference`

```python
client.live_scores.get()
client.plays.summary(season=2024, group_by="team")
client.plays.leaders(season=2024, role="passer")
client.plays.list(game_id=21390, skip_markers=True)
```

`plays.list` is metered per play and the API refuses an unnarrowed request with
`400 invalid_request`: pass `game_id`, or `player`, or `season` together with one
of `week`, `team` or `opponent`. `plays.summary` and `plays.leaders` answer
season-wide questions server-side in tens of rows.

## Errors

- `NFLMetaBadRequestError`
- `NFLMetaUnauthorizedError`
- `NFLMetaNotFoundError`
- `NFLMetaRateLimitError`
- `NFLMetaTimeoutError`
- `NFLMetaError`

## Escape Hatch

```python
raw = client.get("/api/v1/reference/team-colors", query={"limit": 10})
print(raw.data)
```

The path is resolved against `base_url` and has to stay there. A URL on another
origin is refused with `NFLMetaInvalidUrlError` **before** any header is built,
and a redirect that would leave the origin is refused rather than followed —
your API key travels in the `X-NFLMeta-Key` header, and `urllib` forwards every
request header across a cross-origin redirect. Same-origin absolute URLs still
work.

### Selective live-score polling

```python
client.live_scores.get(phase="in")  # Includes halftime and overtime
client.live_scores.get(game_id=12345)
client.live_scores.get(game_ids="12345,12346")  # Comma-separated string
```

Filters select the current live-score window, not historical games. Only returned games count toward row usage; empty results cost zero rows. Request limits still apply. Poll IDs without `phase="in"` to receive final scores. These optional arguments require an SDK release containing this change; existing SDK clients can call the filtered REST URL directly.

## 0.2.0: selected events, historical practice and identity-aware depth charts

Keep returned metadata: unknown distance or attribution is not zero; historical records are not certified pre-kickoff snapshots. Depth-chart `identity_status` describes identity, not vacancy. Player lookup resolves retained aliases; preserve your own player/Favorites IDs. A one-time Sleeper crosswalk can be requested through support; no public external-ID lookup is provided.

```python
events = client.games.defense_special_teams(11565, limit=100, offset=0)
chart = client.teams.depth_chart("NE")
league_charts = client.depth_charts.list(season=2026, limit=100)
changes = client.depth_charts.changes(team="NE", days=7)
history = client.rosters.list(season=2020, week=2)
practice = client.injuries.list(season=2020, date="2020-09-16")
scores = client.live_scores.get(phase="in", game_ids="22834,22835")
```


Live scores return `play_sync` unchanged in `APIResponse.data`. When status is
`matched`, match `last_play_number` to `play_number` for the same `game_id` in
`/api/v1/plays`. Otherwise keep alignment unknown/pending. A matching reference
establishes availability of that play, not simultaneous upstream publication.

## Live play revisions

See [live correction contract](../../docs/live-play-revisions.md) for the game-scoped cursor feed, baseline semantics and finalized-data limits. The new game helper/tool preserves next_cursor and material revisions.

## Continuous live collectors

For a runnable standard-library example with SQLite cursor checkpoints,
correction upserts, score/play alignment, rate limits and scheduled retries,
see [live polling example](examples/LIVE_POLLING.md) and
[live_polling.py](examples/live_polling.py).

Set `timeout` explicitly for a continuously running collector (for example `15.0` for live polling).
The SDK does not retry automatically. Maintain independent polling and error state
for each game and endpoint. Retry network failures and HTTP 5xx responses with
bounded exponential backoff and jitter; honor `Retry-After` on HTTP 429 and inspect
`X-RateLimit-Policy` to distinguish a short request limit from a monthly allowance.
Do not retry a monthly allowance refusal every few seconds. Persist the last
successfully processed play-change cursor only after processing its page; retain
it on failed requests. A successful empty page means no changes in that page,
whereas a failed request means freshness is unknown. Keep advancing one healthy
game when another game's request fails. An unchanged game clock during a break
is not, by itself, evidence of an outage.
