Skip to content

Repository files navigation

🏎️ OpenF1 Python Client

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

PyPI versionPyPI downloadsPublish to PyPIPython 3.10+License: MITCode style: blackPydantic v2Ruff

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:

fromopenf1_clientimportOpenF1Client# Create a clientclient=OpenF1Client()
# Get lap data for a specific driverlaps=client.laps.list(
session_key=9161,
driver_number=63,
)
forlapinlaps:
print(f"Lap {lap.lap_number}: {lap.lap_duration}s")
# Don't forget to close the client when doneclient.close()

Using Context Manager

fromopenf1_clientimportOpenF1ClientwithOpenF1Client() asclient:
# Get driver informationdrivers=client.drivers.list(session_key=9158)
fordriverindrivers:
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:

fromopenf1_clientimportOpenF1Clientclient=OpenF1Client(
username="your_email@example.com",
password="your_password",
)
# Access real-time datalatest_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 valueslaps=client.laps.list(
session_key=9161,
driver_number=63,
lap_number=8,
)

Comparison Operators

Use dictionaries with operator keys for comparisons:

# Speed >= 315 km/hfast_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 rangelocation_data=client.location.list(
session_key=9161,
driver_number=81,
date={
">": "2023-09-16T13:03:35.200",
"<": "2023-09-16T13:03:35.800",
},
)
# Lap rangestint_laps=client.laps.list(
session_key=9161,
driver_number=1,
lap_number={">=": 10, "<=": 20},
)

Using FilterBuilder

For more complex filters, use the FilterBuilder helper:

fromopenf1_clientimportOpenF1Client, FilterBuilderwithOpenF1Client() asclient:
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

EndpointDescriptionExample
🏎️ car_dataCar telemetry (~3.7 Hz)client.car_data.list(...)
👤 driversDriver informationclient.drivers.list(...)
⏱️ intervalsGap data (~4s updates)client.intervals.list(...)
🔄 lapsLap timing dataclient.laps.list(...)
📍 locationCar positions (~3.7 Hz)client.location.list(...)
🏁 meetingsGrand Prix metadataclient.meetings.list(...)
🔀 overtakesPassing events (beta)client.overtakes.list(...)
🛞 pitPit stop activityclient.pit.list(...)
📊 positionTrack positionsclient.position.list(...)
🚩 race_controlFlags, incidentsclient.race_control.list(...)
📅 sessionsSession dataclient.sessions.list(...)
🏆 session_resultFinal results (beta)client.session_result.list(...)
🚦 starting_gridGrid positions (beta)client.starting_grid.list(...)
🔧 stintsStint/tyre dataclient.stints.list(...)
📻 team_radioRadio communicationsclient.team_radio.list(...)
🌤️ weatherWeather data (~1 min)client.weather.list(...)

🛠️ Endpoint Methods

Each endpoint provides several methods:

# List all matching recordslaps=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 parsingraw_data=client.laps.list_raw(session_key=9161)
# Get CSV formatcsv_data=client.laps.list_csv(session_key=9161)
# Count matching recordscount=client.laps.count(session_key=9161, driver_number=1)

Many endpoints also provide convenience methods:

# 🔄 Lapsfastest_lap=client.laps.get_fastest_lap(session_key=9161)
flying_laps=client.laps.get_flying_laps(session_key=9161, driver_number=1)
# 📅 Sessionsraces=client.sessions.get_races(year=2023)
latest=client.sessions.get_latest()
# 🔧 Stintsstrategy=client.stints.get_tyre_strategy(session_key=9161, driver_number=1)
# 🌤️ Weatherrain=client.weather.get_rain_periods(session_key=9161)

⚙️ Configuration

fromopenf1_clientimportOpenF1Clientclient=OpenF1Client(
# 🔐 Authenticationusername="user@example.com",
password="secret",
# Or use a token directly# access_token="your_token",# 🌐 Connection settingstimeout=60.0, # Request timeout in seconds# timeout=(5.0, 30.0), # (connect, read) timeoutsmax_retries=5, # Retry failed requests# 📄 Response formatdefault_format="json", # "json" or "csv"# 🔒 SSL/TLSverify_ssl=True,
)

⚠️ Error Handling

The client provides a comprehensive exception hierarchy:

fromopenf1_clientimport (
OpenF1Client,
OpenF1Error, # Base exceptionOpenF1ConfigError, # Invalid configurationOpenF1TransportError, # Network errorsOpenF1APIError, # API errors (non-2xx)OpenF1AuthError, # 401/403 errorsOpenF1RateLimitError, # 429 errorsOpenF1NotFoundError, # 404 errorsOpenF1ServerError, # 5xx errorsOpenF1TimeoutError, # Request timeoutOpenF1ValidationError, # Data validation
)
try:
withOpenF1Client() asclient:
laps=client.laps.list(session_key=99999)
exceptOpenF1NotFoundErrorase:
print(f"❌ Session not found: {e}")
exceptOpenF1RateLimitErrorase:
print(f"⏳ Rate limited. Retry after: {e.retry_after}s")
exceptOpenF1APIErrorase:
print(f"⚠️ API error {e.status_code}: {e.message}")
exceptOpenF1Errorase:
print(f"💥 Client error: {e}")

📝 Logging

Enable debug logging to see HTTP requests and responses:

fromopenf1_clientimportsetup_loggingimportlogging# Enable debug loggingsetup_logging(logging.DEBUG)
# Or configure manuallylogging.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:

fromopenf1_clientimportOpenF1Client, Lap, DriverwithOpenF1Client() asclient:
lap: Lap=client.laps.first(session_key=9161, driver_number=1, lap_number=1)
iflap:
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

fromopenf1_clientimportOpenF1ClientwithOpenF1Client() asclient:
# Get session infosession=client.sessions.first(session_key=9161)
print(f"🏁 Session: {session.session_name} - {session.country_name}")
# Get all driversdrivers=client.drivers.list(session_key=9161)
fordriverindrivers:
# Get their fastest lapfastest=client.laps.get_fastest_lap(
session_key=9161,
driver_number=driver.driver_number,
)
# Get pit stopspit_count=client.pit.count_pit_stops(
session_key=9161,
driver_number=driver.driver_number,
)
# Get tyre strategystrategy=client.stints.get_tyre_strategy(
session_key=9161,
driver_number=driver.driver_number,
)
print(f"🏎️ {driver.name_acronym}: "f"Fastest: {fastest.lap_durationiffastestelse'N/A'}s, "f"Stops: {pit_count}, "f"Tyres: {' → '.join(strategy)}")

🌤️ Track Weather Changes

fromopenf1_clientimportOpenF1ClientwithOpenF1Client() asclient:
weather_data=client.weather.list(session_key=9161)
forwinweather_data:
rain_emoji="🌧️"ifw.rainfallelse"☀️"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

fromopenf1_clientimportOpenF1ClientfromcollectionsimportCounterwithOpenF1Client() asclient:
overtakes=client.overtakes.list(session_key=9161)
print(f"🔀 Total overtakes: {len(overtakes)}")
# Get drivers with most overtakesovertake_counts=Counter(o.driver_numberforoinovertakes)
print("\n🏆 Top overtakers:")
fordriver_num, countinovertake_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)fromopenf1_clientimportAsyncOpenF1ClientasyncwithAsyncOpenF1Client() asclient:
laps=awaitclient.laps.list(session_key=9161)

📡 Real-time Streaming

# Future streaming support (design ready)# Via MQTT or WebSockets for live dataasyncfortelemetryinclient.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

About

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

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages