Esempio n. 1
0
async def get_pitstops(rnd, season):
    """Get the race pitstop times for each driver.

    Parameters
    ----------
    `season`, `rnd` : int

    Returns
    -------
    `res` : list[dict] {
        'season': str,
        'round': str,
        'race': str,
        'date': str,
        'time': str,
        'total_laps': int,
        'data': list[dict] {
            'Driver_id': str,
            'Stop_no': int,
            'Lap': int,
            'Time': str,
            'Duration': str,
        }
    }

    Raises
    ------
    `MissingDataError`
        if API response invalid.
    """
    url = f"{BASE_URL}/{season}/{rnd}/pitstops?limit=100"
    soup = await get_soup(url)
    if soup:
        race = soup.race
        pitstops = race.pitstopslist.find_all('pitstop')
        date, time = (race.date.string, race.time.string)
        results = await get_race_results(rnd, season, winner_only=True)
        laps = results['data'][0]['Laps']
        res = {
            'season': race['season'],
            'round': race['round'],
            'race': race.racename.string,
            'date': f"{utils.date_parser(date)} {race['season']}",
            'time': utils.time_parser(time),
            'total_laps': laps,
            'data': []
        }
        for stop in pitstops:
            driver = get_driver_info(stop['driverid'])
            res['data'].append(
                {
                    'Driver': f"{driver['code']}",
                    'Stop_no': int(stop['stop']),
                    'Lap': int(stop['lap']),
                    'Time': stop['time'],
                    'Duration': stop['duration'],
                }
            )
        return res
    raise MissingDataError()
Esempio n. 2
0
async def get_all_drivers():
    """Fetch all driver data as JSON. Returns a dict."""
    url = f'{BASE_URL}/drivers.json?limit=1000'
    # Get JSON data as dict
    res = await fetch(url)
    if res is None:
        raise MissingDataError()
    return res
Esempio n. 3
0
async def get_all_laps(rnd, season):
    """Get time and position data for each driver per lap in the race.

    Parameters
    ----------
    `rnd`, `season` : int

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'race': str,
            'url': str,
            'date': str,
            'time': str,
            'data': dict[list] - dict keys are lap number and values are list of dicts per driver:
                {
                    1: [ {'id': str, 'lap': int, 'pos': int, 'time': str} ... ],
                    2: [ ... ],
                    ...
                }
        }

    Raises
    ------
    `MissingDataError`
        if API response invalid.
    """
    url = f"{BASE_URL}/{season}/{rnd}/laps?limit=2000"
    soup = await get_soup(url)
    if soup:
        race = soup.race
        laps = race.lapslist.find_all('lap')
        date, time = (race.date.string, race.time.string)
        res = {
            'season': race['season'],
            'round': race['round'],
            'race': race.racename.string,
            'url': race['url'],
            'date': f"{utils.date_parser(date)} {race['season']}",
            'time': utils.time_parser(time),
            'data': {},
        }
        for lap in laps:
            res['data'][int(lap['number'])] = [
                {
                    'id': t['driverid'],
                    'Pos': int(t['position']),
                    'Time': t['time']
                }
                for t in lap.find_all('timing')]
        return res
    raise MissingDataError()
Esempio n. 4
0
async def get_driver_poles(driver_id):
    """Get total pole positions for driver with details for each race.

    Parameters
    ----------
    `driver_id` : str
        must be valid Eargast API ID, e.g. 'alonso', 'michael_schumacher'.

    Returns
    -------
    `res` : dict
        {
            'total': int,
            'data': list[dict] [{
                'Race': str,
                'Circuit': str,
                'Date': str,
                'Team': str,
                'Q1': str,
                'Q2': str,
                'Q3': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response invalid.
    """
    url = f"{BASE_URL}/drivers/{driver_id}/qualifying/1?limit=200"
    soup = await get_soup(url)
    if soup:
        races = soup.racetable.find_all('race')
        res = {
            'total':  int(soup.mrdata['total']),
            'data': []
        }
        for race in races:
            quali_result = race.qualifyinglist.qualifyingresult
            res['data'].append(
                {
                    'Race': race.racename.string,
                    'Circuit': race.circuitname.string,
                    'Date': utils.date_parser(race.date.string),
                    'Team': quali_result.constructor.find('name').string,
                    'Q1': quali_result.q1.string if quali_result.q1 is not None else None,
                    'Q2': quali_result.q2.string if quali_result.q2 is not None else None,
                    'Q3': quali_result.q3.string if quali_result.q3 is not None else None,
                }
            )
        return res
    return MissingDataError()
