API reference

Public symbols are re-exported from the basef1 package. Submodule pages below list implementation modules.

For client-side observability types, see basef1.client.UsageSnapshot and basef1.client.RequestLogEntry under basef1.client.

basef1.client

HTTP client for the Jolpica F1 API.

class basef1.client.BaseF1Client(*, base_url: str = DEFAULT_BASE_URL, timeout: float | Timeout | None = 30.0, client: Client | None = None, cache: TTLCache | SQLiteCache | Literal[False] | None = None, cache_backend: Literal['memory', 'sqlite'] = 'memory', cache_path: str | Path | None = None, cache_ttl: float | None = None, cache_max_entries: int = 256, request_log_maxlen: int | None = 512)

Bases: object

Sync client for https://api.jolpi.ca/ergast/f1 (JSON).

By default responses are cached in memory (TTLCache) to reduce duplicate GET traffic. Pass cache_backend="sqlite" for a persistent local SQLite cache, cache=False to disable caching, or pass cache= / cache_ttl= to customize.

Pass a custom httpx.Client for tests or advanced configuration. If client is omitted, an internal client is created and closed when this instance is used as a context manager.

request_log_maxlen bounds the in-memory request log (None = unlimited).

stats(*, file: TextIO | None = None) None

Print a human-readable usage summary (logical vs HTTP vs cache).

usage_snapshot() UsageSnapshot

Return current usage counters and the full in-memory request log.

class basef1.client.RequestLogEntry(method: str, url: str, params: tuple[tuple[str, Any], ...], source: Literal['cache', 'network'])

Bases: NamedTuple

One logical client request (cache or network).

method: str

Alias for field number 0

params: tuple[tuple[str, Any], ...]

Alias for field number 2

source: Literal['cache', 'network']

Alias for field number 3

url: str

Alias for field number 1

class basef1.client.UsageSnapshot(logical_requests: int, http_requests: int, cache_hits: int, caching_enabled: bool, request_log: tuple[RequestLogEntry, ...])

Bases: NamedTuple

Point-in-time usage counters and request log (newest last).

cache_hits: int

Alias for field number 2

caching_enabled: bool

Alias for field number 3

http_requests: int

Alias for field number 1

logical_requests: int

Alias for field number 0

request_log: tuple[RequestLogEntry, ...]

Alias for field number 4

basef1.query

Chainable path builder for Jolpica / Ergast-style URLs.

class basef1.query.F1Query(client: BaseF1Client, segments: list[str])

Bases: object

Build filter path segments, then call a terminal resource method.

Invalid segment ordering is possible if methods are chained incorrectly; that matches raw REST usage. round() requires season() to have been called immediately before (last segment is a season year or current).

get_statuses(*, limit: int | None = None, offset: int | None = None) ApiResponse

Finishing status catalogue (GET .../status/).

with_status(status_id: int | str) F1Query

Filter by finishing status id (path /status/{statusId}/).

basef1.models

Lightweight response wrappers.

class basef1.models.ApiResponse(raw: dict[str, Any])

Bases: object

Parsed JSON body with helpers for MRData and pagination.

get_data() dict[str, Any]

Return the primary data table under MRData (e.g. RaceTable), without hard-coding the key.

Tries keys in MRDATA_TABLE_PRIORITY first, then any other *Table dict value (excluding metadata keys). Returns {} if none found.

parse() ParsedApiResponse

Parse MRData into ParsedApiResponse.

class basef1.models.Pagination(limit: str | None, offset: str | None, total: str | None)

Bases: object

Pagination fields from MRData (API returns string values).

basef1.cache

HTTP response caches for idempotent GET responses.

class basef1.cache.ResponseCache(*args, **kwargs)

Bases: Protocol

Minimal cache interface used by basef1.client.BaseF1Client.

class basef1.cache.SQLiteCache(path: str | Path, ttl_seconds: float, *, clock: Callable[[], float] | None = None)

Bases: object

Thread-safe on-disk TTL cache backed by SQLite.

Entries expire after ttl_seconds. The database file is created if missing.

