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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openwec
3
- Version: 0.2.0
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
- # Configure — public endpoints work without a key
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
- # Stints and pace (key required)
84
- stints = session.stints(car_class="HYPERCAR")
85
- pace = session.pace(car_class="HYPERCAR")
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
- # Pit window estimate
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.77M+ laps** across all series.
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 | Returns | Key required |
124
- |--------|---------|-------------|
125
- | `.results()` | DataFrame | No |
126
- | `.laps(car=None)` | DataFrame | Yes |
127
- | `.stints(car_class=None)` | DataFrame | Yes |
128
- | `.pace(car_class=None)` | DataFrame | Yes |
129
- | `.gaps(car_class=None)` | DataFrame | Yes |
130
- | `.pit_window(car=None)` | DataFrame | Yes |
131
- | `.plot_lap_evolution(car)` | Figure | Yes |
132
- | `.plot_stint_chart()` | Figure | Yes |
133
- | `.plot_gap_to_leader()` | Figure | Yes |
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
 
@@ -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.
@@ -34,7 +34,7 @@ Usage:
34
34
  from .client import configure, OpenWECError, OpenWECNotFoundError, OpenWECAuthError
35
35
  from .session import Session
36
36
 
37
- __version__ = "0.2.0"
37
+ __version__ = "0.2.2"
38
38
 
39
39
  __all__ = [
40
40
  "Session",
@@ -246,7 +246,60 @@ class Session:
246
246
  self._laps_cache[cache_key] = df
247
247
  return df
248
248
 
249
- # ── Analytics ─────────────────────────────────────────────
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.0
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
- # Configure — public endpoints work without a key
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
- # Stints and pace (key required)
84
- stints = session.stints(car_class="HYPERCAR")
85
- pace = session.pace(car_class="HYPERCAR")
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
- # Pit window estimate
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.77M+ laps** across all series.
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 | Returns | Key required |
124
- |--------|---------|-------------|
125
- | `.results()` | DataFrame | No |
126
- | `.laps(car=None)` | DataFrame | Yes |
127
- | `.stints(car_class=None)` | DataFrame | Yes |
128
- | `.pace(car_class=None)` | DataFrame | Yes |
129
- | `.gaps(car_class=None)` | DataFrame | Yes |
130
- | `.pit_window(car=None)` | DataFrame | Yes |
131
- | `.plot_lap_evolution(car)` | Figure | Yes |
132
- | `.plot_stint_chart()` | Figure | Yes |
133
- | `.plot_gap_to_leader()` | Figure | Yes |
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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openwec"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Python SDK for endurance racing data — WEC, ELMS, ALMS, Le Mans Cup, IMSA"
9
9
  readme = "README.md"
10
10
  license = "MIT"
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