Metadata-Version: 2.5
Name: pitchapi
Version: 0.1.5
Summary: Python SDK for the PitchAPI football-data API
Project-URL: Homepage, https://pitchapi.dev
Project-URL: Documentation, https://pitchapi.dev/#sdks
Project-URL: Changelog, https://pitchapi.dev/#changelog
Author: PitchAPI
License-Expression: MIT
License-File: LICENSE
Keywords: analytics,api,football,sdk,soccer,xg
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx>=0.24
Provides-Extra: dev
Requires-Dist: mypy<2,>=1.5; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: ruff<0.17,>=0.6; extra == 'dev'
Description-Content-Type: text/markdown

# pitchapi — Python SDK

Typed Python client for the [PitchAPI](https://pitchapi.dev) football-data API.
Match results, shots, xG, lineups, momentum, events, player stats, head-to-head,
and advanced analytics derived from the event feed.

- Sync **and** async clients over one shared core (`httpx`)
- Plain `dataclass` response models — a faithful mirror of the API's JSON, built
  through a small `from_dict` converter (no Pydantic, one dependency)
- Typed exceptions mapped from the API's stable `error.code`
- Automatic retries on `429`/`5xx` with `Retry-After` honoured

## Install

```bash
pip install pitchapi
```

Requires Python 3.9+.

## Quick start

```python
from pitchapi import PitchAPI

with PitchAPI(api_key="pk_live_...") as client:
    day = client.date.get("2026-08-27")
    for m in day.matches:
        print(m.home_team.name, m.score_home, "-", m.score_away, m.away_team.name)

    match = client.matches.get("m_4DP2fy")
    shots = client.matches.shots(match.id)
    adv = client.matches.advanced(match.id)          # team rollups
    net = client.matches.advanced_network(match.id)  # pass networks
```

The key can also come from the `PITCHAPI_API_KEY` environment variable, in which
case `PitchAPI()` needs no arguments.

## Async

```python
import asyncio
from pitchapi import AsyncPitchAPI

async def main():
    async with AsyncPitchAPI() as client:
        league = await client.leagues.get("l_0bfbkO")
        matches = await client.leagues.matches(league.id, season="2025/2026")
        print(len(matches.matches), "matches")

asyncio.run(main())
```

## Namespaces

| Namespace | Methods |
|---|---|
| `client.date` | `get(date, status=None)` — `date` is a `str` (`YYYY-MM-DD`) or a `datetime.date` |
| `client.matches` | `get`, `shots`, `shot`, `events`, `lineups`, `momentum`, `stats`, `players`, `player`, `player_shots`, `h2h`, `advanced`, `advanced_network`, `advanced_players`, `advanced_player`, `heatmaps(id, frame=None)` |
| `client.leagues` | `list`, `get`, `matches(id, season=None, status=None)` |
| `client.teams` | `get` |
| `client.players` | `get` |

Every method returns a typed dataclass from `pitchapi.models`.

Per-player match `stats` is a list of `PlayerStatGroup` — `top_stats`, `attack`,
`defense`, `duels` — and which groups appear depends on position and
involvement. Each group's `stats` is keyed by display label, but the label is
presentation text: branch on the entry's `key`.

```python
for group in client.matches.players("m_4DP2fy")[0].stats:
    for label, entry in group.stats.items():
        s = entry.stat
        # integer and double carry a value; fractionWithPercentage adds a total
        print(group.key, entry.key, s.type, s.value, s.total)
```

## Upcoming fixtures

Match listings return played matches by default. Pass `status` to reach
scheduled ones — `"upcoming"` for fixtures that have not kicked off, `"all"` for
both. An upcoming match carries a kickoff `time_utc` and a `status`, but its
scores are `None` until it is played.

```python
for m in client.date.get("2026-09-01", status="upcoming").matches:
    print(m.time_utc, m.home_team.name, "vs", m.away_team.name)

# Within a season. The season is resolved first, so asking for upcoming
# fixtures of a finished campaign is an empty list, not next season's.
client.leagues.matches("l_0bfbkO", season="2025/2026", status="all")
```

Lineups for a fixture may be a pre-match prediction rather than the real XI.
`confirmed` is the flag to branch on; `lineup_type` carries the source's own
label for a prediction and is `None` once the lineup is confirmed.

```python
lineups = client.matches.lineups("m_4DP2fy")
if lineups.home.confirmed:
    print(lineups.home.formation, [p.name for p in lineups.home.starters])
else:
    print("predicted only:", lineups.home.lineup_type)
```

## Errors

```python
from pitchapi import NotFoundError, PlanUpgradeRequiredError, RateLimitError

try:
    client.matches.advanced("m_unprocessed")
except NotFoundError as e:
    # code is RESOURCE_NOT_FOUND or ANALYTICS_UNAVAILABLE
    print(e.code, e.request_id)
except PlanUpgradeRequiredError:
    ...  # league is Pro-only
except RateLimitError as e:
    print("retry after", e.retry_after, "s")
```

All exceptions derive from `pitchapi.PitchAPIError` and carry `code`,
`status_code`, and `request_id` where available.

## Configuration

```python
PitchAPI(
    api_key="pk_live_...",
    base_url="https://api.pitchapi.dev",  # override for self-hosting/tests
    timeout=30.0,
    max_retries=2,                        # 429/5xx + network errors; 0 disables
)
```

## Development

```bash
pip install -e ".[dev]"
pytest              # tests use httpx.MockTransport — no network
mypy                # scoped to src/ by pyproject
ruff check .
ruff format --check .
```

## OpenAPI

A full OpenAPI 3.1 description of the API lives at
[`openapi/openapi.yaml`](../../openapi/openapi.yaml) in the repository root. The
dataclass models in this SDK mirror its schemas one-to-one.

## License

This client library is released under the [MIT License](LICENSE).

The licence covers the SDK source only. Access to the PitchAPI service and the
football data it returns is governed separately by the PitchAPI terms of
service — an MIT-licensed client does not grant any right to the data.
