Skip to main content

A production-grade Python client SDK for the OpenF1 Formula 1 API

Project description

๐ŸŽ๏ธ OpenF1 Python Client

A production-grade Python SDK for the OpenF1 API, providing easy access to real-time and historical Formula 1 data.

PyPI version PyPI downloads Publish to PyPI Python 3.10+ License: MIT Code style: black Pydantic v2 Ruff

Buy Me A Coffee


๐Ÿ“‘ Table of Contents


โœจ Features

  • ๐Ÿ”Œ Full API Coverage โ€” Access all 16 OpenF1 endpoints including telemetry, lap times, positions, weather, and more
  • ๐Ÿ”’ Type Safety โ€” Fully typed with Pydantic v2 models and comprehensive type hints
  • ๐ŸŽฏ Pythonic Filtering โ€” Use dictionaries with comparison operators for flexible queries
  • ๐Ÿ” Authentication Support โ€” OAuth2 password flow for real-time data access
  • โš ๏ธ Robust Error Handling โ€” Comprehensive exception hierarchy with detailed error information
  • ๐Ÿš€ Production Ready โ€” Automatic retries, configurable timeouts, and logging support
  • ๐Ÿ“Š Multiple Formats โ€” JSON and CSV response support

๐Ÿ“ฆ Installation

pip install OpenF1-python-client

Or install from source:

git clone https://github.com/rhtnr/OpenF1-python-client.git
cd OpenF1-python-client
pip install -e .

For development:

pip install -e ".[dev]"

๐Ÿš€ Quick Start

Basic Usage (Unauthenticated)

Historical data is available without authentication:

from openf1_client import OpenF1Client

# Create a client
client = OpenF1Client()

# Get lap data for a specific driver
laps = client.laps.list(
    session_key=9161,
    driver_number=63,
)

for lap in laps:
    print(f"Lap {lap.lap_number}: {lap.lap_duration}s")

# Don't forget to close the client when done
client.close()

Using Context Manager

from openf1_client import OpenF1Client

with OpenF1Client() as client:
    # Get driver information
    drivers = client.drivers.list(session_key=9158)

    for driver in drivers:
        print(f"{driver.name_acronym}: {driver.full_name} - {driver.team_name}")

๐Ÿ” Authenticated Usage

For real-time data and higher rate limits, authenticate with your OpenF1 credentials:

from openf1_client import OpenF1Client

client = OpenF1Client(
    username="your_email@example.com",
    password="your_password",
)

# Access real-time data
latest_session = client.sessions.first(session_key="latest")
print(f"Current session: {latest_session.session_name}")

Or use a pre-existing access token:

client = OpenF1Client(access_token="your_access_token")

๐Ÿ” Filtering Data

OpenF1 supports rich filtering with comparison operators. The client provides a Pythonic interface:

Simple Equality

# Filter by exact values
laps = client.laps.list(
    session_key=9161,
    driver_number=63,
    lap_number=8,
)

Comparison Operators

Use dictionaries with operator keys for comparisons:

# Speed >= 315 km/h
fast_telemetry = client.car_data.list(
    session_key=9159,
    driver_number=55,
    speed={">=": 315},
)

# Close intervals (< 0.5 seconds)
close_battles = client.intervals.list(
    session_key=9161,
    interval={"<": 0.5},
)

Range Filters

# Date range
location_data = client.location.list(
    session_key=9161,
    driver_number=81,
    date={
        ">": "2023-09-16T13:03:35.200",
        "<": "2023-09-16T13:03:35.800",
    },
)

# Lap range
stint_laps = client.laps.list(
    session_key=9161,
    driver_number=1,
    lap_number={">=": 10, "<=": 20},
)

Using FilterBuilder

For more complex filters, use the FilterBuilder helper:

from openf1_client import OpenF1Client, FilterBuilder

with OpenF1Client() as client:
    filters = (
        FilterBuilder()
        .eq("session_key", 9161)
        .eq("driver_number", 1)
        .gte("speed", 300)
        .lt("lap_number", 10)
        .build()
    )

    car_data = client.car_data.list(**filters)

๐Ÿ“ก Available Endpoints

