Skip to main content
The schedule_schema module validates the internal schedule data structure used by tif1. It ensures schedule payloads conform to the expected schema before being used by get_events() and get_sessions().
This module is used internally. Most users don’t need to interact with it directly.

Schema Validation

validate_schedule_payload

def validate_schedule_payload(payload: Any) -> dict[str, Any]
Validate that a schedule payload conforms to the expected internal schema. Parameters:
  • payload: Decoded schedule payload (dict with schema_version and years)
Returns:
  • The validated payload (same as input if valid)
Raises:
  • InvalidDataError: If the payload structure is invalid
Example:
from tif1.schedule_schema import validate_schedule_payload
from tif1.exceptions import InvalidDataError

payload = {
    "schema_version": 1,
    "years": {
        "2021": {
            "events": ["Bahrain Grand Prix", "Belgian Grand Prix"],
            "sessions": {
                "Bahrain Grand Prix": ["Practice 1", "Practice 2", "Practice 3", "Qualifying", "Race"],
                "Belgian Grand Prix": ["Practice 1", "Practice 2", "Practice 3", "Qualifying", "Race"]
            }
        }
    }
}

try:
    validated = validate_schedule_payload(payload)
    print("Schedule is valid")
except InvalidDataError as e:
    print(f"Invalid schedule: {e}")

Schedule Schema

The internal schedule data follows this structure:
{
  "schema_version": 1,
  "years": {
    "2021": {
      "events": [
        "Bahrain Grand Prix",
        "Belgian Grand Prix",
        "Abu Dhabi Grand Prix"
      ],
      "sessions": {
        "Bahrain Grand Prix": [
          "Practice 1",
          "Practice 2",
          "Practice 3",
          "Qualifying",
          "Race"
        ],
        "Belgian Grand Prix": [
          "Practice 1",
          "Practice 2",
          "Practice 3",
          "Qualifying",
          "Race"
        ]
      },
      "metadata": {
        "Belgian Grand Prix": {
          "RoundNumber": 12,
          "EventDate": "2021-08-29T17:00:00",
          "Location": "Spa-Francorchamps",
          "Country": "Belgium",
          "OfficialEventName": "FORMULA 1 ROLEX BELGIAN GRAND PRIX 2021",
          "EventFormat": "conventional",
          "GmtOffset": "+02:00",
          "F1ApiSupport": true,
          "Session1Date": "2021-08-27T11:30:00",
          "Session2Date": "2021-08-27T15:00:00",
          "Session3Date": "2021-08-28T12:00:00",
          "Session4Date": "2021-08-28T15:00:00",
          "Session5Date": "2021-08-29T15:00:00"
        }
      }
    }
  }
}

Schema Version

The schema_version field indicates the structure version. Currently, only version 1 is supported. Future versions may:
  • Add new metadata fields
  • Support additional event formats
  • Include circuit information

Validation Rules

The validator checks:
  1. Top-level structure
    • Payload must be a dictionary
    • Must contain schema_version field
    • Must contain years dictionary
  2. Schema version
    • Must be exactly 1
    • Other versions raise InvalidDataError
  3. Year structure
    • Each year key must be a string of digits (e.g., “2021”)
    • Each year value must be a dictionary
    • Must contain events list and sessions dictionary
  4. Events list
    • Must be a list of strings
    • Each event name must be a non-empty string (e.g., “Belgian Grand Prix”)
  5. Sessions dictionary
    • Keys must match event names from events list
    • Values must be lists of session names
    • Session names must be strings (e.g., “Practice 1”, “Qualifying”, “Race”)

Error Messages

The validator provides detailed error messages:
# Missing schema version
InvalidDataError: Unsupported schedule schema version: None

# Invalid year key
InvalidDataError: Invalid year key: 'twenty-twenty-one'

# Missing events list
InvalidDataError: Invalid events list for year=2021

# Invalid session list
InvalidDataError: Invalid session list for year=2021 event='Belgian Grand Prix'

# Not a dictionary
InvalidDataError: Schedule payload must be an object

Usage in tif1

The schedule validation is used internally by:

get_events()

import tif1

# Internally validates schedule before returning events
events = tif1.get_events(2021)

get_sessions()

import tif1

# Internally validates schedule before returning sessions
sessions = tif1.get_sessions(2021, "Belgian Grand Prix")
# Returns: ['Practice 1', 'Practice 2', 'Practice 3', 'Qualifying', 'Race']

Custom Schedule Data

If you’re working with custom schedule data, you can validate it manually:
from tif1.schedule_schema import validate_schedule_payload
from tif1.exceptions import InvalidDataError

custom_schedule = {
    "schema_version": 1,
    "years": {
        "2021": {
            "events": ["Custom Event"],
            "sessions": {
                "Custom Event": ["Practice", "Qualifying", "Race"]
            }
        }
    }
}

try:
    validated = validate_schedule_payload(custom_schedule)
    print("Custom schedule is valid")
except InvalidDataError as e:
    print(f"Validation failed: {e}")

Internal Data Flow

The schedule system works as follows:
  1. Raw f1schedule data: Vendored JSON files in src/tif1/data/schedules/f1schedule/ contain per-year schedule data in columnar format
  2. Conversion: _convert_f1schedule_year() transforms raw data into the internal schema
  3. Validation: validate_schedule_payload() ensures the converted data is valid
  4. Caching: Validated schedule is cached for performance
  5. API exposure: get_events() and get_sessions() use the validated data
The raw f1schedule format uses columnar data (like pandas DataFrames stored as JSON), while the internal format uses event-centric structure for easier querying.

Performance

Schedule validation is fast:
  • Typical validation time: <1ms
  • Schedule data is cached after first load
  • Validation only runs once per session
  • No network requests (data is vendored)

Complete Example

import tif1
from tif1.schedule_schema import validate_schedule_payload
from tif1.exceptions import InvalidDataError

# Get the 2021 Belgian Grand Prix Race
event = tif1.get_event(2021, "Belgian Grand Prix")
print(f"Event: {event['EventName']}")
print(f"Location: {event['Location']}")
print(f"Round: {event['RoundNumber']}")

# Get all sessions for this event
sessions = tif1.get_sessions(2021, "Belgian Grand Prix")
print(f"Sessions: {sessions}")

# Load the race session
race = event.get_session("Race")
race.load()
print(f"Drivers: {race.drivers}")

# Manual validation (internal use)
from tif1.events import _load_vendored_f1schedule_years

years = _load_vendored_f1schedule_years()
payload = {"schema_version": 1, "years": years}

try:
    validated = validate_schedule_payload(payload)
    print(f"Validated {len(validated['years'])} years")
except InvalidDataError as e:
    print(f"Validation failed: {e}")

Events & Schedule

Event discovery and session access

Core API

Load and work with session data

Exceptions

Error handling

Examples

Usage examples
Last modified on March 5, 2026