class basef1.cache.TTLCache(max_entries: int, ttl_seconds: float, *, clock: Callable[[], float] | None = None)

Bases: object

Thread-safe in-memory LRU-ish cache: entries expire after ttl_seconds; when full, the oldest inserted entry is evicted.

basef1.cache.cache_key_for_request(method: str, url: str, params: dict[str, Any] | None) str

Stable cache key for HTTP method, url, and query params.

basef1.cache.create_response_cache(*, backend: Literal['memory', 'sqlite'] = 'memory', path: str | Path | None = None, ttl_seconds: float, max_entries: int = 256) TTLCache | SQLiteCache

Build a TTLCache or SQLiteCache for the given backend.

basef1.cache.default_sqlite_cache_path() Path

Default on-disk cache file: ~/.cache/basef1/http_cache.sqlite.

basef1.exceptions

Client errors.

exception basef1.exceptions.JolpicaHTTPError(message: str, *, status_code: int, body: str | None = None)

Bases: Exception

Raised when the API returns a non-success HTTP status.

basef1.constants

MRData keys shared across Jolpica / Ergast-style JSON responses.

basef1.domain

Typed domain models for Jolpica / Ergast JSON datas.

class basef1.domain.AverageSpeed(units: 'str | None' = None, speed: 'str | None' = None)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) AverageSpeed
speed: str | None = None
units: str | None = None
class basef1.domain.Circuit(circuit_id: 'str | None' = None, url: 'str | None' = None, circuit_name: 'str | None' = None, location: 'Location | None' = None)

Bases: JolpicaModel

circuit_id: str | None = None
circuit_name: str | None = None
classmethod from_dict(data: dict[str, Any]) Circuit
location: Location | None = None
url: str | None = None
class basef1.domain.CircuitTable(circuits: 'list[Circuit]' = <factory>)

Bases: JolpicaModel

circuits: list[Circuit]
classmethod from_dict(data: dict[str, Any]) CircuitTable
class basef1.domain.Constructor(constructor_id: 'str | None' = None, url: 'str | None' = None, name: 'str | None' = None, nationality: 'str | None' = None)

Bases: JolpicaModel

constructor_id: str | None = None
classmethod from_dict(data: dict[str, Any]) Constructor
name: str | None = None
nationality: str | None = None
url: str | None = None
class basef1.domain.ConstructorStandingRow(position: 'str | None' = None, position_text: 'str | None' = None, points: 'str | None' = None, wins: 'str | None' = None, constructor: 'Constructor | None' = None)

Bases: JolpicaModel

constructor: Constructor | None = None
classmethod from_dict(data: dict[str, Any]) ConstructorStandingRow
points: str | None = None
position: str | None = None
position_text: str | None = None
wins: str | None = None
class basef1.domain.ConstructorTable(constructors: 'list[Constructor]' = <factory>)

Bases: JolpicaModel

constructors: list[Constructor]
classmethod from_dict(data: dict[str, Any]) ConstructorTable
class basef1.domain.Driver(driver_id: 'str | None' = None, permanent_number: 'str | None' = None, code: 'str | None' = None, url: 'str | None' = None, given_name: 'str | None' = None, family_name: 'str | None' = None, date_of_birth: 'str | None' = None, nationality: 'str | None' = None)

Bases: JolpicaModel

code: str | None = None
date_of_birth: str | None = None
driver_id: str | None = None
family_name: str | None = None
classmethod from_dict(data: dict[str, Any]) Driver
given_name: str | None = None
nationality: str | None = None
permanent_number: str | None = None
url: str | None = None
class basef1.domain.DriverStandingRow(position: 'str | None' = None, position_text: 'str | None' = None, points: 'str | None' = None, wins: 'str | None' = None, driver: 'Driver | None' = None, constructors: 'list[Constructor]' = <factory>)

Bases: JolpicaModel

constructors: list[Constructor]
driver: Driver | None = None
classmethod from_dict(data: dict[str, Any]) DriverStandingRow
points: str | None = None
position: str | None = None
position_text: str | None = None
wins: str | None = None
class basef1.domain.DriverTable(drivers: 'list[Driver]' = <factory>)

