Skip to content

DivyamSamarwal/pyopenf1

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🏎️ pyopenf1

A production-grade, asynchronous Python wrapper for the OpenF1 API.

PyPI CI Python versions License


✨ Features

  • Fully Async β€” Built on httpx.AsyncClient with first-class async/await support.
  • Sync Wrapper β€” OpenF1Client for users who don't need async.
  • All 18 Endpoints β€” Complete coverage: telemetry, laps, drivers, sessions, weather, pit stops, stints, overtakes, race control, team radio, championship standings, results, starting grid, and more.
  • Pydantic V2 Models β€” Every response is validated and returned as a strict, typed model.
  • Auto-Retry β€” Exponential backoff on 429/5xx via tenacity.
  • Rate Limiting β€” Built-in client-side throttle (3 req/s free tier).
  • Response Caching β€” Optional in-memory TTL cache.
  • CLI Tool β€” Query the API from your terminal.
  • DataFrame Support β€” Optional pandas integration.
  • Production-Ready β€” Custom exceptions, structured logging, connection pooling.

πŸ“¦ Installation

pip install pyopenf1

With pandas support:

pip install pyopenf1[pandas]

πŸš€ Quickstart

Async (recommended)

import asyncio
from pyopenf1 import AsyncOpenF1Client

async def main() -> None:
    async with AsyncOpenF1Client() as client:
        # Fetch telemetry
        car_data = await client.telemetry.get_car_data(driver_number=1, session_key=9159)
        for entry in car_data[:5]:
            print(f"Speed: {entry.speed} km/h | Gear: {entry.n_gear}")

        # Fetch drivers
        drivers = await client.drivers.get_drivers(session_key=9158)
        for d in drivers[:3]:
            print(f"#{d.driver_number} {d.full_name} - {d.team_name}")

asyncio.run(main())

Sync

from pyopenf1 import OpenF1Client

with OpenF1Client() as client:
    drivers = client.drivers.get_drivers(session_key=9158)
    for d in drivers:
        print(f"{d.name_acronym} - {d.team_name}")

CLI

pyopenf1 car-data --driver 1 --session 9159 --format table
pyopenf1 drivers --session 9158 --format json
pyopenf1 weather --meeting 1208 --format csv --output weather.csv

DataFrame

from pyopenf1.ext.pandas import to_dataframe

data = await client.telemetry.get_car_data(driver_number=1)
df = to_dataframe(data)
print(df.describe())

βš™οΈ Configuration

async with AsyncOpenF1Client(
    cache_ttl=300.0,        # Cache responses for 5 minutes
    max_retries=5,          # Retry up to 5 times
    max_per_second=6.0,     # Sponsor-tier rate limit
    max_per_minute=60.0,
) as client:
    ...

πŸ“‘ Available Endpoints

Namespace Methods OpenF1 Endpoints
client.telemetry get_car_data(), get_location() /car_data, /location
client.sessions get_sessions(), get_meetings() /sessions, /meetings
client.drivers get_drivers() /drivers
client.timing get_laps(), get_intervals(), get_positions() /laps, /intervals, /position
client.race get_race_control(), get_pit_stops(), get_stints(), get_overtakes() /race_control, /pit, /stints, /overtakes
client.championship get_drivers_championship(), get_teams_championship() /championship_drivers, /championship_teams
client.results get_session_results(), get_starting_grid() /session_result, /starting_grid
client.weather get_weather() /weather
client.team_radio get_team_radio() /team_radio

πŸ—οΈ Architecture

pyopenf1/
β”œβ”€β”€ __init__.py              # Public API surface
β”œβ”€β”€ client.py                # AsyncOpenF1Client facade
β”œβ”€β”€ sync_client.py           # OpenF1Client (sync wrapper)
β”œβ”€β”€ cli.py                   # Click CLI
β”œβ”€β”€ exceptions.py            # Custom exception hierarchy
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ http_client.py       # httpx wrapper + retry + logging
β”‚   β”œβ”€β”€ rate_limiter.py      # Token-bucket rate limiter
β”‚   └── cache.py             # In-memory TTL cache
β”œβ”€β”€ models/                  # Pydantic V2 data models
β”‚   β”œβ”€β”€ telemetry.py         # CarData, Location
β”‚   β”œβ”€β”€ session.py           # Session, Meeting
β”‚   β”œβ”€β”€ driver.py            # Driver
β”‚   β”œβ”€β”€ timing.py            # Lap, Interval, Position
β”‚   β”œβ”€β”€ race.py              # RaceControl, Pit, Stint, Overtake
β”‚   β”œβ”€β”€ championship.py      # ChampionshipDriver, ChampionshipTeam
β”‚   β”œβ”€β”€ results.py           # SessionResult, StartingGrid
β”‚   β”œβ”€β”€ weather.py           # Weather
β”‚   └── team_radio.py        # TeamRadio
β”œβ”€β”€ endpoints/               # API endpoint classes
β”‚   β”œβ”€β”€ telemetry_api.py
β”‚   β”œβ”€β”€ session_api.py
β”‚   β”œβ”€β”€ driver_api.py
β”‚   β”œβ”€β”€ timing_api.py
β”‚   β”œβ”€β”€ race_api.py
β”‚   β”œβ”€β”€ championship_api.py
β”‚   β”œβ”€β”€ results_api.py
β”‚   β”œβ”€β”€ weather_api.py
β”‚   └── team_radio_api.py
└── ext/
    └── pandas.py            # Optional DataFrame integration

πŸ§ͺ Development

# Install dev dependencies
poetry install

# Lint & format
poetry run ruff check .
poetry run ruff format .

# Type check
poetry run mypy pyopenf1/

# Test
poetry run pytest -v

# Build docs
poetry run mkdocs serve

πŸ“„ License

Distributed under the MIT License. See LICENSE for details.