Endpoint Description Example
๐ŸŽ๏ธ car_data Car telemetry (~3.7 Hz) client.car_data.list(...)
๐Ÿ‘ค drivers Driver information client.drivers.list(...)
โฑ๏ธ intervals Gap data (~4s updates) client.intervals.list(...)
๐Ÿ”„ laps Lap timing data client.laps.list(...)
๐Ÿ“ location Car positions (~3.7 Hz) client.location.list(...)
๐Ÿ meetings Grand Prix metadata client.meetings.list(...)
๐Ÿ”€ overtakes Passing events (beta) client.overtakes.list(...)
๐Ÿ›ž pit Pit stop activity client.pit.list(...)
๐Ÿ“Š position Track positions client.position.list(...)
๐Ÿšฉ race_control Flags, incidents client.race_control.list(...)
๐Ÿ“… sessions Session data client.sessions.list(...)
๐Ÿ† session_result Final results (beta) client.session_result.list(...)
๐Ÿšฆ starting_grid Grid positions (beta) client.starting_grid.list(...)
๐Ÿ”ง stints Stint/tyre data client.stints.list(...)
๐Ÿ“ป team_radio Radio communications client.team_radio.list(...)
๐ŸŒค๏ธ weather Weather data (~1 min) client.weather.list(...)

๐Ÿ› ๏ธ Endpoint Methods

Each endpoint provides several methods:

# List all matching records
laps = client.laps.list(session_key=9161, driver_number=1)

# Get first matching record (or None)
lap = client.laps.first(session_key=9161, driver_number=1, lap_number=1)

# Get raw data (dict) without model parsing
raw_data = client.laps.list_raw(session_key=9161)

# Get CSV format
csv_data = client.laps.list_csv(session_key=9161)

# Count matching records
count = client.laps.count(session_key=9161, driver_number=1)

Many endpoints also provide convenience methods:

# ๐Ÿ”„ Laps
fastest_lap = client.laps.get_fastest_lap(session_key=9161)
flying_laps = client.laps.get_flying_laps(session_key=9161, driver_number=1)

# ๐Ÿ“… Sessions
races = client.sessions.get_races(year=2023)
latest = client.sessions.get_latest()

# ๐Ÿ”ง Stints
strategy = client.stints.get_tyre_strategy(session_key=9161, driver_number=1)

# ๐ŸŒค๏ธ Weather
rain = client.weather.get_rain_periods(session_key=9161)

โš™๏ธ Configuration

from openf1_client import OpenF1Client

client = OpenF1Client(
    # ๐Ÿ” Authentication
    username="user@example.com",
    password="secret",
    # Or use a token directly
    # access_token="your_token",

    # ๐ŸŒ Connection settings
    timeout=60.0,                    # Request timeout in seconds
    # timeout=(5.0, 30.0),           # (connect, read) timeouts
    max_retries=5,                   # Retry failed requests

    # ๐Ÿ“„ Response format
    default_format="json",           # "json" or "csv"

    # ๐Ÿ”’ SSL/TLS
    verify_ssl=True,
)

โš ๏ธ Error Handling

The client provides a comprehensive exception hierarchy:

from openf1_client import (
    OpenF1Client,
    OpenF1Error,           # Base exception
    OpenF1ConfigError,     # Invalid configuration
    OpenF1TransportError,  # Network errors
    OpenF1APIError,        # API errors (non-2xx)
    OpenF1AuthError,       # 401/403 errors
    OpenF1RateLimitError,  # 429 errors
    OpenF1NotFoundError,   # 404 errors
    OpenF1ServerError,     # 5xx errors
    OpenF1TimeoutError,    # Request timeout
    OpenF1ValidationError, # Data validation
)

try:
    with OpenF1Client() as client:
        laps = client.laps.list(session_key=99999)
except OpenF1NotFoundError as e:
    print(f"โŒ Session not found: {e}")
except OpenF1RateLimitError as e:
    print(f"โณ Rate limited. Retry after: {e.retry_after}s")
except OpenF1APIError as e:
    print(f"โš ๏ธ API error {e.status_code}: {e.message}")
except OpenF1Error as e:
    print(f"๐Ÿ’ฅ Client error: {e}")

๐Ÿ“ Logging

Enable debug logging to see HTTP requests and responses:

from openf1_client import setup_logging
import logging

# Enable debug logging
setup_logging(logging.DEBUG)

# Or configure manually
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("openf1_client")
logger.setLevel(logging.DEBUG)

๐Ÿ“Š Data Models

All responses are parsed into Pydantic models with full type annotations:

from openf1_client import OpenF1Client, Lap, Driver

with OpenF1Client() as client:
    lap: Lap = client.laps.first(session_key=9161, driver_number=1, lap_number=1)

    if lap:
        print(f"Lap duration: {lap.lap_duration}")
        print(f"Sector 1: {lap.duration_sector_1}")
        print(f"Sector 2: {lap.duration_sector_2}")
        print(f"Sector 3: {lap.duration_sector_3}")
        print(f"Speed trap: {lap.st_speed} km/h")

๐Ÿ’ก Examples

๐Ÿ Analyze a Race

from openf1_client import OpenF1Client

