Skip to main content
ingestion/src/ingest.py is the single entry point for pulling data into Bronze. It takes a season range (or a single season shorthand), an optional round and session filter, and a handful of behaviour flags.

Season selection

A season range is the one required argument, and it comes in two mutually exclusive forms.
int
First season to ingest. Must be paired with --end-season.
int
Last season to ingest, inclusive. Required alongside --start-season; ignored if you used -s/--season instead.
int
Shorthand for a single season equivalent to passing the same year to both --start-season and --end-season.
--start-season/-s are mutually exclusive the parser rejects a command that passes both. If --start-season is after --end-season, or --round/--rounds is combined with a season range spanning more than one year, ingest.py exits immediately with an error before touching the network.

Scope and behaviour flags

int
default:"None"
Ingest only this round number. Requires a single season combine with -s/--season, not a multi-year range.
string
default:"None"
Ingest only these rounds, as a range or list: 1-14, 3,5,7, 1-3,9. Same single-season rule as --round, and the two are mutually exclusive.
float
default:"6"
A session counts as finished this many hours after its scheduled start on the FastF1 schedule. Sessions that have not reached that point are skipped without loading (logged as [NOT RUN], no manifest row), so a whole-season run never walks into rounds that have not happened. With --session both the round is the unit: qualifying waits until the race is also finished, so bronze never holds a qualifying-only round.
boolean
default:"false"
Attempt every round on the schedule regardless of its date (the old behaviour).
boolean
default:"false"
Write a session even if it is still incomplete after its retry. By default a thin load (FastF1 returned it, but key columns came back missing: results points/grid or Q1 times, tyre columns, weather or race control) is retried once with the FastF1 cache bypassed and, if still thin, not written, so the next run pulls it again. With this flag it is written and the manifest records what was thin.
path
default:"data/bronze"
Bronze root to write under (same layout). Also settable as INGESTION_BRONZE_DIR. Point probes and experiments at a scratch directory so they never touch data/bronze.
path
default:"data/cache"
FastF1 cache directory for this run; overrides FASTF1_CACHE_DIR.
'R' | 'Q' | 'both'
default:"both"
Which session types to pull. R for race only, Q for qualifying only, both for everything.
boolean
default:"false"
Skip the telemetry writer entirely. Useful for fast dry-runs or qualifying-only pulls where telemetry isn’t needed.
boolean
default:"false"
Also ingest full-channel car data (Speed, Throttle, Brake, nGear, RPM, DRS) and car-position data, beyond the default telemetry write. Substantially larger and slower see Architecture for what each telemetry writer captures.
boolean
default:"false"
Overwrite existing Parquet files instead of skipping sessions already on disk. Without it, ingest.py is idempotent re-running the same command after a crash resumes from the gap rather than re-pulling everything.
boolean
default:"false"
Fetch the season schedule (from the FastF1 cache when it has it) and list, per round and session, whether it would be pulled, skipped as already on disk, or is not run yet, plus any slug/venue warnings and an estimated bronze size. Loads no session and writes nothing to bronze. make ingest-plan SEASON=YYYY wraps it.
string
default:"INFO"
Logging verbosity: DEBUG, INFO, WARNING, or ERROR.

Canonical invocations

--dry-run estimates size at ~0.05 GB of bronze per race weekend pulled (race + qualifying + race telemetry; 2025 on disk averages ~47 MB). It’s a quick sanity check before committing to a multi-hour backfill.

Exit code and end-of-run summary

ingest.py exits 1 when any session ended error (load or write failed after retries), thin (loaded incomplete, not written) or a season’s schedule could not be fetched, and 0 otherwise. Those sessions are listed under === NEEDS ATTENTION at the end of the log; re-running the same command retries them, since everything already on disk is skipped. Sessions that were written but deserve a look (telemetry merged on fewer than 95% of laps, no circuit info, an accepted thin load, a slug that now names a different venue) are listed under === NOTES and recorded in the run manifest (see Manifest report); they do not change the exit code. Known source gaps (ingestion/src/bronze_checks.py, e.g. 2018 Rd1/Rd2 telemetry) are logged as [KNOWN GAP] and never flagged. See the generated flag dump for the raw argparse help text, including the exact usage: line.