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.
๐ Table of Contents
- Features
- Installation
- Quick Start
- Filtering Data
- Available Endpoints
- Endpoint Methods
- Configuration
- Error Handling
- Logging
- Data Models
- Examples
- Future Enhancements
- Contributing
- License
- Acknowledgements
โจ 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-client
Or install from source:
git clone https://github.com/YOUR_USERNAME/openf1-python.git
cd openf1-python
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:
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openf1_python_client-1.0.0.tar.gz.
File metadata
- Download URL: openf1_python_client-1.0.0.tar.gz
- Upload date:
- Size: 43.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef24b68a31d86c27a2b016a6afd5e4c6b764180889c727e041600032df8ddb87
|
|
| MD5 |
c7297a0cc21627af11ba28d67868bba2
|
|
| BLAKE2b-256 |
b5d9d167bfacc5d986a9edc1a07d3fc67ee87c356064b6d46878b547336efba0
|
Provenance
The following attestation bundles were made for openf1_python_client-1.0.0.tar.gz:
Publisher:
workflow.yml on rhtnr/OpenF1-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openf1_python_client-1.0.0.tar.gz -
Subject digest:
ef24b68a31d86c27a2b016a6afd5e4c6b764180889c727e041600032df8ddb87 - Sigstore transparency entry: 732555303
- Sigstore integration time:
-
Permalink:
rhtnr/OpenF1-python-client@98fc143ee900a99f1b0244ad7e928ccef432a009 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rhtnr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@98fc143ee900a99f1b0244ad7e928ccef432a009 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file openf1_python_client-1.0.0-py3-none-any.whl.
File metadata
- Download URL: openf1_python_client-1.0.0-py3-none-any.whl
- Upload date:
- Size: 50.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6af5f6545bef36720bd0caf691f247362e6f2f161817d326a73df772b2604232
|
|
| MD5 |
c59b142ff9da1cd9a32a803c2ef8af1a
|
|
| BLAKE2b-256 |
054d2dfa921d0ff03757de1f5d6c9c9bf0ca9311c723f7216b7dc1e9d894905b
|
Provenance
The following attestation bundles were made for openf1_python_client-1.0.0-py3-none-any.whl:
Publisher:
workflow.yml on rhtnr/OpenF1-python-client
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
openf1_python_client-1.0.0-py3-none-any.whl -
Subject digest:
6af5f6545bef36720bd0caf691f247362e6f2f161817d326a73df772b2604232 - Sigstore transparency entry: 732555310
- Sigstore integration time:
-
Permalink:
rhtnr/OpenF1-python-client@98fc143ee900a99f1b0244ad7e928ccef432a009 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/rhtnr
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
workflow.yml@98fc143ee900a99f1b0244ad7e928ccef432a009 -
Trigger Event:
workflow_dispatch
-
Statement type: