Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/TracingInsights/tif1/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The tif1 library provides a structured exception hierarchy for handling different error conditions. All exceptions inherit from TIF1Error, making it easy to catch library-specific errors.

Exception Hierarchy

TIF1Error (base)
├── DataNotFoundError
│   ├── DriverNotFoundError
│   └── LapNotFoundError
├── NetworkError
├── InvalidDataError
├── CacheError
└── SessionNotLoadedError

Common Exceptions

TIF1Error

Base exception for all tif1 errors:
import tif1

try:
    session = tif1.get_session(2025, "Invalid GP", "Race")
    laps = session.laps
except tif1.TIF1Error as e:
    print(f"tif1 error: {e}")
    print(f"Context: {e.context}")

DataNotFoundError

Raised when requested data doesn’t exist:
import tif1

# Invalid event name
try:
    session = tif1.get_session(2025, "Nonexistent GP", "Practice 1")
    laps = session.laps
except tif1.DataNotFoundError as e:
    print(f"Data not found: {e}")
    print("Available events:")
    events = tif1.get_events(2025)
    for event in events[:5]:
        print(f"  • {event}")

# Invalid session type
try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Invalid Session")
    laps = session.laps
except tif1.DataNotFoundError as e:
    print(f"Session not found: {e}")
    print("Available sessions:")
    sessions = tif1.get_sessions(2025, "Monaco Grand Prix")
    for session in sessions:
        print(f"  • {session}")

DriverNotFoundError

Raised when a driver isn’t in the session:
import tif1

session = tif1.get_session(2025, "Monaco Grand Prix", "Race")

try:
    driver = session.get_driver("XXX")  # Invalid driver code
except tif1.DriverNotFoundError as e:
    print(f"Driver not found: {e}")
    print(f"Context: {e.context}")
    print("\nAvailable drivers:")
    for _, d in session.drivers_df.iterrows():
        print(f"  {d['Driver']:3s} - {d['FullName']}")

LapNotFoundError

Raised when a lap doesn’t exist:
import tif1

session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
ver = session.get_driver("VER")

try:
    lap = ver.get_lap(999)  # Lap number doesn't exist
except tif1.LapNotFoundError as e:
    print(f"Lap not found: {e}")
    print(f"Driver: {e.context.get('driver')}")
    print(f"Lap number: {e.context.get('lap_number')}")
    
    # Show available laps
    ver_laps = ver.laps
    if len(ver_laps) > 0:
        if hasattr(ver_laps, "iloc"):
            min_lap = ver_laps["lap"].min()
            max_lap = ver_laps["lap"].max()
        else:
            lap_nums = list(ver_laps["lap"])
            min_lap = min(lap_nums)
            max_lap = max(lap_nums)
        print(f"Available laps: {min_lap} to {max_lap}")

NetworkError

Raised when network requests fail:
import tif1

try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
    laps = session.laps
except tif1.NetworkError as e:
    print(f"Network error: {e}")
    print(f"URL: {e.context.get('url')}")
    print(f"Status: {e.context.get('status_code')}")
    print("\nTips:")
    print("  • Check your internet connection")
    print("  • Verify CDN availability")
    print("  • Try again later (temporary CDN issue)")
Note: Network errors are automatically retried (max 3 attempts by default). The exception is only raised after all retries fail.

InvalidDataError

Raised when data validation fails:
import tif1
from tif1.config import get_config

# Enable data validation
config = get_config()
config.set("validate_data", True)

try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
    laps = session.laps
except tif1.InvalidDataError as e:
    print(f"Invalid data: {e}")
    print(f"Reason: {e.context.get('reason')}")

CacheError

Raised when cache operations fail:
import tif1

try:
    cache = tif1.get_cache()
    cache.clear()
except tif1.CacheError as e:
    print(f"Cache error: {e}")
    print("Cache operations failed, continuing without cache...")

SessionNotLoadedError

Raised when accessing data before loading:
import tif1
from tif1.core import Session

try:
    # Create session without loading
    session = Session(
        year=2025,
        event="Monaco Grand Prix",
        session_type="Race"
    )
    # Try to access data before loading
    laps = session.laps  # Error: data not loaded