Bases: JolpicaModel

drivers: list[Driver]
classmethod from_dict(data: dict[str, Any]) DriverTable
class basef1.domain.FastestLap(rank: 'str | None' = None, lap: 'str | None' = None, time: 'TimeElement | None' = None, average_speed: 'AverageSpeed | None' = None)

Bases: JolpicaModel

average_speed: AverageSpeed | None = None
classmethod from_dict(data: dict[str, Any]) FastestLap
lap: str | None = None
rank: str | None = None
time: TimeElement | None = None
class basef1.domain.JolpicaModel

Bases: object

Mixin-style base: subclasses must be @dataclass instances.

to_dict() dict[str, Any]

Serialize using field metadata key for JSON names (defaults to field name).

class basef1.domain.LapRow(number: 'str | None' = None, timings: 'list[LapTimingEntry]' = <factory>)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) LapRow
number: str | None = None
timings: list[LapTimingEntry]
class basef1.domain.LapTimingEntry(driver_id: 'str | None' = None, position: 'str | None' = None, time: 'str | None' = None)

Bases: JolpicaModel

driver_id: str | None = None
classmethod from_dict(data: dict[str, Any]) LapTimingEntry
position: str | None = None
time: str | None = None
class basef1.domain.Location(lat: 'str | None' = None, longitude: 'str | None' = None, locality: 'str | None' = None, country: 'str | None' = None)

Bases: JolpicaModel

country: str | None = None
classmethod from_dict(data: dict[str, Any]) Location
lat: str | None = None
locality: str | None = None
longitude: str | None = None
class basef1.domain.ParsedApiResponse(kind: str | None, pagination: Pagination, data: RaceTable | SeasonTable | DriverTable | ConstructorTable | CircuitTable | StatusTable | StandingsTable | RawTable)

Bases: object

Typed view of an ApiResponse.

data: RaceTable | SeasonTable | DriverTable | ConstructorTable | CircuitTable | StatusTable | StandingsTable | RawTable
kind: str | None
pagination: Pagination
class basef1.domain.PitStopRow(driver_id: 'str | None' = None, lap: 'str | None' = None, stop: 'str | None' = None, time: 'str | None' = None, duration: 'str | None' = None)

Bases: JolpicaModel

driver_id: str | None = None
duration: str | None = None
classmethod from_dict(data: dict[str, Any]) PitStopRow
lap: str | None = None
stop: str | None = None
time: str | None = None
class basef1.domain.QualifyingResult(number: 'str | None' = None, position: 'str | None' = None, driver: 'Driver | None' = None, constructor: 'Constructor | None' = None, q1: 'str | None' = None, q2: 'str | None' = None, q3: 'str | None' = None)

Bases: JolpicaModel

constructor: Constructor | None = None
driver: Driver | None = None
classmethod from_dict(data: dict[str, Any]) QualifyingResult
number: str | None = None
position: str | None = None
q1: str | None = None
q2: str | None = None
q3: str | None = None
class basef1.domain.Race(season: 'str | None' = None, round: 'str | None' = None, url: 'str | None' = None, race_name: 'str | None' = None, circuit: 'Circuit | None' = None, date: 'str | None' = None, time: 'str | None' = None, first_practice: 'Session | None' = None, second_practice: 'Session | None' = None, third_practice: 'Session | None' = None, qualifying: 'Session | None' = None, sprint: 'Session | None' = None, sprint_qualifying: 'Session | None' = None, sprint_shootout: 'Session | None' = None, results: 'list[RaceResult]' = <factory>, sprint_results: 'list[RaceResult]' = <factory>, qualifying_results: 'list[RaceResult]' = <factory>, laps: 'list[LapRow]' = <factory>, pit_stops: 'list[PitStopRow]' = <factory>)

Bases: JolpicaModel

