> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/TracingInsights-Archive/Stats/llms.txt
> Use this file to discover all available pages before exploring further.

# driver_points.py

> Fetch Formula 1 driver championship standings

# driver\_points.py

The `driver_points.py` script fetches driver championship standings after each race. It tracks points accumulated by drivers throughout the season.

## Overview

This script:

* Fetches driver standings from the Ergast API
* Saves cumulative points after each round
* Implements rate limiting and logging
* Requires the events.json file to exist first

## Functions

### create\_folder\_if\_not\_exists()

```python driver_points.py theme={null}
def create_folder_if_not_exists(folder_path):
    """Create folder if it doesn't exist"""
    if not os.path.exists(folder_path):
        os.makedirs(folder_path)
        logger.info(f"Created folder: {folder_path}")
```

### get\_race\_folder\_name()

```python driver_points.py theme={null}
def get_race_folder_name(race):
    """Convert race name to folder name format"""
    return race["raceName"].lower().replace(" ", "-")
```

### fetch\_with\_rate\_limit()

```python driver_points.py theme={null}
def fetch_with_rate_limit(url):
    """Fetch data with rate limiting"""
    logger.info(f"Fetching: {url}")
    time.sleep(REQUEST_DELAY)  # Respect rate limit
    response = requests.get(url)
    
    if response.status_code == 429:
        logger.warning("Rate limit exceeded. Waiting 30 seconds before retrying...")
        time.sleep(30)
        return fetch_with_rate_limit(url)
    
    if response.status_code != 200:
        logger.error(f"Error fetching {url}: {response.status_code} - {response.text}")
        return None
    
    return response.json()
```

### fetch\_driver\_standings()

```python driver_points.py theme={null}
def fetch_driver_standings(season, round_num):
    """Fetch driver standings for a specific round in a season"""
    url = f"{BASE_URL}/{season}/{round_num}/driverstandings/"
    return fetch_with_rate_limit(url)
```

### process\_round()

Main function that processes a specific round.

```python driver_points.py theme={null}
def process_round(season, round_num):
    """Process a specific round in a season"""
    logger.info(f"Processing season: {season}, round: {round_num}")
    
    # Create season folder
    season_folder = Path(f"{season}")
    create_folder_if_not_exists(season_folder)
    
    # Fetch events data for the season
    events_file = season_folder / "events.json"
    if not events_file.exists():
        logger.warning(f"Events file not found for season {season}. Skipping.")
        return
    
    with open(events_file, "r") as f:
        events_data = json.load(f)
    
    races = events_data.get("MRData", {}).get("RaceTable", {}).get("Races", [])
    if not races:
        logger.warning(f"No races found for season {season}. Skipping.")
        return
    
    # Find the specific race for the round
    race = None
    for r in races:
        if r.get("round") == str(round_num):
            race = r
            break
    
    if not race:
        logger.warning(f"Round {round_num} not found for season {season}. Skipping.")
        return
    
    race_folder_name = get_race_folder_name(race)
    race_folder = season_folder / race_folder_name
    create_folder_if_not_exists(race_folder)
    
    # Fetch round-level driver standings
    round_standings = fetch_driver_standings(season, round_num)
    if round_standings:
        with open(race_folder / "driverPoints.json", "w") as f:
            json.dump(round_standings, f, indent=2)
            logger.info(f"Saved round driver standings to {race_folder}/driverPoints.json")
```

## Usage

### Fetch Standings for a Round

```python theme={null}
# Fetch driver standings after Round 1 of 2024
process_round(2024, 1)

# Fetch standings after Round 10
process_round(2024, 10)
```

### Command Line

```bash theme={null}
python driver_points.py
```

<Warning>
  You must run `events.py` first to create the events.json file. This script depends on it to determine race folder names.
</Warning>

## API Endpoint

```
GET https://api.jolpi.ca/ergast/f1/{season}/{round}/driverstandings/
```

## Output Structure

Standings are saved to: `{year}/{race-slug}/driverPoints.json`

```json theme={null}
{
  "MRData": {
    "StandingsTable": {
      "season": "2024",
      "round": "1",
      "StandingsLists": [
        {
          "season": "2024",
          "round": "1",
          "DriverStandings": [
            {
              "position": "1",
              "points": "25",
              "wins": "1",
              "Driver": {
                "driverId": "verstappen",
                "code": "VER",
                "givenName": "Max",
                "familyName": "Verstappen",
                "dateOfBirth": "1997-09-30",
                "nationality": "Dutch"
              },
              "Constructors": [
                {
                  "constructorId": "red_bull",
                  "name": "Red Bull"
                }
              ]
            }
          ]
        }
      ]
    }
  }
}
```

## Configuration

```python theme={null}
BASE_URL = "https://api.jolpi.ca/ergast/f1"
RATE_LIMIT_BURST = 2  # requests per second
RATE_LIMIT_SUSTAINED = 500  # requests per hour
REQUEST_DELAY = 1 / RATE_LIMIT_BURST  # seconds between requests
```

## Logging

Log file: `driver_standings_fetch.log`

## See Also

* [Standings Data Collection](/data-collection/standings)
* [Team Points Script](/api/team-points)
* [JSON Schemas](/data-structure/json-schemas)
