openwec 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openwec-0.2.0 → openwec-0.2.2}/PKG-INFO +38 -23
- openwec-0.2.2/README.md +120 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec/__init__.py +1 -1
- {openwec-0.2.0 → openwec-0.2.2}/openwec/session.py +54 -1
- {openwec-0.2.0 → openwec-0.2.2}/openwec.egg-info/PKG-INFO +38 -23
- {openwec-0.2.0 → openwec-0.2.2}/pyproject.toml +1 -1
- openwec-0.2.0/README.md +0 -105
- {openwec-0.2.0 → openwec-0.2.2}/LICENSE +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec/client.py +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec/plotting.py +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec.egg-info/SOURCES.txt +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec.egg-info/dependency_links.txt +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec.egg-info/requires.txt +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/openwec.egg-info/top_level.txt +0 -0
- {openwec-0.2.0 → openwec-0.2.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwec
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Python SDK for endurance racing data — WEC, ELMS, ALMS, Le Mans Cup, IMSA
|
|
5
5
|
Author: Paloma C.
|
|
6
6
|
License-Expression: MIT
|
|
@@ -61,13 +61,11 @@ pip install openwec[plotting]
|
|
|
61
61
|
```python
|
|
62
62
|
import openwec
|
|
63
63
|
|
|
64
|
-
#
|
|
64
|
+
# Public endpoints work without a key.
|
|
65
65
|
# Request a free key at https://openwec.com/api-keys
|
|
66
|
-
openwec.configure(
|
|
67
|
-
api_key="your-key-here" # required for laps and analytics
|
|
68
|
-
)
|
|
66
|
+
openwec.configure(api_key="your-key-here") # required for laps and analytics
|
|
69
67
|
|
|
70
|
-
# Load any session
|
|
68
|
+
# Load any session — WEC, ELMS, ALMS, Le Mans Cup, or IMSA
|
|
71
69
|
session = openwec.Session("WEC", 2026, "Le Mans", "Race")
|
|
72
70
|
print(session)
|
|
73
71
|
# Session(WEC 2026 LE MANS — Race, id=6556)
|
|
@@ -80,11 +78,16 @@ print(results[["position", "car_number", "car_class", "team", "drivers"]].head(1
|
|
|
80
78
|
laps = session.laps(car="7")
|
|
81
79
|
print(laps[["lap_number", "lap_time_s", "s1_s", "s2_s", "s3_s"]].head())
|
|
82
80
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
# Endurance-specific: filter laps by driver within a shared-drive car
|
|
82
|
+
# (unique to endurance racing — not possible in FastF1)
|
|
83
|
+
conway_laps = session.driver_laps("Conway", car="7")
|
|
84
|
+
kobayashi_laps = session.driver_laps("Kobayashi", car="7")
|
|
85
|
+
print(f"Conway pace: {conway_laps['lap_time_s'].median():.3f}s")
|
|
86
|
+
print(f"Kobayashi pace: {kobayashi_laps['lap_time_s'].median():.3f}s")
|
|
86
87
|
|
|
87
|
-
#
|
|
88
|
+
# Stints and pace
|
|
89
|
+
stints = session.stints(car_class="HYPERCAR")
|
|
90
|
+
pace = session.pace(car_class="HYPERCAR")
|
|
88
91
|
pit_window = session.pit_window(car="7")
|
|
89
92
|
|
|
90
93
|
# Plots (requires matplotlib)
|
|
@@ -105,13 +108,13 @@ session.plot_gap_to_leader(car_class="HYPERCAR")
|
|
|
105
108
|
| Le Mans Cup | 2017–2026 |
|
|
106
109
|
| IMSA | 2014–2026 |
|
|
107
110
|
|
|
108
|
-
**1.
|
|
111
|
+
**1.96M+ laps** across all series.
|
|
109
112
|
|
|
110
113
|
---
|
|
111
114
|
|
|
112
115
|
## API key
|
|
113
116
|
|
|
114
|
-
Public endpoints (results, driver profiles, team profiles) require no key.
|
|
117
|
+
Public endpoints (results, driver profiles, team profiles, driver search) require no key.
|
|
115
118
|
Lap-by-lap data and analytics endpoints require a free API key.
|
|
116
119
|
|
|
117
120
|
→ **[Request a key at openwec.com/api-keys](https://openwec.com/api-keys)**
|
|
@@ -120,17 +123,29 @@ Lap-by-lap data and analytics endpoints require a free API key.
|
|
|
120
123
|
|
|
121
124
|
## Session methods
|
|
122
125
|
|
|
123
|
-
| Method |
|
|
124
|
-
|
|
125
|
-
| `.results()` | DataFrame | No |
|
|
126
|
-
| `.laps(car=None)` |
|
|
127
|
-
| `.
|
|
128
|
-
| `.
|
|
129
|
-
| `.
|
|
130
|
-
| `.
|
|
131
|
-
| `.
|
|
132
|
-
| `.
|
|
133
|
-
| `.
|
|
126
|
+
| Method | Description | Key required |
|
|
127
|
+
|--------|-------------|-------------|
|
|
128
|
+
| `.results()` | Race classification as DataFrame | No |
|
|
129
|
+
| `.laps(car=None)` | Lap-by-lap data | Yes |
|
|
130
|
+
| `.driver_laps(name, car=None)` | Laps filtered by driver name ⚑ | Yes |
|
|
131
|
+
| `.stints(car_class=None)` | Stint breakdown per car | Yes |
|
|
132
|
+
| `.pace(car_class=None)` | Average green-flag pace | Yes |
|
|
133
|
+
| `.gaps(car_class=None)` | Gap to leader evolution | Yes |
|
|
134
|
+
| `.pit_window(car=None)` | Optimal pit window estimate | Yes |
|
|
135
|
+
| `.plot_lap_evolution(car)` | Lap time chart | Yes |
|
|
136
|
+
| `.plot_stint_chart()` | Strategy/stint chart | Yes |
|
|
137
|
+
| `.plot_gap_to_leader()` | Gap to leader chart | Yes |
|
|
138
|
+
|
|
139
|
+
⚑ **Unique to endurance racing** — multiple drivers share a car. `driver_laps()` has no equivalent in FastF1.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Example notebooks
|
|
144
|
+
|
|
145
|
+
| Notebook | Description |
|
|
146
|
+
|----------|-------------|
|
|
147
|
+
| [le_mans_2026.ipynb](examples/le_mans_2026.ipynb) | Full race analysis — results, pace, stints, plots |
|
|
148
|
+
| [driver_career.ipynb](examples/driver_career.ipynb) | Cross-series career analysis for a driver |
|
|
134
149
|
|
|
135
150
|
---
|
|
136
151
|
|
openwec-0.2.2/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# openwec
|
|
2
|
+
|
|
3
|
+
**Python SDK for endurance racing data — WEC, ELMS, ALMS, Le Mans Cup, IMSA.**
|
|
4
|
+
|
|
5
|
+
Inspired by [FastF1](https://github.com/theOehrly/Fast-F1), OpenWEC gives you lap-by-lap timing data, stint analytics, and race results from endurance racing as pandas DataFrames — in one line.
|
|
6
|
+
|
|
7
|
+
→ **[openwec.com](https://openwec.com)** — Live dashboard
|
|
8
|
+
→ **[api.openwec.com/docs](https://api.openwec.com/docs)** — API reference
|
|
9
|
+
→ **[github.com/palomacdev/openwec](https://github.com/palomacdev/openwec)** — Source
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install openwec
|
|
17
|
+
|
|
18
|
+
# With plotting support
|
|
19
|
+
pip install openwec[plotting]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick start
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import openwec
|
|
28
|
+
|
|
29
|
+
# Public endpoints work without a key.
|
|
30
|
+
# Request a free key at https://openwec.com/api-keys
|
|
31
|
+
openwec.configure(api_key="your-key-here") # required for laps and analytics
|
|
32
|
+
|
|
33
|
+
# Load any session — WEC, ELMS, ALMS, Le Mans Cup, or IMSA
|
|
34
|
+
session = openwec.Session("WEC", 2026, "Le Mans", "Race")
|
|
35
|
+
print(session)
|
|
36
|
+
# Session(WEC 2026 LE MANS — Race, id=6556)
|
|
37
|
+
|
|
38
|
+
# Results as a DataFrame (no key needed)
|
|
39
|
+
results = session.results()
|
|
40
|
+
print(results[["position", "car_number", "car_class", "team", "drivers"]].head(10))
|
|
41
|
+
|
|
42
|
+
# Lap-by-lap data (key required)
|
|
43
|
+
laps = session.laps(car="7")
|
|
44
|
+
print(laps[["lap_number", "lap_time_s", "s1_s", "s2_s", "s3_s"]].head())
|
|
45
|
+
|
|
46
|
+
# Endurance-specific: filter laps by driver within a shared-drive car
|
|
47
|
+
# (unique to endurance racing — not possible in FastF1)
|
|
48
|
+
conway_laps = session.driver_laps("Conway", car="7")
|
|
49
|
+
kobayashi_laps = session.driver_laps("Kobayashi", car="7")
|
|
50
|
+
print(f"Conway pace: {conway_laps['lap_time_s'].median():.3f}s")
|
|
51
|
+
print(f"Kobayashi pace: {kobayashi_laps['lap_time_s'].median():.3f}s")
|
|
52
|
+
|
|
53
|
+
# Stints and pace
|
|
54
|
+
stints = session.stints(car_class="HYPERCAR")
|
|
55
|
+
pace = session.pace(car_class="HYPERCAR")
|
|
56
|
+
pit_window = session.pit_window(car="7")
|
|
57
|
+
|
|
58
|
+
# Plots (requires matplotlib)
|
|
59
|
+
session.plot_lap_evolution(car="7")
|
|
60
|
+
session.plot_stint_chart(car_class="HYPERCAR")
|
|
61
|
+
session.plot_gap_to_leader(car_class="HYPERCAR")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Coverage
|
|
67
|
+
|
|
68
|
+
| Series | Seasons |
|
|
69
|
+
|--------|---------|
|
|
70
|
+
| FIA WEC | 2012–2026 |
|
|
71
|
+
| ELMS | 2012–2026 |
|
|
72
|
+
| ALMS (Asian) | 2022–2026 |
|
|
73
|
+
| Le Mans Cup | 2017–2026 |
|
|
74
|
+
| IMSA | 2014–2026 |
|
|
75
|
+
|
|
76
|
+
**1.96M+ laps** across all series.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## API key
|
|
81
|
+
|
|
82
|
+
Public endpoints (results, driver profiles, team profiles, driver search) require no key.
|
|
83
|
+
Lap-by-lap data and analytics endpoints require a free API key.
|
|
84
|
+
|
|
85
|
+
→ **[Request a key at openwec.com/api-keys](https://openwec.com/api-keys)**
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Session methods
|
|
90
|
+
|
|
91
|
+
| Method | Description | Key required |
|
|
92
|
+
|--------|-------------|-------------|
|
|
93
|
+
| `.results()` | Race classification as DataFrame | No |
|
|
94
|
+
| `.laps(car=None)` | Lap-by-lap data | Yes |
|
|
95
|
+
| `.driver_laps(name, car=None)` | Laps filtered by driver name ⚑ | Yes |
|
|
96
|
+
| `.stints(car_class=None)` | Stint breakdown per car | Yes |
|
|
97
|
+
| `.pace(car_class=None)` | Average green-flag pace | Yes |
|
|
98
|
+
| `.gaps(car_class=None)` | Gap to leader evolution | Yes |
|
|
99
|
+
| `.pit_window(car=None)` | Optimal pit window estimate | Yes |
|
|
100
|
+
| `.plot_lap_evolution(car)` | Lap time chart | Yes |
|
|
101
|
+
| `.plot_stint_chart()` | Strategy/stint chart | Yes |
|
|
102
|
+
| `.plot_gap_to_leader()` | Gap to leader chart | Yes |
|
|
103
|
+
|
|
104
|
+
⚑ **Unique to endurance racing** — multiple drivers share a car. `driver_laps()` has no equivalent in FastF1.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Example notebooks
|
|
109
|
+
|
|
110
|
+
| Notebook | Description |
|
|
111
|
+
|----------|-------------|
|
|
112
|
+
| [le_mans_2026.ipynb](examples/le_mans_2026.ipynb) | Full race analysis — results, pace, stints, plots |
|
|
113
|
+
| [driver_career.ipynb](examples/driver_career.ipynb) | Cross-series career analysis for a driver |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT — data sourced from Al Kamel Systems public timing exports.
|
|
120
|
+
Not affiliated with ACO, FIA, or any racing organization.
|
|
@@ -246,7 +246,60 @@ class Session:
|
|
|
246
246
|
self._laps_cache[cache_key] = df
|
|
247
247
|
return df
|
|
248
248
|
|
|
249
|
-
|
|
249
|
+
def driver_laps(self, driver_name: str, car: str | None = None) -> pd.DataFrame:
|
|
250
|
+
"""
|
|
251
|
+
Return lap-by-lap data for a specific driver within the session.
|
|
252
|
+
|
|
253
|
+
Filters laps by driver name using a case-insensitive partial match.
|
|
254
|
+
In endurance racing, multiple drivers share a car — this method lets
|
|
255
|
+
you isolate one driver's stints from the shared-drive data.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
driver_name: Driver name or partial name to filter by, e.g.
|
|
259
|
+
``"Conway"``, ``"Mike Conway"``, ``"CONWAY"``.
|
|
260
|
+
Matching is case-insensitive and substring-based.
|
|
261
|
+
car: Optional car number to filter. If ``None``, searches across
|
|
262
|
+
all cars in the session (slower for long races).
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
DataFrame with the same columns as :meth:`laps`, filtered to
|
|
266
|
+
laps where ``driver_name`` appears in the ``driver_name`` column.
|
|
267
|
+
|
|
268
|
+
Raises:
|
|
269
|
+
OpenWECAuthError: If no API key is configured.
|
|
270
|
+
ValueError: If no laps are found matching the driver name.
|
|
271
|
+
|
|
272
|
+
Note:
|
|
273
|
+
This method is unique to endurance racing — it has no equivalent
|
|
274
|
+
in FastF1 because Formula 1 cars have a single driver per race.
|
|
275
|
+
|
|
276
|
+
Example:
|
|
277
|
+
>>> session = openwec.Session("WEC", 2026, "Le Mans", "Race")
|
|
278
|
+
>>> conway_laps = session.driver_laps("Conway", car="7")
|
|
279
|
+
>>> print(f"Conway drove {len(conway_laps)} laps")
|
|
280
|
+
>>>
|
|
281
|
+
>>> # Compare two drivers in the same car
|
|
282
|
+
>>> kobayashi_laps = session.driver_laps("Kobayashi", car="7")
|
|
283
|
+
>>> print(f"Pace: Conway {conway_laps['lap_time_s'].median():.3f}s "
|
|
284
|
+
... f"vs Kobayashi {kobayashi_laps['lap_time_s'].median():.3f}s")
|
|
285
|
+
"""
|
|
286
|
+
all_laps = self.laps(car=car)
|
|
287
|
+
|
|
288
|
+
if all_laps.empty or "driver_name" not in all_laps.columns:
|
|
289
|
+
raise ValueError("No lap data available for this session.")
|
|
290
|
+
|
|
291
|
+
mask = all_laps["driver_name"].str.contains(
|
|
292
|
+
driver_name, case=False, na=False
|
|
293
|
+
)
|
|
294
|
+
result = all_laps[mask].copy()
|
|
295
|
+
|
|
296
|
+
if result.empty:
|
|
297
|
+
raise ValueError(
|
|
298
|
+
f"No laps found for driver matching '{driver_name}'. "
|
|
299
|
+
f"Available drivers: {', '.join(all_laps['driver_name'].dropna().unique()[:10])}"
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
return result
|
|
250
303
|
|
|
251
304
|
def stints(self, car: str | None = None,
|
|
252
305
|
car_class: str | None = None) -> pd.DataFrame:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openwec
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Python SDK for endurance racing data — WEC, ELMS, ALMS, Le Mans Cup, IMSA
|
|
5
5
|
Author: Paloma C.
|
|
6
6
|
License-Expression: MIT
|
|
@@ -61,13 +61,11 @@ pip install openwec[plotting]
|
|
|
61
61
|
```python
|
|
62
62
|
import openwec
|
|
63
63
|
|
|
64
|
-
#
|
|
64
|
+
# Public endpoints work without a key.
|
|
65
65
|
# Request a free key at https://openwec.com/api-keys
|
|
66
|
-
openwec.configure(
|
|
67
|
-
api_key="your-key-here" # required for laps and analytics
|
|
68
|
-
)
|
|
66
|
+
openwec.configure(api_key="your-key-here") # required for laps and analytics
|
|
69
67
|
|
|
70
|
-
# Load any session
|
|
68
|
+
# Load any session — WEC, ELMS, ALMS, Le Mans Cup, or IMSA
|
|
71
69
|
session = openwec.Session("WEC", 2026, "Le Mans", "Race")
|
|
72
70
|
print(session)
|
|
73
71
|
# Session(WEC 2026 LE MANS — Race, id=6556)
|
|
@@ -80,11 +78,16 @@ print(results[["position", "car_number", "car_class", "team", "drivers"]].head(1
|
|
|
80
78
|
laps = session.laps(car="7")
|
|
81
79
|
print(laps[["lap_number", "lap_time_s", "s1_s", "s2_s", "s3_s"]].head())
|
|
82
80
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
# Endurance-specific: filter laps by driver within a shared-drive car
|
|
82
|
+
# (unique to endurance racing — not possible in FastF1)
|
|
83
|
+
conway_laps = session.driver_laps("Conway", car="7")
|
|
84
|
+
kobayashi_laps = session.driver_laps("Kobayashi", car="7")
|
|
85
|
+
print(f"Conway pace: {conway_laps['lap_time_s'].median():.3f}s")
|
|
86
|
+
print(f"Kobayashi pace: {kobayashi_laps['lap_time_s'].median():.3f}s")
|
|
86
87
|
|
|
87
|
-
#
|
|
88
|
+
# Stints and pace
|
|
89
|
+
stints = session.stints(car_class="HYPERCAR")
|
|
90
|
+
pace = session.pace(car_class="HYPERCAR")
|
|
88
91
|
pit_window = session.pit_window(car="7")
|
|
89
92
|
|
|
90
93
|
# Plots (requires matplotlib)
|
|
@@ -105,13 +108,13 @@ session.plot_gap_to_leader(car_class="HYPERCAR")
|
|
|
105
108
|
| Le Mans Cup | 2017–2026 |
|
|
106
109
|
| IMSA | 2014–2026 |
|
|
107
110
|
|
|
108
|
-
**1.
|
|
111
|
+
**1.96M+ laps** across all series.
|
|
109
112
|
|
|
110
113
|
---
|
|
111
114
|
|
|
112
115
|
## API key
|
|
113
116
|
|
|
114
|
-
Public endpoints (results, driver profiles, team profiles) require no key.
|
|
117
|
+
Public endpoints (results, driver profiles, team profiles, driver search) require no key.
|
|
115
118
|
Lap-by-lap data and analytics endpoints require a free API key.
|
|
116
119
|
|
|
117
120
|
→ **[Request a key at openwec.com/api-keys](https://openwec.com/api-keys)**
|
|
@@ -120,17 +123,29 @@ Lap-by-lap data and analytics endpoints require a free API key.
|
|
|
120
123
|
|
|
121
124
|
## Session methods
|
|
122
125
|
|
|
123
|
-
| Method |
|
|
124
|
-
|
|
125
|
-
| `.results()` | DataFrame | No |
|
|
126
|
-
| `.laps(car=None)` |
|
|
127
|
-
| `.
|
|
128
|
-
| `.
|
|
129
|
-
| `.
|
|
130
|
-
| `.
|
|
131
|
-
| `.
|
|
132
|
-
| `.
|
|
133
|
-
| `.
|
|
126
|
+
| Method | Description | Key required |
|
|
127
|
+
|--------|-------------|-------------|
|
|
128
|
+
| `.results()` | Race classification as DataFrame | No |
|
|
129
|
+
| `.laps(car=None)` | Lap-by-lap data | Yes |
|
|
130
|
+
| `.driver_laps(name, car=None)` | Laps filtered by driver name ⚑ | Yes |
|
|
131
|
+
| `.stints(car_class=None)` | Stint breakdown per car | Yes |
|
|
132
|
+
| `.pace(car_class=None)` | Average green-flag pace | Yes |
|
|
133
|
+
| `.gaps(car_class=None)` | Gap to leader evolution | Yes |
|
|
134
|
+
| `.pit_window(car=None)` | Optimal pit window estimate | Yes |
|
|
135
|
+
| `.plot_lap_evolution(car)` | Lap time chart | Yes |
|
|
136
|
+
| `.plot_stint_chart()` | Strategy/stint chart | Yes |
|
|
137
|
+
| `.plot_gap_to_leader()` | Gap to leader chart | Yes |
|
|
138
|
+
|
|
139
|
+
⚑ **Unique to endurance racing** — multiple drivers share a car. `driver_laps()` has no equivalent in FastF1.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Example notebooks
|
|
144
|
+
|
|
145
|
+
| Notebook | Description |
|
|
146
|
+
|----------|-------------|
|
|
147
|
+
| [le_mans_2026.ipynb](examples/le_mans_2026.ipynb) | Full race analysis — results, pace, stints, plots |
|
|
148
|
+
| [driver_career.ipynb](examples/driver_career.ipynb) | Cross-series career analysis for a driver |
|
|
134
149
|
|
|
135
150
|
---
|
|
136
151
|
|
openwec-0.2.0/README.md
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
# openwec
|
|
2
|
-
|
|
3
|
-
**Python SDK for endurance racing data — WEC, ELMS, ALMS, Le Mans Cup, IMSA.**
|
|
4
|
-
|
|
5
|
-
Inspired by [FastF1](https://github.com/theOehrly/Fast-F1), OpenWEC gives you lap-by-lap timing data, stint analytics, and race results from endurance racing as pandas DataFrames — in one line.
|
|
6
|
-
|
|
7
|
-
→ **[openwec.com](https://openwec.com)** — Live dashboard
|
|
8
|
-
→ **[api.openwec.com/docs](https://api.openwec.com/docs)** — API reference
|
|
9
|
-
→ **[github.com/palomacdev/openwec](https://github.com/palomacdev/openwec)** — Source
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
pip install openwec
|
|
17
|
-
|
|
18
|
-
# With plotting support
|
|
19
|
-
pip install openwec[plotting]
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Quick start
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
import openwec
|
|
28
|
-
|
|
29
|
-
# Configure — public endpoints work without a key
|
|
30
|
-
# Request a free key at https://openwec.com/api-keys
|
|
31
|
-
openwec.configure(
|
|
32
|
-
api_key="your-key-here" # required for laps and analytics
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
# Load any session
|
|
36
|
-
session = openwec.Session("WEC", 2026, "Le Mans", "Race")
|
|
37
|
-
print(session)
|
|
38
|
-
# Session(WEC 2026 LE MANS — Race, id=6556)
|
|
39
|
-
|
|
40
|
-
# Results as a DataFrame (no key needed)
|
|
41
|
-
results = session.results()
|
|
42
|
-
print(results[["position", "car_number", "car_class", "team", "drivers"]].head(10))
|
|
43
|
-
|
|
44
|
-
# Lap-by-lap data (key required)
|
|
45
|
-
laps = session.laps(car="7")
|
|
46
|
-
print(laps[["lap_number", "lap_time_s", "s1_s", "s2_s", "s3_s"]].head())
|
|
47
|
-
|
|
48
|
-
# Stints and pace (key required)
|
|
49
|
-
stints = session.stints(car_class="HYPERCAR")
|
|
50
|
-
pace = session.pace(car_class="HYPERCAR")
|
|
51
|
-
|
|
52
|
-
# Pit window estimate
|
|
53
|
-
pit_window = session.pit_window(car="7")
|
|
54
|
-
|
|
55
|
-
# Plots (requires matplotlib)
|
|
56
|
-
session.plot_lap_evolution(car="7")
|
|
57
|
-
session.plot_stint_chart(car_class="HYPERCAR")
|
|
58
|
-
session.plot_gap_to_leader(car_class="HYPERCAR")
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Coverage
|
|
64
|
-
|
|
65
|
-
| Series | Seasons |
|
|
66
|
-
|--------|---------|
|
|
67
|
-
| FIA WEC | 2012–2026 |
|
|
68
|
-
| ELMS | 2012–2026 |
|
|
69
|
-
| ALMS (Asian) | 2022–2026 |
|
|
70
|
-
| Le Mans Cup | 2017–2026 |
|
|
71
|
-
| IMSA | 2014–2026 |
|
|
72
|
-
|
|
73
|
-
**1.77M+ laps** across all series.
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
|
|
77
|
-
## API key
|
|
78
|
-
|
|
79
|
-
Public endpoints (results, driver profiles, team profiles) require no key.
|
|
80
|
-
Lap-by-lap data and analytics endpoints require a free API key.
|
|
81
|
-
|
|
82
|
-
→ **[Request a key at openwec.com/api-keys](https://openwec.com/api-keys)**
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
## Session methods
|
|
87
|
-
|
|
88
|
-
| Method | Returns | Key required |
|
|
89
|
-
|--------|---------|-------------|
|
|
90
|
-
| `.results()` | DataFrame | No |
|
|
91
|
-
| `.laps(car=None)` | DataFrame | Yes |
|
|
92
|
-
| `.stints(car_class=None)` | DataFrame | Yes |
|
|
93
|
-
| `.pace(car_class=None)` | DataFrame | Yes |
|
|
94
|
-
| `.gaps(car_class=None)` | DataFrame | Yes |
|
|
95
|
-
| `.pit_window(car=None)` | DataFrame | Yes |
|
|
96
|
-
| `.plot_lap_evolution(car)` | Figure | Yes |
|
|
97
|
-
| `.plot_stint_chart()` | Figure | Yes |
|
|
98
|
-
| `.plot_gap_to_leader()` | Figure | Yes |
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## License
|
|
103
|
-
|
|
104
|
-
MIT — data sourced from Al Kamel Systems public timing exports.
|
|
105
|
-
Not affiliated with ACO, FIA, or any racing organization.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|