circuit: Circuit | None = None
date: str | None = None
first_practice: Session | None = None
classmethod from_dict(data: dict[str, Any]) Race
laps: list[LapRow]
pit_stops: list[PitStopRow]
qualifying: Session | None = None
qualifying_results: list[RaceResult]
race_name: str | None = None
results: list[RaceResult]
round: str | None = None
season: str | None = None
second_practice: Session | None = None
sprint: Session | None = None
sprint_qualifying: Session | None = None
sprint_results: list[RaceResult]
sprint_shootout: Session | None = None
third_practice: Session | None = None
time: str | None = None
url: str | None = None
class basef1.domain.RaceResult(number: 'str | None' = None, position: 'str | None' = None, position_text: 'str | None' = None, points: 'str | None' = None, grid: 'str | None' = None, laps: 'str | None' = None, status: 'str | None' = None, driver: 'Driver | None' = None, constructor: 'Constructor | None' = None, time: 'TimeElement | None' = None, fastest_lap: 'FastestLap | None' = None)

Bases: JolpicaModel

constructor: Constructor | None = None
driver: Driver | None = None
fastest_lap: FastestLap | None = None
classmethod from_dict(data: dict[str, Any]) RaceResult
grid: str | None = None
laps: str | None = None
number: str | None = None
points: str | None = None
position: str | None = None
position_text: str | None = None
status: str | None = None
time: TimeElement | None = None
class basef1.domain.RaceTable(season: 'str | None' = None, round: 'str | None' = None, circuit_id: 'str | None' = None, driver_id: 'str | None' = None, constructor_id: 'str | None' = None, races: 'list[Race]' = <factory>)

Bases: JolpicaModel

circuit_id: str | None = None
constructor_id: str | None = None
driver_id: str | None = None
classmethod from_dict(data: dict[str, Any]) RaceTable
races: list[Race]
round: str | None = None
season: str | None = None
class basef1.domain.RawTable(kind: str | None, data: dict[str, Any])

Bases: object

Fallback when MRData contains an unknown *Table key or no table.

data: dict[str, Any]
kind: str | None
to_dict() dict[str, Any]
class basef1.domain.Season(season: 'str | None' = None, url: 'str | None' = None)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) Season
season: str | None = None
url: str | None = None
class basef1.domain.SeasonTable(seasons: 'list[Season]' = <factory>)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) SeasonTable
seasons: list[Season]
class basef1.domain.Session(date: str | None = None, time: str | None = None)

Bases: JolpicaModel

Practice / qualifying / sprint session slot with date and time.

date: str | None = None
classmethod from_dict(data: dict[str, Any]) Session
time: str | None = None
class basef1.domain.StandingsList(season: 'str | None' = None, round: 'str | None' = None, driver_standings: 'list[DriverStandingRow]' = <factory>, constructor_standings: 'list[ConstructorStandingRow]' = <factory>)

Bases: JolpicaModel

constructor_standings: list[ConstructorStandingRow]
driver_standings: list[DriverStandingRow]
classmethod from_dict(data: dict[str, Any]) StandingsList
round: str | None = None
season: str | None = None
class basef1.domain.StandingsTable(season: 'str | None' = None, round: 'str | None' = None, driver_id: 'str | None' = None, constructor_id: 'str | None' = None, standings_lists: 'list[StandingsList]' = <factory>)

Bases: JolpicaModel

constructor_id: str | None = None
driver_id: str | None = None
classmethod from_dict(data: dict[str, Any]) StandingsTable
round: str | None = None
season: str | None = None
standings_lists: list[StandingsList]
class basef1.domain.StatusRow(status_id: 'str | None' = None, status: 'str | None' = None)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) StatusRow
status: str | None = None
status_id: str | None = None
class basef1.domain.StatusTable(statuses: 'list[StatusRow]' = <factory>)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) StatusTable
statuses: list[StatusRow]
class basef1.domain.TimeElement(millis: 'str | None' = None, time: 'str | None' = None)

Bases: JolpicaModel

classmethod from_dict(data: dict[str, Any]) TimeElement
millis: str | None = None
time: str | None = None
basef1.domain.ensure_list(value: Any) list[Any]

Normalize Ergast single-object-or-list JSON to a list.

basef1.domain.parse_api_response(resp: ApiResponse) ParsedApiResponse

Parse resp into a ParsedApiResponse based on the MRData table key.