Esempio n. 5
0
async def get_driver_wins(driver_id):
    """Get total wins for the driver and a list of dicts with details for each race.

    Parameters
    ----------
    `driver_id` : str
        must be valid Eargast API ID, e.g. 'alonso', 'michael_schumacher'.

    Returns
    -------
    `res` : dict
        {
            'total': int,
            'data': list[dict] [{
                'Race': str,
                'Circuit': str,
                'Date': str,
                'Team': str,
                'Grid': int,
                'Laps': int,
                'Time': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response invalid.
    """
    url = f"{BASE_URL}/drivers/{driver_id}/results/1?limit=200"
    soup = await get_soup(url)
    if soup:
        races = soup.racetable.find_all('race')
        res = {
            'total': int(soup.mrdata['total']),
            'data': []
        }
        for race in races:
            race_result = race.resultslist.result
            res['data'].append(
                {
                    'Race': race.racename.string,
                    'Circuit': race.circuitname.string,
                    'Date': utils.date_parser(race.date.string),
                    'Team': race_result.constructor.find('name').string,
                    'Grid': int(race_result.grid.string),
                    'Laps': int(race_result.laps.string),
                    'Time': race_result.time.string,
                }
            )
        return res
    return MissingDataError()
Esempio n. 6
0
async def get_all_drivers_and_teams(season):
    """Get all drivers and teams on the grid.

    Parameters
    ----------
    `season` : int

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'data': list[dict] [{
                'Code': str,
                'No': int,
                'Name': str,
                'Age': int,
                'Nationality': str,
                'Team': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    url = f'{BASE_URL}/{season}/driverStandings'
    soup = await get_soup(url)
    if soup:
        standings = soup.find_all('driverstanding')
        results = {
            'season': soup.standingslist['season'],
            'round': soup.standingslist['round'],
            'data': []
        }
        for standing in standings:
            driver = standing.driver
            team = standing.constructor
            results['data'].append(
                {
                    'Code': driver['code'],
                    'No': int(driver.permanentnumber.string),
                    'Name': f'{driver.givenname.string} {driver.familyname.string}',
                    'Age': utils.age(driver.dateofbirth.string[:4]),
                    'Nationality': driver.nationality.string,
                    'Team': team.find('name').string,
                }
            )
        return results
    raise MissingDataError()
Esempio n. 7
0
async def get_driver_standings(season):
    """Get the driver championship standings.

    Fetches results from API. Response XML is parsed into a list of dicts to be tabulated.
    Data includes position, driver code, total points and wins.

    Parameters
    ----------
    `season` : int

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'data': list[dict] [{
                'Pos': int,
                'Driver': str,
                'Points': int,
                'Wins': int,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    url = f'{BASE_URL}/{season}/driverStandings'
    soup = await get_soup(url)
    if soup:
        # tags are lowercase
        standings = soup.standingslist
        results = {
            'season': standings['season'],
            'round': standings['round'],
            'data': [],
        }
        for standing in standings.find_all('driverstanding'):
            results['data'].append(
                {
                    'Pos': int(standing['position']),
                    'Driver': f"{standing.driver.givenname.string[0]} {standing.driver.familyname.string}",
                    'Points': int(standing['points']),
                    'Wins': int(standing['wins']),
                }
            )
        return results
    raise MissingDataError()
Esempio n. 8
0
async def get_team_standings(season):
    """Get the constructor championship standings.

    Fetches results from API. Response XML is parsed into a list of dicts to be tabulated.
    Data includes position, team, total points and wins.

    Parameters
    ----------
    `season` : int

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'data': list[dict] [{
                'Pos': int,
                'Team': str,
                'Points': int,
                'Wins': int,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    url = f'{BASE_URL}/{season}/constructorStandings'
    soup = await get_soup(url)
    if soup:
        standings = soup.standingslist
        results = {
            'season': standings['season'],
            'round': standings['round'],
            'data': [],
        }
        for standing in standings.find_all('constructorstanding'):
            results['data'].append(
                {
                    'Pos': int(standing['position']),
                    'Team': standing.constructor.find('name').string,
                    'Points': int(standing['points']),
                    'Wins': int(standing['wins']),
                }
            )
        return results
    raise MissingDataError()
Esempio n. 9
0
async def get_driver_seasons(driver_id):
    """Get all seasons the driver has participated in as a dict.

    Raises `MissingDataError`.
    """
    url = f"{BASE_URL}/drivers/{driver_id}/seasons"
    soup = await get_soup(url)
    if soup:
        seasons = soup.seasontable.find_all('season')
        res = {
            'total': int(soup.mrdata['total']),
            'data': [{'year': int(s.string), 'url': s['url']} for s in seasons]
        }
        return res
    raise MissingDataError()
Esempio n. 10
0
async def get_next_race():
    """Get the next race in the calendar and a countdown (from moment of req) as dict.

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'countdown': str,
            'url': str,
            'data': list[dict] [{
                'Round': int,
                'Name': str,
                'Date': str,
                'Time': str,
                'Circuit': str,
                'Country': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    url = f'{BASE_URL}/current/next'
    soup = await get_soup(url)
    if soup:
        race = soup.race
        date, time = (race.date.string, race.time.string)
        cd = utils.countdown(datetime.strptime(
            f'{date} {time}', '%Y-%m-%d %H:%M:%SZ'
        ))
        result = {
            'season': race['season'],
            'countdown': cd[0],
            'url': race['url'],
            'data': {
                'Round': int(race['round']),
                'Name': race.racename.string,
                'Date': f"{utils.date_parser(date)} {race['season']}",
                'Time': utils.time_parser(time),
                'Circuit': race.circuit.circuitname.string,
                'Country': race.location.country.string,
            }
        }
        return result
    raise MissingDataError()
Esempio n. 11
0
async def get_driver_championship_wins(driver_id):
    """Returns dict with driver standings results where the driver placed first.

    Parameters
    ----------
    `driver_id` : str
        must be valid Eargast API ID, e.g. 'alonso', 'michael_schumacher'.

    Returns
    -------
    `res` : dict
        {
            'total': int,
            'data': list[dict] [{
                'Season': str,
                'Points': int,
                'Wins': int,
                'Team': str,
            }]
        }
    Raises
    ------
    `MissingDataError`
    """
    url = f"{BASE_URL}/drivers/{driver_id}/driverStandings/1"
    soup = await get_soup(url)
    if soup:
        standings = soup.standingstable.find_all('standingslist')
        res = {
            'total': int(soup.mrdata['total']),
            'data': []
        }
        for standing in standings:
            res['data'].append(
                {
                    'Season': standing['season'],
                    'Pos': int(standing.driverstanding['position']),
                    'Wins': int(standing.driverstanding['wins']),
                    'Points': int(standing.driverstanding['points']),
                    'Team': standing.driverstanding.constructor.find('name').string,
                }
            )
        return res
    raise MissingDataError()
Esempio n. 12
0
async def get_race_schedule():
    """Get full race calendar with circuit names and date as dict.

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'data': list[dict] [{
                'Round': int,
                'Circuit': str,
                'Date': str,
                'Time': str,
                'Country': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    url = f'{BASE_URL}/current'
    soup = await get_soup(url)
    if soup:
        races = soup.find_all('race')
        results = {
            'season': soup.racetable['season'],
            'data': []
        }
        for race in races:
            results['data'].append(
                {
                    'Round': int(race['round']),
                    'Circuit': race.circuit.circuitname.string,
                    'Date': utils.date_parser(race.date.string),
                    'Time': utils.time_parser(race.time.string),
                    'Country': race.location.country.string,
                }
            )
        return results
    raise MissingDataError()
Esempio n. 13
0
async def get_qualifying_results(rnd, season):
    """Gets qualifying results for `round` in `season`.

    E.g. `get_qualifying_results(12, 2008)` --> Results for round 12 in 2008 season.

    Data includes Q1, Q2, Q3 times per driver, position, laps per driver.

    Parameters
    ----------
    `rnd` : int or str
        Race number or 'last' for the latest race
    `season` : int or str
        Season year or 'current'

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'race': str,
            'url': str,
            'date': str,
            'time': str,
            'data': list[dict] [{
                'Pos': int,
                'Driver': str,
                'Team': str,
                'Q1': str,
                'Q2': str,
                'Q3': str,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response invalid.
    """
    url = f'{BASE_URL}/{season}/{rnd}/qualifying'
    soup = await get_soup(url)
    if soup:
        race = soup.race
        quali_results = race.qualifyinglist.find_all('qualifyingresult')
        date, time = (race.date.string, race.time.string)
        res = {
            'season': race['season'],
            'round': race['round'],
            'race': race.racename.string,
            'url': race['url'],
            'date': f"{utils.date_parser(date)} {race['season']}",
            'time': utils.time_parser(time),
            'data': []
        }
        for result in quali_results:
            res['data'].append(
                {
                    'Pos': int(result['position']),
                    'Driver': result.driver['code'],
                    'Team': result.constructor.find('name').string,
                    'Q1': result.q1.string if result.q1 is not None else None,
                    'Q2': result.q2.string if result.q2 is not None else None,
                    'Q3': result.q3.string if result.q3 is not None else None,
                }
            )
        return res
    raise MissingDataError()
Esempio n. 14
0
async def get_race_results(rnd, season, winner_only=False):
    """Get race results for `round` in `season` as dict.

    E.g. `get_race_results(12, 2008)` --> Results for 2008 season, round 12.

    Data includes finishing position, fastest lap, finish status, pit stops per driver.

    Parameters
    ----------
    `rnd` : int
    `season` : int
    `winner_only` : bool

    Returns
    -------
    `res` : dict
        {
            'season': str,
            'round': str,
            'race': str,
            'url': str,
            'date': str,
            'time': str,
            'data': list[dict] [{
                'Pos': int,
                'Driver': str,
                'Team': str,
                'Laps': int,
                'Start': int,
                'Time': str,
                'Status': str,
                'Points': int,
            }],
            'timings': list[dict] [{
                'Rank': int,
                'Driver': str,
                'Time': str,
                'Speed': int,
            }]
        }

    Raises
    ------
    `MissingDataError`
        if API response unavailable.
    """
    if winner_only is True:
        url = f'{BASE_URL}/{season}/{rnd}/results/1'
    else:
        url = f'{BASE_URL}/{season}/{rnd}/results'
    soup = await get_soup(url)
    if soup:
        race = soup.race
        race_results = race.resultslist.find_all('result')
        date, time = (race.date.string, race.time.string)
        res = {
            'season': race['season'],
            'round': race['round'],
            'race': race.racename.string,
            'url': race['url'],
            'date': f"{utils.date_parser(date)} {race['season']}",
            'time': utils.time_parser(time),
            'data': [],
            'timings': [],
        }
        for result in race_results:
            driver = result.driver
            # Now get the fastest lap time element
            fastest_lap = result.fastestlap
            res['data'].append(
                {
                    'Pos': int(result['position']),
                    'Driver': f'{driver.givenname.string[0]} {driver.familyname.string}',
                    'Team': result.constructor.find('name').string,
                    'Start': int(result.grid.string),
                    'Laps': int(result.laps.string),
                    'Status': result.status.string,
                    'Points': int(result['points']),
                }
            )
            # Fastest lap data if available
            if fastest_lap is not None:
                res['timings'].append(
                    {
                        'Rank': int(fastest_lap['rank']),
                        'Driver': driver['code'],
                        'Time': fastest_lap.time.string,
                        'Speed (kph)': int(float(fastest_lap.averagespeed.string)),
                    }
                )
        return res
    raise MissingDataError()