Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanding Ergast filter parameters #489

Merged
merged 8 commits into from
Dec 26, 2023
53 changes: 36 additions & 17 deletions fastf1/ergast/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class ErgastRawResponse(ErgastResponseMixin, list):
auto_cast: Determines if values are automatically cast to the most
appropriate data type from their original string representation
"""

def __init__(self, *, query_result, category, auto_cast, **kwargs):
if auto_cast:
query_result = self._prepare_response(query_result, category)
Expand Down Expand Up @@ -351,6 +352,7 @@ class ErgastMultiResponse(ErgastResponseMixin):
auto_cast: Flag that enables or disables automatic casting from the
original string representation to the most suitable data type.
"""

def __init__(self, *args,
response_description: dict,
response_data: list,
Expand Down Expand Up @@ -409,6 +411,7 @@ class Ergast:
30 if not set. Maximum: 1000. See also "Response Paging" on
https://ergast.com/mrd/.
"""

def __init__(self,
result_type: Literal['raw', 'pandas'] = 'pandas',
auto_cast: bool = True,
Expand Down Expand Up @@ -439,41 +442,57 @@ def _build_url(
selectors.append(f"/{season}")
if round is not None:
selectors.append(f"/{round}")
if circuit is not None:
selectors.append(f"/circuits/{circuit}")
if constructor is not None:
selectors.append(f"/constructors/{constructor}")
if driver is not None:
selectors.append(f"/drivers/{driver}")
if grid_position is not None:
selectors.append(f"/grid/{grid_position}")
if results_position is not None:
selectors.append(f"/results/{results_position}")
if fastest_rank is not None:
selectors.append(f"/fastest/{fastest_rank}")
if status is not None:
selectors.append(f"/status/{status}")

# some special cases: the endpoint may also be used as selector
# therefore, if the specifier is defined, do not add the endpoint
theOehrly marked this conversation as resolved.
Show resolved Hide resolved
# string additionally
if driver is not None:
if endpoint == 'drivers':
endpoint = f"drivers/{driver}"
else:
selectors.append(f"/drivers/{driver}")

if constructor is not None:
if endpoint == 'constructors':
endpoint = f"constructors/{constructor}"
else:
selectors.append(f"/constructors/{constructor}")

if circuit is not None:
if endpoint == 'circuits':
endpoint = f"circuits/{circuit}"
else:
selectors.append(f"/circuits/{circuit}")

if status is not None:
if endpoint == 'status':
endpoint = f"status/{status}"
else:
selectors.append(f"/status/{status}")

if standings_position is not None:
if endpoint == 'driverStandings':
selectors.append(f"/driverStandings/{standings_position}")
endpoint = None
endpoint = f"driverStandings/{standings_position}"
elif endpoint == 'constructorStandings':
selectors.append(f"/constructorStandings/{standings_position}")
endpoint = None
endpoint = f"constructorStandings/{standings_position}"

if lap_number is not None:
selectors.append(f"/laps/{lap_number}")
if endpoint == 'laps':
endpoint = None
endpoint = f"laps/{lap_number}"
else:
selectors.append(f"/laps/{lap_number}")

if stop_number is not None:
selectors.append(f"/pitstops/{stop_number}")
if endpoint == 'pitstops':
endpoint = None
endpoint = f"pitstops/{stop_number}"
else:
selectors.append(f"/pitstops/{stop_number}")

if endpoint is not None:
selectors.append(f"/{endpoint}")
Expand Down Expand Up @@ -845,7 +864,7 @@ def get_constructor_info(
'fastest_rank': fastest_rank,
'status': status}

return self._build_default_result(endpoint='constructors',
return self._build_default_result(endpoint="constructors",
table='ConstructorTable',
category=API.Constructors,
subcategory=None,
Expand Down
70 changes: 59 additions & 11 deletions fastf1/tests/test_ergast.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,30 +313,78 @@ def test_merge_dicts_of_lists(data, expected):
@pytest.mark.parametrize(
"endpoint, selectors, expected",
(
# "normal" behaviour for most endpoints
# "simple" behaviour
['seasons', {}, "https://ergast.com/api/f1/seasons.json"],
['circuits', {'driver': 'alonso', 'constructor': 'alpine'},
"https://ergast.com/api/f1/constructors/alpine/"
"drivers/alonso/circuits.json"],
['races', {'season': 2022},
"https://ergast.com/api/f1/2022/races.json"],
['results', {'season': 2022, 'round': '10'},
"https://ergast.com/api/f1/2022/10/results.json"],
['sprint', {'season': 2022, 'round': '4'},
"https://ergast.com/api/f1/2022/4/sprint.json"],
['qualifying', {'season': 2022, 'round': '10'},
"https://ergast.com/api/f1/2022/10/qualifying.json"],
# special cases where endpoint name matches selector and the endpoint
# gets extended with its selection
['drivers', {},
"https://ergast.com/api/f1/drivers.json"],
['drivers', {'driver': 'alonso'},
"https://ergast.com/api/f1/drivers/alonso.json"],
['constructors', {},
"https://ergast.com/api/f1/constructors.json"],
['constructors', {'constructor': 'ferrari'},
"https://ergast.com/api/f1/constructors/ferrari.json"],
['circuits', {},
"https://ergast.com/api/f1/circuits.json"],
['circuits', {'circuit': 'monza'},
"https://ergast.com/api/f1/circuits/monza.json"],
['status', {},
"https://ergast.com/api/f1/status.json"],
['status', {'status': '1'},
"https://ergast.com/api/f1/status/1.json"],
['driverStandings', {'season': 2022},
"https://ergast.com/api/f1/2022/driverStandings.json"],
['driverStandings', {'season': 2022, 'standings_position': '1'},
"https://ergast.com/api/f1/2022/driverStandings/1.json"],
['constructorStandings', {'season': 2022},
"https://ergast.com/api/f1/2022/constructorStandings.json"],
['constructorStandings', {'season': 2022, 'standings_position': '1'},
"https://ergast.com/api/f1/2022/constructorStandings/1.json"],
# special case where endpoint name matches selector
['laps', {'season': 2022, 'round': 10},
"https://ergast.com/api/f1/2022/10/laps.json"],
['laps', {'season': 2022, 'round': 10, 'lap_number': 1},
"https://ergast.com/api/f1/2022/10/laps/1.json"],
['pitstops', {'season': 2022, 'round': 10},
"https://ergast.com/api/f1/2022/10/pitstops.json"],
['pitstops', {'season': 2022, 'round': 10, 'stop_number': '1'},
"https://ergast.com/api/f1/2022/10/pitstops/1.json"],
# endpoint/selector combination in other request
['pitstops', {'season': 2022, 'round': 10, 'lap_number': 1},
"https://ergast.com/api/f1/2022/10/laps/1/pitstops.json"],
# combined selector standings_position
['driverStandings', {'season': 2022, 'standings_position': 1},
"https://ergast.com/api/f1/2022/driverStandings/1.json"],
['constructorStandings', {'season': 2022, 'standings_position': 3},
"https://ergast.com/api/f1/2022/constructorStandings/3.json"]
['circuits', {'driver': 'alonso', 'constructor': 'alpine'},
"https://ergast.com/api/f1/drivers/alonso/"
"constructors/alpine/circuits.json"],
)
)
def test_ergast_build_url(endpoint: str, selectors: dict, expected: str):
Expand Down