except tif1.SessionNotLoadedError as e:
    print(f"Session not loaded: {e}")
    print(f"Attribute: {e.context.get('attribute')}")
    print("\nLoad session data first:")
    print("  session.load(laps=True)")

Error Handling Patterns

Basic Error Handling

import tif1

try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
    laps = session.laps
    print(f"Loaded {len(laps)} laps")
except tif1.TIF1Error as e:
    print(f"Error: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

Specific Error Handling

import tif1

try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
    ver = session.get_driver("VER")
    lap = ver.get_lap(19)
    telemetry = lap.telemetry
except tif1.DataNotFoundError as e:
    print(f"Data not found: {e}")
    # Handle missing data
except tif1.DriverNotFoundError as e:
    print(f"Driver not found: {e}")
    # Show available drivers
except tif1.LapNotFoundError as e:
    print(f"Lap not found: {e}")
    # Show available laps
except tif1.NetworkError as e:
    print(f"Network error: {e}")
    # Retry or use cache
except tif1.TIF1Error as e:
    print(f"tif1 error: {e}")
    # Generic tif1 error handling

Defensive Programming

Validate inputs before making requests:
import tif1

def get_driver_fastest_lap(year, event, session_type, driver_code):
    """Safely get driver's fastest lap with validation."""
    try:
        # 1. Validate event exists
        events = tif1.get_events(year)
        if event not in events:
            print(f"Event '{event}' not found in {year}")
            print(f"Available events: {events[:5]}...")
            return None
        
        # 2. Validate session exists
        sessions = tif1.get_sessions(year, event)
        if session_type not in sessions:
            print(f"Session '{session_type}' not found")
            print(f"Available sessions: {sessions}")
            return None
        
        # 3. Load session
        session = tif1.get_session(year, event, session_type)
        
        # 4. Validate driver exists
        drivers_df = session.drivers_df
        if driver_code not in drivers_df["Driver"].values:
            print(f"Driver '{driver_code}' not in session")
            print("Available drivers:")
            for _, d in drivers_df.iterrows():
                print(f"  {d['Driver']:3s} - {d['FullName']}")
            return None
        
        # 5. Get driver and fastest lap
        driver = session.get_driver(driver_code)
        fastest = driver.get_fastest_lap()
        
        if len(fastest) > 0:
            return fastest
        else:
            print(f"No valid laps for {driver_code}")
            return None
            
    except tif1.TIF1Error as e:
        print(f"Error: {e}")
        return None

# Usage
fastest = get_driver_fastest_lap(2025, "Monaco Grand Prix", "Race", "VER")
if fastest is not None:
    lap_time = fastest["LapTime"].iloc[0]
    print(f"VER fastest lap: {lap_time:.3f}s")

Retry with Backoff

Implement custom retry logic for specific errors:
import tif1
import time

def load_session_with_retry(year, event, session_type, max_retries=3):
    """Load session with custom retry logic."""
    for attempt in range(max_retries):
        try:
            session = tif1.get_session(year, event, session_type)
            laps = session.laps
            return session
        except tif1.NetworkError as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt  # Exponential backoff
                print(f"Network error (attempt {attempt + 1}/{max_retries})")
                print(f"Retrying in {wait_time}s...")
                time.sleep(wait_time)
            else:
                print(f"Failed after {max_retries} attempts")
                raise
        except tif1.DataNotFoundError as e:
            # Don't retry for data not found
            print(f"Data not found: {e}")
            return None

# Usage
session = load_session_with_retry(2025, "Monaco Grand Prix", "Race")
if session:
    print(f"Loaded {len(session.laps)} laps")

Graceful Degradation

Provide fallbacks when errors occur:
import tif1

def analyze_driver_with_fallback(session, driver_code):
    """Analyze driver with graceful fallback."""
    try:
        # Try to get driver
        driver = session.get_driver(driver_code)
        laps = driver.laps
        
        if len(laps) == 0:
            print(f"{driver_code} has no laps")
            return None
        
        # Try to get fastest lap
        try:
            fastest = driver.get_fastest_lap()
            if len(fastest) > 0:
                lap_time = fastest["LapTime"].iloc[0]
                return {"driver": driver_code, "fastest": lap_time}
        except tif1.LapNotFoundError:
            print(f"No fastest lap for {driver_code}")
            return None
            
    except tif1.DriverNotFoundError:
        # Driver not in session, return None
        return None

# Analyze all drivers, skip those not in session
session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
drivers_to_check = ["VER", "HAM", "LEC", "NOR", "XXX"]

results = []
for driver_code in drivers_to_check:
    result = analyze_driver_with_fallback(session, driver_code)
    if result:
        results.append(result)

print(f"\nAnalyzed {len(results)} drivers:")
for r in results:
    print(f"  {r['driver']}: {r['fastest']:.3f}s")

Logging for Debugging

Enable logging to see detailed error information:
import logging
import tif1

# Enable debug logging
tif1.setup_logging(logging.DEBUG)

# Or use standard logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

try:
    session = tif1.get_session(2025, "Monaco Grand Prix", "Race")
    laps = session.laps
except tif1.TIF1Error as e:
    logging.error(f"Error loading session: {e}", exc_info=True)
Configure log level via environment variable:
export TIF1_LOG_LEVEL=DEBUG
python your_script.py
Or via configuration file:
{
  "log_level": "DEBUG"
}

Complete Error Handling Example

import logging
import tif1

# Setup logging
tif1.setup_logging(logging.INFO)

def safe_driver_analysis(year, event, session_type, driver_code):
    """Comprehensive error handling example."""
    print(f"\nAnalyzing {driver_code} in {event} {session_type}")
    print("=" * 60)
    
    try:
        # 1. Get available events
        events = tif1.get_events(year)
        if event not in events:
            print(f"✗ Event not found")
            print(f"  Tip: Use tif1.get_events({year}) to list events")
            return False
        print("✓ Event found")
        
        # 2. Get available sessions
        sessions = tif1.get_sessions(year, event)
        if session_type not in sessions:
            print(f"✗ Session not found")
            print(f"  Available: {sessions}")
            return False
        print("✓ Session found")
        
        # 3. Load session
        try:
            session = tif1.get_session(year, event, session_type)
            print("✓ Session loaded")
        except tif1.NetworkError as e:
            print(f"✗ Network error: {e}")
            print("  Tip: Check internet connection")
            return False
        
        # 4. Validate driver exists
        drivers_df = session.drivers_df
        if driver_code not in drivers_df["Driver"].values:
            print(f"✗ Driver {driver_code} not in session")
            print("  Available drivers:")
            for _, d in drivers_df.head(5).iterrows():
                print(f"    {d['Driver']:3s} - {d['FullName']}")
            return False
        print(f"✓ Driver {driver_code} found")
        
        # 5. Get driver data
        driver = session.get_driver(driver_code)
        laps = driver.laps
        
        if len(laps) == 0:
            print(f"✗ No laps available for {driver_code}")
            return False
        print(f"✓ {len(laps)} laps loaded")
        
        # 6. Get fastest lap
        fastest = driver.get_fastest_lap()
        if len(fastest) > 0:
            lap_time = fastest["LapTime"].iloc[0]
            lap_num = fastest["LapNumber"].iloc[0]
            print(f"✓ Fastest lap: {lap_time:.3f}s (Lap {lap_num})")
        else:
            print("✗ No valid lap times")
            return False
        
        # 7. Get telemetry
        try:
            lap = driver.get_lap(int(lap_num))
            telemetry = lap.telemetry
            print(f"✓ Telemetry loaded: {len(telemetry)} points")
            print(f"  Max speed: {telemetry['Speed'].max():.1f} km/h")
        except tif1.LapNotFoundError as e:
            print(f"✗ Lap telemetry not available: {e}")
        
        return True
        
    except tif1.TIF1Error as e:
        print(f"✗ tif1 error: {e}")
        return False
    except Exception as e:
        print(f"✗ Unexpected error: {e}")
        logging.exception("Unexpected error")
        return False

# Test the function
print("ERROR HANDLING DEMONSTRATION")
print("=" * 60)

# Valid request
safe_driver_analysis(2025, "Monaco Grand Prix", "Race", "VER")

# Invalid driver
safe_driver_analysis(2025, "Monaco Grand Prix", "Race", "XXX")

# Invalid event
safe_driver_analysis(2025, "Invalid GP", "Race", "VER")

Next Steps

Build docs developers (and LLMs) love