with OpenF1Client() as client:
    # Get session info
    session = client.sessions.first(session_key=9161)
    print(f"๐Ÿ Session: {session.session_name} - {session.country_name}")

    # Get all drivers
    drivers = client.drivers.list(session_key=9161)

    for driver in drivers:
        # Get their fastest lap
        fastest = client.laps.get_fastest_lap(
            session_key=9161,
            driver_number=driver.driver_number,
        )

        # Get pit stops
        pit_count = client.pit.count_pit_stops(
            session_key=9161,
            driver_number=driver.driver_number,
        )

        # Get tyre strategy
        strategy = client.stints.get_tyre_strategy(
            session_key=9161,
            driver_number=driver.driver_number,
        )

        print(f"๐ŸŽ๏ธ {driver.name_acronym}: "
              f"Fastest: {fastest.lap_duration if fastest else 'N/A'}s, "
              f"Stops: {pit_count}, "
              f"Tyres: {' โ†’ '.join(strategy)}")

๐ŸŒค๏ธ Track Weather Changes

from openf1_client import OpenF1Client

with OpenF1Client() as client:
    weather_data = client.weather.list(session_key=9161)

    for w in weather_data:
        rain_emoji = "๐ŸŒง๏ธ" if w.rainfall else "โ˜€๏ธ"
        print(f"{rain_emoji} {w.date}")
        print(f"   ๐ŸŒก๏ธ Air: {w.air_temperature}ยฐC")
        print(f"   ๐Ÿ›ฃ๏ธ Track: {w.track_temperature}ยฐC")
        print(f"   ๐Ÿ’ง Humidity: {w.humidity}%")

๐Ÿ”€ Find Overtakes

from openf1_client import OpenF1Client
from collections import Counter

with OpenF1Client() as client:
    overtakes = client.overtakes.list(session_key=9161)

    print(f"๐Ÿ”€ Total overtakes: {len(overtakes)}")

    # Get drivers with most overtakes
    overtake_counts = Counter(o.driver_number for o in overtakes)

    print("\n๐Ÿ† Top overtakers:")
    for driver_num, count in overtake_counts.most_common(5):
        driver = client.drivers.first(
            session_key=9161,
            driver_number=driver_num,
        )
        print(f"   {driver.name_acronym}: {count} overtakes")

๐Ÿ”ฎ Future Enhancements

The client is designed to be easily extended. Planned additions:

โšก Async Support

# Future async client (design ready, not yet implemented)
from openf1_client import AsyncOpenF1Client

async with AsyncOpenF1Client() as client:
    laps = await client.laps.list(session_key=9161)

๐Ÿ“ก Real-time Streaming

# Future streaming support (design ready)
# Via MQTT or WebSockets for live data
async for telemetry in client.car_data.stream(driver_number=1):
    print(f"๐ŸŽ๏ธ Speed: {telemetry.speed} km/h")

๐Ÿค Contributing

Contributions are welcome! Please read our Contributing Guide for details.

# Install development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run type checking
mypy src/openf1_client

# Format code
black src tests

# Lint code
ruff check src tests

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


๐Ÿ™ Acknowledgements

  • ๐ŸŽ๏ธ OpenF1 for providing the excellent Formula 1 data API
  • โค๏ธ The Formula 1 community for their passion and support

If you find this project useful, consider supporting its development:

Buy Me A Coffee

Made with โค๏ธ for the F1 community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openf1_python_client-1.0.1.tar.gz (43.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openf1_python_client-1.0.1-py3-none-any.whl (51.0 kB view details)

Uploaded Python 3

File details

Details for the file openf1_python_client-1.0.1.tar.gz.

File metadata

  • Download URL: openf1_python_client-1.0.1.tar.gz
  • Upload date:
  • Size: 43.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for openf1_python_client-1.0.1.tar.gz
Algorithm Hash digest
SHA256 fc9d2d8df84d79527989ac5283423b7f9701e268fc7b532115d2651a1aea5dca
MD5 01bfd3d449d7160e44326cd5527bc47a
BLAKE2b-256 b5b4b5aba8ebb6e4ba4b6631b02520b7ebff0ed0f59ec5eff529f973b04e52d8

See more details on using hashes here.

Provenance

The following attestation bundles were made for openf1_python_client-1.0.1.tar.gz:

Publisher: workflow.yml on rhtnr/OpenF1-python-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openf1_python_client-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for openf1_python_client-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 483ea92dcb937166b258dcba20296152920047d8c7bdfdf735fccf71f9e1b9f5
MD5 27c2d695125d7c2f844acf110a5314b0
BLAKE2b-256 e127315d99be673cf8714ff992beae4752b48f5875f58f83c9f88789575dc8d6

See more details on using hashes here.

Provenance

The following attestation bundles were made for openf1_python_client-1.0.1-py3-none-any.whl:

Publisher: workflow.yml on rhtnr/OpenF1-python-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page