diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98cb4ad..cdf3d22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,15 +2,15 @@ name: Test, Build, Publish, Release on: push: - branches: [main, staging, dev] + branches: [main, dev] pull_request: - branches: [main, staging, dev] + branches: [main, dev] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} - # if branch is main, use prod, else staging or dev as necessary - BUILD_NAME: ${{ github.ref == 'refs/heads/main' && 'prod' || github.ref == 'refs/heads/staging' && 'staging' || 'dev' }} + # if branch is main, use prod, else dev + BUILD_NAME: ${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }} jobs: test: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cfe31ab..c167b88 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,9 +13,9 @@ name: "CodeQL" on: push: - branches: [main, staging, dev] + branches: [main, dev] pull_request: - branches: [main, staging, dev] + branches: [main, dev] schedule: - cron: "26 3 * * 6" diff --git a/.vscode/extensions.json b/.vscode/extensions.json index bc4e127..cc2ea92 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -7,11 +7,13 @@ "kisstkondoros.vscode-gutter-preview", "ms-python.isort", "yzhang.markdown-all-in-one", + "ms-python.mypy-type-checker", "christian-kohler.path-intellisense", "esbenp.prettier-vscode", "ms-python.vscode-pylance", "ms-python.pylint", "ms-python.python", + "ms-python.debugpy", "Gruntfuggly.todo-tree" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index e0a6210..05712ec 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,10 @@ "editor.formatOnSave": true, "black-formatter.args": ["--line-length", "120", "--target-version", "py312"], "isort.args": ["--settings-file", "${workspaceFolder}/pyproject.toml"], + "mypy-type-checker.args": [ + "--config-file", + "${workspaceFolder}/pyproject.toml" + ], "pylint.args": ["--rcfile", "${workspaceFolder}/.pylintrc"], "python.testing.pytestArgs": ["tests"], "python.testing.unittestEnabled": false, diff --git a/Dockerfile.staging b/Dockerfile.staging deleted file mode 100644 index 05ccd47..0000000 --- a/Dockerfile.staging +++ /dev/null @@ -1,49 +0,0 @@ -# https://fastapi.tiangolo.com/deployment/docker/#docker-image-with-poetry - -# First stage -FROM python:3.12.2-slim as requirements-stage - -# Set /tmp as the current working directory. -WORKDIR /tmp - -# Install Poetry -RUN pip install poetry - -# Copy the pyproject.toml and poetry.lock files to the /tmp directory. -COPY ./pyproject.toml ./poetry.lock* /tmp/ - -# Generate the requirements.txt file. -RUN poetry export -f requirements.txt --output requirements.txt --without-hashes - -# This is the final stage, anything here will be preserved in the final container image. -FROM python:3.12.2-slim - -# Install gcc and other dependencies -RUN apt-get update && apt-get install -y \ - build-essential \ - && rm -rf /var/lib/apt/lists/* - -# Set the current working directory to /code. -WORKDIR /code - -# Copy the requirements.txt file to the /code directory. -# This file only lives in the previous Docker stage, that's why we use --from-requirements-stage to copy it. -COPY --from=requirements-stage /tmp/requirements.txt /code/requirements.txt - -# Install the package dependencies in the generated requirements.txt file. -RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt - -# Copy the app directory to the /code directory. -COPY ./app /code/app - -# Make port 80 available to the world outside this container -EXPOSE 80 - -# Healthcheck -HEALTHCHECK --interval=5s --timeout=5s --retries=3 \ - CMD curl -f http://localhost:8081/health || exit 1 - -# Run the uvicorn command, telling it to use the app object imported from app.main. -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"] - -# CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "80"] diff --git a/README.md b/README.md index 74eddac..5a610dc 100644 --- a/README.md +++ b/README.md @@ -147,19 +147,17 @@ For other docker commands, see [useful_commands.md](./useful_commands.md) - [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph) (free) - **Branches**: - `main` is the production mainline. - - `staging` is the staging line. - `dev` is the development line (***default branch***). - **PR merge strategy on Github** - Code should flow in the following direction through branches: ``` - feature/bug fix -> dev -> staging -> main + feature/bug fix -> dev -> main ``` - We'll be keeping a linear commit history and so using a combination of `Rebase and merge` and `Squash and merge` merge strategies. - Use `Rebase and merge` as ***default*** to ensure all commits from the branch to be merged are brought in individually to the target branch. - `Squash and merge` may be used ***ONLY*** when bringing in changes from a feature/bug fix branch into `dev`. - To maintain linear commit history, ensure to use `push force` when: - - Bringing `dev` on the same commit as `staging` (ie rebasing `dev` onto `staging`). - - Bringing `staging` on the same commit as `main` (ie rebasing `staging` onto `main`). + - Bringing `dev` on the same commit as `main` (ie rebasing `dev` onto `main`). - [More information on git rebase](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase). - [More information on PR merge strategies](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github). - **Jira issue linking** diff --git a/app/constants.py b/app/constants.py index edd1573..41b64d7 100644 --- a/app/constants.py +++ b/app/constants.py @@ -4,10 +4,6 @@ METADATA_DESCRIPTION = """ Slick Telemetry backend written in python with fastf1. 🏎 - -## Schedule - -You can query Formula 1 schedule by **year**. """ EVENT_SCHEDULE_DATETIME_DTYPE_LIST = [ @@ -24,13 +20,20 @@ "Session5DateUtc", ] -MIN_SUPPORTED_YEAR = 1950 -MAX_SUPPORTED_YEAR = datetime.today().year +MIN_YEAR_SUPPORTED = 1950 +MIN_YEAR_WITH_TELEMETRY_SUPPORTED = 2018 +MAX_YEAR_SUPPORTED = datetime.today().year -MIN_SUPPORTED_ROUND = 1 # testing events all share round number = 0 -MAX_SUPPORTED_ROUND = 25 +MIN_ROUND_SUPPORTED = 1 # testing events all share round number = 0 +MAX_ROUND_SUPPORTED = 25 -MIN_SUPPORTED_SESSION = 1 -MAX_SUPPORTED_SESSION = 5 +MIN_SESSION_SUPPORTED = 1 +MAX_SESSION_SUPPORTED = 5 DEFAULT_SESSION = 5 # race + +MIN_DRIVER_NUMBER_SUPPORTED = 1 +MAX_DRIVER_NUMBER_SUPPORTED = 99 + +MIN_LAP_COUNT_SUPPORTED = 1 +MAX_LAP_COUNT_SUPPORTED = 80 diff --git a/app/main.py b/app/main.py index c9fd8b9..6e2c9bd 100644 --- a/app/main.py +++ b/app/main.py @@ -15,24 +15,39 @@ from .constants import ( DEFAULT_SESSION, EVENT_SCHEDULE_DATETIME_DTYPE_LIST, - MAX_SUPPORTED_ROUND, - MAX_SUPPORTED_SESSION, - MAX_SUPPORTED_YEAR, + MAX_DRIVER_NUMBER_SUPPORTED, + MAX_LAP_COUNT_SUPPORTED, + MAX_ROUND_SUPPORTED, + MAX_SESSION_SUPPORTED, + MAX_YEAR_SUPPORTED, METADATA_DESCRIPTION, - MIN_SUPPORTED_ROUND, - MIN_SUPPORTED_SESSION, - MIN_SUPPORTED_YEAR, + MIN_DRIVER_NUMBER_SUPPORTED, + MIN_LAP_COUNT_SUPPORTED, + MIN_ROUND_SUPPORTED, + MIN_SESSION_SUPPORTED, + MIN_YEAR_SUPPORTED, +) +from .models import ( + EventSchedule, + ExtendedTelemetry, + HealthCheck, + Laps, + Results, + Root, + Schedule, + Standings, + Telemetry, + Weather, ) -from .models import EventSchedule, HealthCheck, Laps, Results, Root, Schedule, Standings from .utils import get_default_year +# FastF1 configuration fastf1.set_log_level("WARNING") - -# Cors Middleware -origins = ["http://localhost:3000"] # Ergast configuration ergast = Ergast(result_type="raw", auto_cast=True) +# Cors Middleware +origins = ["http://localhost:3000"] # Others favicon_path = "favicon.ico" @@ -116,8 +131,8 @@ def get_schedule( Query( title="The year for which to get the schedule", description="The year for which to get the schedule", - ge=MIN_SUPPORTED_YEAR, - le=MAX_SUPPORTED_YEAR, + ge=MIN_YEAR_SUPPORTED, + le=MAX_YEAR_SUPPORTED, ), ] = None, ) -> Schedule: @@ -193,7 +208,7 @@ def get_next_event() -> EventSchedule: next_event_as_json = next_event.to_json() # Parse the JSON string to a JSON object - next_event_as_json_obj: EventSchedule = json.loads(next_event_as_json) + next_event_as_json_obj: EventSchedule = EventSchedule.model_validate_json(next_event_as_json) return next_event_as_json_obj @@ -212,8 +227,8 @@ def get_standings( Query( title="The year for which to get the driver and constructors standing. If the season hasn't ended you get the current standings.", description="The year for which to get the driver and constructors standing. If the season hasn't ended you get the current standings.", - ge=MIN_SUPPORTED_YEAR, - le=MAX_SUPPORTED_YEAR, + ge=MIN_YEAR_SUPPORTED, + le=MAX_YEAR_SUPPORTED, ), ] = None, round: Annotated[ @@ -221,8 +236,8 @@ def get_standings( Query( title="The round in a year for which to get the driver and constructor standings", description="The round in a year for which to get the driver and constructor standings", - ge=MIN_SUPPORTED_ROUND, - le=MAX_SUPPORTED_ROUND, + ge=MIN_ROUND_SUPPORTED, + le=MAX_ROUND_SUPPORTED, ), ] = None, ) -> Standings: @@ -284,7 +299,9 @@ def get_standings( raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Driver standings not found.") else: # something went wrong, investigate - raise HTTPException(status_code=500, detail="Something went wrong. Investigate!") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Something went wrong. Investigate!" + ) @app.get( @@ -301,8 +318,8 @@ def get_results( Path( title="The year for which to get the results", description="The year for which to get the results", - ge=MIN_SUPPORTED_YEAR, - le=MAX_SUPPORTED_YEAR, + ge=MIN_YEAR_SUPPORTED, + le=MAX_YEAR_SUPPORTED, ), ], round: Annotated[ @@ -310,8 +327,8 @@ def get_results( Path( title="The round in a year for which to get the results", description="The round in a year for which to get the results", - ge=MIN_SUPPORTED_ROUND, - le=MAX_SUPPORTED_ROUND, + ge=MIN_ROUND_SUPPORTED, + le=MAX_ROUND_SUPPORTED, ), ], session: Annotated[ @@ -319,8 +336,8 @@ def get_results( Query( title="The session in a round for which to get the results", description="The session in a round for which to get the results. (Default = 5; ie race)", - ge=MIN_SUPPORTED_SESSION, - le=MAX_SUPPORTED_SESSION, + ge=MIN_SESSION_SUPPORTED, + le=MAX_SESSION_SUPPORTED, ), ] = DEFAULT_SESSION, ) -> List[Results]: @@ -374,8 +391,8 @@ def get_laps( Path( title="The year for which to get the laps", description="The year for which to get the laps", - ge=MIN_SUPPORTED_YEAR, - le=MAX_SUPPORTED_YEAR, + ge=MIN_YEAR_SUPPORTED, + le=MAX_YEAR_SUPPORTED, ), ], round: Annotated[ @@ -383,8 +400,8 @@ def get_laps( Path( title="The round in a year for which to get the laps", description="The round in a year for which to get the laps", - ge=MIN_SUPPORTED_ROUND, - le=MAX_SUPPORTED_ROUND, + ge=MIN_ROUND_SUPPORTED, + le=MAX_ROUND_SUPPORTED, ), ], session: Annotated[ @@ -392,8 +409,8 @@ def get_laps( Query( title="The session in a round for which to get the laps", description="The session in a round for which to get the laps. (Default = 5; ie race)", - ge=MIN_SUPPORTED_SESSION, - le=MAX_SUPPORTED_SESSION, + ge=MIN_SESSION_SUPPORTED, + le=MAX_SESSION_SUPPORTED, ), ] = DEFAULT_SESSION, driver_number: Annotated[ @@ -416,18 +433,17 @@ def get_laps( List[Laps]: Returns a JSON response with the list of session results """ - session_obj = fastf1.get_session(year=year, gp=round, identifier=session) - session_obj.load( - laps=True, - telemetry=False, - weather=False, - messages=True, # required for `Deleted` and `DeletedReason` - ) - session_laps = session_obj.laps - try: + session_obj = fastf1.get_session(year=year, gp=round, identifier=session) + session_obj.load( + laps=True, + telemetry=False, + weather=False, + messages=True, # required for `Deleted` and `DeletedReason` + ) + session_laps = session_obj.laps + if len(driver_number) > 0: - print(driver_number) session_laps = session_laps.pick_drivers(driver_number) # Convert the dataframe to a JSON string @@ -444,3 +460,151 @@ def get_laps( status_code=status.HTTP_404_NOT_FOUND, detail=f"Likely an error when fetching laps data for a session that has yet to happen. {str(ke)}", ) + + +@app.get( + "/telemetry/{year}/{round}/{driver_number}/{lap}", + tags=["telemetry"], + summary="Get telemetry of a driver for a given year, round and session for one or multiple laps optionally with weather data", + response_description="telemetry of a driver for a given year, round and session for one or multiple laps optionally with weather data.", + status_code=status.HTTP_200_OK, + response_model=ExtendedTelemetry, +) +def get_telemetry( + year: Annotated[ + int, + Path( + title="The year for which to get the telemetry", + description="The year for which to get the telemetry", + ge=MIN_YEAR_SUPPORTED, + le=MAX_YEAR_SUPPORTED, + ), + ], + round: Annotated[ + int, + Path( + title="The round in a year for which to get the telemetry", + description="The round in a year for which to get the telemetry", + ge=MIN_ROUND_SUPPORTED, + le=MAX_ROUND_SUPPORTED, + ), + ], + driver_number: Annotated[ + int, + Path( + title="Driver number for whom to get the telemetry", + description="Driver number for whom to get the telemetry", + ge=MIN_DRIVER_NUMBER_SUPPORTED, + le=MAX_DRIVER_NUMBER_SUPPORTED, + ), + ], + lap: Annotated[ + int, + Path( + title="List of laps of the driver for which to get the telemetry", + description="List of laps of the driver for which to get the telemetry", + ge=MIN_LAP_COUNT_SUPPORTED, + le=MAX_LAP_COUNT_SUPPORTED, + ), + ], + session: Annotated[ + int, + Query( + title="The session in a round for which to get the telemetry", + description="The session in a round for which to get the telemetry. (Default = 5; ie race)", + ge=MIN_SESSION_SUPPORTED, + le=MAX_SESSION_SUPPORTED, + ), + ] = DEFAULT_SESSION, + weather: Annotated[ + bool, + Query( + title="Flag to fetch weather data along with telemetry", + description="Flag to fetch weather data along with telemetry", + ), + ] = False, +) -> ExtendedTelemetry: + """ + ## Get telemetry of a driver for a given year, round and session for one or multiple laps optionally with weather data + Endpoint to get telemetry of a driver for a given year, round and session for one or multiple laps optionally with weather data. + + **NOTE**: + - If `session` is not provided; we use the default session. Default = 5; ie race. + + **Returns**: + ExtendedTelemetry: Returns a JSON response with the list of telemetry optionally with weather data + """ + + try: + session_obj = fastf1.get_session(year=year, gp=round, identifier=session) + session_obj.load( + laps=True, + telemetry=True, + weather=weather, + messages=True, # required for `Deleted` and `DeletedReason` + ) + session_laps_for_driver = session_obj.laps.pick_drivers(driver_number) + except ValueError as ve: + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Bad Request. {str(ve)}") + except KeyError as ke: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Likely an error when fetching laps data for a session that has yet to happen. {str(ke)}", + ) + + # Error out if no laps are found for the driver + if len(session_laps_for_driver) == 0: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Laps for driver {driver_number} not found.", + ) + + # filter laps based on the `lap` path parameter + filtered_lap_for_driver = session_laps_for_driver.pick_laps(lap) + + # Error out if the requested lap is not found for the driver + if len(filtered_lap_for_driver) == 0: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Requested lap for driver {driver_number} not found.", + ) + + try: + session_telemetry = filtered_lap_for_driver.get_telemetry() + except ValueError as ve: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Telemetry not found for driver {driver_number} for the requested laps. {str(ve)}", + ) + + # keep only the required data in session_telemetry + session_telemetry = session_telemetry[ + ["Time", "RPM", "Speed", "nGear", "Throttle", "Brake", "DRS", "Distance", "X", "Y"] + ] + + # Convert the dataframe to a JSON string + session_telemetry_as_json = session_telemetry.to_json(orient="records") + + # Parse the JSON string to a JSON object + session_telemetry_as_json_obj: List[Telemetry] = json.loads(session_telemetry_as_json) + + session_weather_as_json_obj: Weather | None = None + if weather: + session_weather = filtered_lap_for_driver.get_weather_data() + + # Convert the dataframe to a JSON string + session_weather_as_json = session_weather.to_json(orient="records") + + # Parse the JSON string to a JSON object + session_weather_as_json_list_obj: List[Weather] = json.loads(session_weather_as_json) + + # Grab the first row of the weather data + # https://docs.fastf1.dev/core.html#fastf1.core.Laps.get_weather_data + session_weather_as_json_obj = session_weather_as_json_list_obj[0] + + return ExtendedTelemetry.model_validate( + { + "Telemetry": session_telemetry_as_json_obj, + "Weather": session_weather_as_json_obj, + } + ) diff --git a/app/models.py b/app/models.py index d13a5ac..e42ce95 100644 --- a/app/models.py +++ b/app/models.py @@ -6,13 +6,13 @@ class Root(BaseModel): - """Response model for root.""" + """Response model for root""" we_are: str = "SlickTelemetry" class EventSchedule(BaseModel): - """Response model for event schedule data for a Formula 1 calendar year.""" + """Response model for event schedule data for a Formula 1 calendar year""" RoundNumber: int Country: str @@ -47,7 +47,7 @@ class Schedule(BaseModel): class HealthCheck(BaseModel): - """Response model to validate and return when performing a health check.""" + """Response model to validate and return when performing a health check""" status: str = "OK" @@ -107,38 +107,38 @@ class Standings(BaseModel): class Results(BaseModel): """Response model for session results for a given year, round and session""" - DriverNumber: str - BroadcastName: str - Abbreviation: str - DriverId: str - TeamName: str - TeamColor: str - TeamId: str - FirstName: str - LastName: str - FullName: str - HeadshotUrl: str - CountryCode: str + DriverNumber: str | None + BroadcastName: str | None + Abbreviation: str | None + DriverId: str | None + TeamName: str | None + TeamColor: str | None + TeamId: str | None + FirstName: str | None + LastName: str | None + FullName: str | None + HeadshotUrl: str | None + CountryCode: str | None Position: float | None - ClassifiedPosition: str + ClassifiedPosition: str | None GridPosition: float | None Q1: int | None Q2: int | None Q3: int | None Time: int | None - Status: str + Status: str | None Points: float | None class Laps(BaseModel): """Response model for session laps for a given year, round, session and drivers""" - Time: int - Driver: str - DriverNumber: str + Time: int | None + Driver: str | None + DriverNumber: str | None LapTime: int | None - LapNumber: float - Stint: float + LapNumber: float | None + Stint: float | None PitOutTime: int | None PitInTime: int | None Sector1Time: int | None @@ -151,16 +151,51 @@ class Laps(BaseModel): SpeedI2: float | None SpeedFL: float | None SpeedST: float | None - IsPersonalBest: bool - Compound: str - TyreLife: float - FreshTyre: bool - Team: str + IsPersonalBest: bool | None + Compound: str | None + TyreLife: float | None + FreshTyre: bool | None + Team: str | None LapStartTime: int | None LapStartDate: str | None - TrackStatus: str + TrackStatus: str | None Position: float | None Deleted: bool | None - DeletedReason: str - FastF1Generated: bool - IsAccurate: bool + DeletedReason: str | None + FastF1Generated: bool | None + IsAccurate: bool | None + + +class Telemetry(BaseModel): + """Response model for session telemetry for a given year, round, session, driver and laps""" + + Time: int + RPM: int + Speed: float + nGear: int + Throttle: float + Brake: bool + DRS: int + Distance: float + X: float + Y: float + + +class Weather(BaseModel): + """Response model for session weather for a given year, round, session and laps""" + + Time: int + AirTemp: float + Humidity: float + Pressure: float + Rainfall: bool + TrackTemp: float + WindDirection: int + WindSpeed: float + + +class ExtendedTelemetry(BaseModel): + """Response model for telemetry with weather""" + + Telemetry: List[Telemetry] + Weather: Weather | None diff --git a/app/utils.py b/app/utils.py index 263e79c..ea2f6ff 100644 --- a/app/utils.py +++ b/app/utils.py @@ -6,7 +6,10 @@ def get_default_year() -> int: - # default year is defined as the year which has data for at least 1 race session + """Get the default year for the app. + + NOTE - The default year is defined as the year which has data for at least 1 race session. + """ current_year = datetime.today().year event_schedule = fastf1.get_event_schedule(current_year, include_testing=False) diff --git a/poetry.lock b/poetry.lock index a921e4a..26e7a21 100644 --- a/poetry.lock +++ b/poetry.lock @@ -304,13 +304,13 @@ files = [ [[package]] name = "commitizen" -version = "3.16.0" +version = "3.17.0" description = "Python commitizen client tool" optional = false python-versions = ">=3.8" files = [ - {file = "commitizen-3.16.0-py3-none-any.whl", hash = "sha256:a880005352fd35b908d9c3951e71e155b157f4a4ec61ca9c080a9637bf98e0a1"}, - {file = "commitizen-3.16.0.tar.gz", hash = "sha256:1269619d383d12809f436ff196fb786a3d49fc50987562e6e566cd9c2908735c"}, + {file = "commitizen-3.17.0-py3-none-any.whl", hash = "sha256:2a9942d52724dc50518ca53997bef0f3b51a7e1c518d1ea3da44f9a9ece2df3a"}, + {file = "commitizen-3.17.0.tar.gz", hash = "sha256:1949025c5485c645656929158a5e2f6f6fa96501eb4461dee88a2493f630cb9c"}, ] [package.dependencies] @@ -462,19 +462,19 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "fastf1" -version = "3.2.2" +version = "3.3.0" description = "Python package for accessing and analyzing Formula 1 results, schedules, timing data and telemetry." optional = false python-versions = ">=3.8" files = [ - {file = "fastf1-3.2.2-py3-none-any.whl", hash = "sha256:1dbafb83b66ccaaa5dce869238046b20719b307a9dccad5c692d15ad87282bdd"}, - {file = "fastf1-3.2.2.tar.gz", hash = "sha256:49f2304d155822bd01f824a36283553e128fcd536ae48c56b74e7293176d04a7"}, + {file = "fastf1-3.3.0-py3-none-any.whl", hash = "sha256:04a7fe10fbc7a27e87bedd3de8fce0e23f3f3e63790d9be6ac7d635b8832ea18"}, + {file = "fastf1-3.3.0.tar.gz", hash = "sha256:fb65e3e76b7bd84d0273eb5668afb404a6a042b80751857d2d795dbf58007b35"}, ] [package.dependencies] matplotlib = ">=3.5.1,<4.0.0" numpy = ">=1.21.5,<2.0.0" -pandas = ">=1.3.5,<3.0.0" +pandas = ">=1.4.1,<3.0.0" python-dateutil = "*" requests = ">=2.28.1" requests-cache = ">=1.0.0" @@ -1351,13 +1351,13 @@ wcwidth = "*" [[package]] name = "pydantic" -version = "2.6.2" +version = "2.6.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, - {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, + {file = "pydantic-2.6.3-py3-none-any.whl", hash = "sha256:72c6034df47f46ccdf81869fddb81aade68056003900a8724a4f160700016a2a"}, + {file = "pydantic-2.6.3.tar.gz", hash = "sha256:e07805c4c7f5c6826e33a1d4c9d47950d7eaf34868e2690f8594d2e30241f11f"}, ] [package.dependencies] @@ -1496,13 +1496,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" -version = "3.1.1" +version = "3.1.2" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, - {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, + {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"}, + {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"}, ] [package.extras] @@ -1545,13 +1545,13 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "python-dateutil" -version = "2.8.2" +version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, - {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] @@ -1657,101 +1657,101 @@ prompt_toolkit = ">=2.0,<=3.0.36" [[package]] name = "rapidfuzz" -version = "3.6.1" +version = "3.6.2" description = "rapid fuzzy string matching" optional = false python-versions = ">=3.8" files = [ - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ac434fc71edda30d45db4a92ba5e7a42c7405e1a54cb4ec01d03cc668c6dcd40"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a791168e119cfddf4b5a40470620c872812042f0621e6a293983a2d52372db0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5a2f3e9df346145c2be94e4d9eeffb82fab0cbfee85bd4a06810e834fe7c03fa"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23de71e7f05518b0bbeef55d67b5dbce3bcd3e2c81e7e533051a2e9401354eb0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d056e342989248d2bdd67f1955bb7c3b0ecfa239d8f67a8dfe6477b30872c607"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01835d02acd5d95c1071e1da1bb27fe213c84a013b899aba96380ca9962364bc"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f712e0bb5fea327e92aec8a937afd07ba8de4c529735d82e4c4124c10d5a0"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96cd19934f76a1264e8ecfed9d9f5291fde04ecb667faef5f33bdbfd95fe2d1f"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e06c4242a1354cf9d48ee01f6f4e6e19c511d50bb1e8d7d20bcadbb83a2aea90"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d73dcfe789d37c6c8b108bf1e203e027714a239e50ad55572ced3c004424ed3b"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:06e98ff000e2619e7cfe552d086815671ed09b6899408c2c1b5103658261f6f3"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:08b6fb47dd889c69fbc0b915d782aaed43e025df6979b6b7f92084ba55edd526"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a1788ebb5f5b655a15777e654ea433d198f593230277e74d51a2a1e29a986283"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win32.whl", hash = "sha256:c65f92881753aa1098c77818e2b04a95048f30edbe9c3094dc3707d67df4598b"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:4243a9c35667a349788461aae6471efde8d8800175b7db5148a6ab929628047f"}, - {file = "rapidfuzz-3.6.1-cp310-cp310-win_arm64.whl", hash = "sha256:f59d19078cc332dbdf3b7b210852ba1f5db8c0a2cd8cc4c0ed84cc00c76e6802"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fbc07e2e4ac696497c5f66ec35c21ddab3fc7a406640bffed64c26ab2f7ce6d6"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40cced1a8852652813f30fb5d4b8f9b237112a0bbaeebb0f4cc3611502556764"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:82300e5f8945d601c2daaaac139d5524d7c1fdf719aa799a9439927739917460"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf97c321fd641fea2793abce0e48fa4f91f3c202092672f8b5b4e781960b891"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7420e801b00dee4a344ae2ee10e837d603461eb180e41d063699fb7efe08faf0"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060bd7277dc794279fa95522af355034a29c90b42adcb7aa1da358fc839cdb11"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7e3375e4f2bfec77f907680328e4cd16cc64e137c84b1886d547ab340ba6928"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a490cd645ef9d8524090551016f05f052e416c8adb2d8b85d35c9baa9d0428ab"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2e03038bfa66d2d7cffa05d81c2f18fd6acbb25e7e3c068d52bb7469e07ff382"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b19795b26b979c845dba407fe79d66975d520947b74a8ab6cee1d22686f7967"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:064c1d66c40b3a0f488db1f319a6e75616b2e5fe5430a59f93a9a5e40a656d15"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3c772d04fb0ebeece3109d91f6122b1503023086a9591a0b63d6ee7326bd73d9"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:841eafba6913c4dfd53045835545ba01a41e9644e60920c65b89c8f7e60c00a9"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win32.whl", hash = "sha256:266dd630f12696ea7119f31d8b8e4959ef45ee2cbedae54417d71ae6f47b9848"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:d79aec8aeee02ab55d0ddb33cea3ecd7b69813a48e423c966a26d7aab025cdfe"}, - {file = "rapidfuzz-3.6.1-cp311-cp311-win_arm64.whl", hash = "sha256:484759b5dbc5559e76fefaa9170147d1254468f555fd9649aea3bad46162a88b"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b2ef4c0fd3256e357b70591ffb9e8ed1d439fb1f481ba03016e751a55261d7c1"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:588c4b20fa2fae79d60a4e438cf7133d6773915df3cc0a7f1351da19eb90f720"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7142ee354e9c06e29a2636b9bbcb592bb00600a88f02aa5e70e4f230347b373e"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1dfc557c0454ad22382373ec1b7df530b4bbd974335efe97a04caec936f2956a"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:03f73b381bdeccb331a12c3c60f1e41943931461cdb52987f2ecf46bfc22f50d"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b0ccc2ec1781c7e5370d96aef0573dd1f97335343e4982bdb3a44c133e27786"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da3e8c9f7e64bb17faefda085ff6862ecb3ad8b79b0f618a6cf4452028aa2222"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fde9b14302a31af7bdafbf5cfbb100201ba21519be2b9dedcf4f1048e4fbe65d"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1a23eee225dfb21c07f25c9fcf23eb055d0056b48e740fe241cbb4b22284379"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e49b9575d16c56c696bc7b06a06bf0c3d4ef01e89137b3ddd4e2ce709af9fe06"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:0a9fc714b8c290261669f22808913aad49553b686115ad0ee999d1cb3df0cd66"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:a3ee4f8f076aa92184e80308fc1a079ac356b99c39408fa422bbd00145be9854"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f056ba42fd2f32e06b2c2ba2443594873cfccc0c90c8b6327904fc2ddf6d5799"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win32.whl", hash = "sha256:5d82b9651e3d34b23e4e8e201ecd3477c2baa17b638979deeabbb585bcb8ba74"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:dad55a514868dae4543ca48c4e1fc0fac704ead038dafedf8f1fc0cc263746c1"}, - {file = "rapidfuzz-3.6.1-cp312-cp312-win_arm64.whl", hash = "sha256:3c84294f4470fcabd7830795d754d808133329e0a81d62fcc2e65886164be83b"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e19d519386e9db4a5335a4b29f25b8183a1c3f78cecb4c9c3112e7f86470e37f"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01eb03cd880a294d1bf1a583fdd00b87169b9cc9c9f52587411506658c864d73"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:be368573255f8fbb0125a78330a1a40c65e9ba3c5ad129a426ff4289099bfb41"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3e5af946f419c30f5cb98b69d40997fe8580efe78fc83c2f0f25b60d0e56efb"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f382f7ffe384ce34345e1c0b2065451267d3453cadde78946fbd99a59f0cc23c"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be156f51f3a4f369e758505ed4ae64ea88900dcb2f89d5aabb5752676d3f3d7e"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1936d134b6c513fbe934aeb668b0fee1ffd4729a3c9d8d373f3e404fbb0ce8a0"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:12ff8eaf4a9399eb2bebd838f16e2d1ded0955230283b07376d68947bbc2d33d"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae598a172e3a95df3383634589660d6b170cc1336fe7578115c584a99e0ba64d"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:cd4ba4c18b149da11e7f1b3584813159f189dc20833709de5f3df8b1342a9759"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:0402f1629e91a4b2e4aee68043a30191e5e1b7cd2aa8dacf50b1a1bcf6b7d3ab"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:1e12319c6b304cd4c32d5db00b7a1e36bdc66179c44c5707f6faa5a889a317c0"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0bbfae35ce4de4c574b386c43c78a0be176eeddfdae148cb2136f4605bebab89"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-win32.whl", hash = "sha256:7fec74c234d3097612ea80f2a80c60720eec34947066d33d34dc07a3092e8105"}, - {file = "rapidfuzz-3.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:a553cc1a80d97459d587529cc43a4c7c5ecf835f572b671107692fe9eddf3e24"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:757dfd7392ec6346bd004f8826afb3bf01d18a723c97cbe9958c733ab1a51791"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2963f4a3f763870a16ee076796be31a4a0958fbae133dbc43fc55c3968564cf5"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d2f0274595cc5b2b929c80d4e71b35041104b577e118cf789b3fe0a77b37a4c5"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f211e366e026de110a4246801d43a907cd1a10948082f47e8a4e6da76fef52"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a59472b43879012b90989603aa5a6937a869a72723b1bf2ff1a0d1edee2cc8e6"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a03863714fa6936f90caa7b4b50ea59ea32bb498cc91f74dc25485b3f8fccfe9"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dd95b6b7bfb1584f806db89e1e0c8dbb9d25a30a4683880c195cc7f197eaf0c"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7183157edf0c982c0b8592686535c8b3e107f13904b36d85219c77be5cefd0d8"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ad9d74ef7c619b5b0577e909582a1928d93e07d271af18ba43e428dc3512c2a1"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b53137d81e770c82189e07a8f32722d9e4260f13a0aec9914029206ead38cac3"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:49b9ed2472394d306d5dc967a7de48b0aab599016aa4477127b20c2ed982dbf9"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:dec307b57ec2d5054d77d03ee4f654afcd2c18aee00c48014cb70bfed79597d6"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4381023fa1ff32fd5076f5d8321249a9aa62128eb3f21d7ee6a55373e672b261"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win32.whl", hash = "sha256:8d7a072f10ee57c8413c8ab9593086d42aaff6ee65df4aa6663eecdb7c398dca"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:ebcfb5bfd0a733514352cfc94224faad8791e576a80ffe2fd40b2177bf0e7198"}, - {file = "rapidfuzz-3.6.1-cp39-cp39-win_arm64.whl", hash = "sha256:1c47d592e447738744905c18dda47ed155620204714e6df20eb1941bb1ba315e"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:eef8b346ab331bec12bbc83ac75641249e6167fab3d84d8f5ca37fd8e6c7a08c"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53251e256017e2b87f7000aee0353ba42392c442ae0bafd0f6b948593d3f68c6"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6dede83a6b903e3ebcd7e8137e7ff46907ce9316e9d7e7f917d7e7cdc570ee05"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e4da90e4c2b444d0a171d7444ea10152e07e95972bb40b834a13bdd6de1110c"}, - {file = "rapidfuzz-3.6.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:ca3dfcf74f2b6962f411c33dd95b0adf3901266e770da6281bc96bb5a8b20de9"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bcc957c0a8bde8007f1a8a413a632a1a409890f31f73fe764ef4eac55f59ca87"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:692c9a50bea7a8537442834f9bc6b7d29d8729a5b6379df17c31b6ab4df948c2"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c23ceaea27e790ddd35ef88b84cf9d721806ca366199a76fd47cfc0457a81b"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b155e67fff215c09f130555002e42f7517d0ea72cbd58050abb83cb7c880cec"}, - {file = "rapidfuzz-3.6.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3028ee8ecc48250607fa8a0adce37b56275ec3b1acaccd84aee1f68487c8557b"}, - {file = "rapidfuzz-3.6.1.tar.gz", hash = "sha256:35660bee3ce1204872574fa041c7ad7ec5175b3053a4cb6e181463fc07013de7"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a5637e6bf11b15b5aff6ee818c76bdec99ad208511b78985e6209ba648a6e3ee"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:380586664f2f63807050ddb95e7702888b4f0b425abf17655940c411f39287ad"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3168ff565d4b8c239cf11fb604dd2507d30e9bcaac76a4077c0ac23cf2c866ed"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be69f7fd46b5c6467fe5e2fd4cff3816b0c03048eed8a4becb9a73e6000960e7"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cbd5894f23fdf5697499cf759523639838ac822bd1600e343fdce7313baa02ae"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85a5b6e026393fe39fb61146b9c17c5af66fffbe1410e992c4bb06d9ec327bd3"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab269adfc64480f209e99f253391a10735edd5c09046e04899adab5fb132f20e"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35aeac852bca06023d6bbd50c1fc504ca5a9a3613d5e75a140f0be7601fa34ef"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e706f302c6a3ae0d74edd0d6ace46aee1ae07c563b436ccf5ff04db2b3571e60"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bec353f022011e6e5cd28ccb8700fbd2a33918197af0d4e0abb3c3f4845cc864"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ef3925daaa93eed20401012e219f569ff0c039ed5bf4ce2d3737b4f75d441622"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6ee98d88ae9ccc77ff61992ed33b2496478def5dc0da55c9a9aa06fcb725a352"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:423c7c588b09d618601097b7a0017dfcb91132a2076bef29023c5f3cd2dc3de1"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-win32.whl", hash = "sha256:c17c5efee347a40a6f4c1eec59e3d7d1e22f7613a97f8b8a07733ef723483a04"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:4209816626d8d6ff8ae7dc248061c6059e618b70c6e6f6e4d7444ae3740b2b85"}, + {file = "rapidfuzz-3.6.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c54d3c85e522d3ac9ee39415f183c8fa184c4f87e7e5a37938f15a6d50e853a"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e06f6d270112f5db001f1cba5a97e1a48aee3d3dbdcbea3ec027c230462dbf9b"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:080cb71b50cb6aff11d1c6aeb157f273e2da0b2bdb3f9d7b01257e49e69a8576"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a7895e04a22d6515bc91a850e0831f2405547605aa311d1ffec51e4818abc3c1"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82f9838519136b7083dd1e3149ee80344521f3dc37f744f227505ff0883efb"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a945567c2b0b6e069454c9782d5234b0b6795718adf7a9f868bd3144afa6a023"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:673ba2c343644805acdae1cb949c6a4de71aa2f62a998978551ebea59603af3f"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d457c89bac1471442002e70551e8268e639b3870b4a4521eae363c07253be87"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:495c0d8e14e6f12520eb7fc71b9ba9fcaafb47fc23a654e6e89b6c7985ec0020"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6d67b649bf3e1b1722d04eca44d37919aef88305ce7ad05564502d013cf550fd"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e48dde8ca83d11daa00900cf6a5d281a1297aef9b7bfa73801af6e8822be5019"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:824cc381cf81cbf8d158f6935664ec2a69e6ac3b1d39fa201988bf81a257f775"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:1dfe4c24957474ce0ac75d886387e30e292b4be39228a6d71f76de414dc187db"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d57b98013b802621bbc8b12a46bfc9d36ac552ab51ca207f7ce167ad46adabeb"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-win32.whl", hash = "sha256:9a07dffac439223b4f1025dbfc68f4445a3460a859309c9858c2a3fa29617cdc"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:95a49c6b8bf1229743ae585dd5b7d57f0d15a7eb6e826866d5c9965ba958503c"}, + {file = "rapidfuzz-3.6.2-cp311-cp311-win_arm64.whl", hash = "sha256:af7c19ec86e11488539380d3db1755be5d561a3c0e7b04ff9d07abd7f9a8e9d8"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:de8adc12161bf282c60f12dc9233bb31632f71d446a010fe7469a69b8153427f"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:337e357f693130c4c6be740652542b260e36f622c59e01fa33d58f1d2750c930"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6468f8bc8c3c50604f43631550ef9cfec873515dba5023ca34d461be94669fc8"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74c6773b11445b5e5cf93ca383171cd0ac0cdeafea11a7b2a5688f8bf8d813e6"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1507fc5769aa109dda4de3a15f822a0f6a03e18d627bd0ba3ddbb253cf70e07"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:617949a70150e6fffdaed19253dd49f7a53528411dc8bf7663d499ba21e0f61e"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8b77779174b1b40aa70827692571ab457061897846255ad7d5d559e2edb1932"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80e51b22a7da83f9c87a97e92df07ed0612c74c35496590255f4b5d5b4212dfe"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3ae7c86914cb6673e97e187ba431b9c4cf4177d9ae77f8a1e5b2ba9a5628839e"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ddc380ffaa90f204cc9ddcb779114b9ab6f015246d549de9d47871a97ef9f18a"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:3c1dc078ef371fce09f9f3eec2ca4eaa2a8cd412ec53941015b4f39f14d34407"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:9a74102fc5a2534fe91f7507838623e1f3a149d8e05648389c42bb42e14b1c3f"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:48e1eaea8fcd522fca7f04f0480663f0f0cfb77957092cce60a93f4462864996"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-win32.whl", hash = "sha256:66b008bf2972740cd2dda5d382eb8bdb87265cd88198e71c7797bdc0d1f79d20"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:87ac3a87f2251ae2e95fc9478ca5c759de6d141d04c84d3fec9f9cdcfc167b33"}, + {file = "rapidfuzz-3.6.2-cp312-cp312-win_arm64.whl", hash = "sha256:b593cc51aed887e93b78c2f94dfae9008be2b23d17afd3b1f1d3eb3913b58f26"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d830bc7a9b586a374147ec60b08b1f9ae5996b43f75cc514f37faef3866b519"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dbee7f5ff11872b76505cbd87c814abc823e8757f11c69062eb3b25130a283da"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28c011fb31f2c3f82f503aedd6097d3d3854e574e327a119a3b7eb2cf90b79ca"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cda81d0e0ce0c13abfa46b24e10c1e85f9c6acb628f0a9a948f5779f9c2076a2"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c279928651ce0e9e5220dcb25a00cc53b65e592a0861336a38299bcdca3a596"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35bd4bc9c40e6994c5d6edea4b9319388b4d9711c13c66d543bb4c37624b4184"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d07899506a5a8760448d9df036d528b55a554bf571714173635c79eef4a86e58"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb2e51d01b9c6d6954a3e055c57a80d4685b4fc82719db5519fc153566bcd6bb"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:153d065e353371cc0aeff32b99999a5758266a64e958d1364189367c1c9f6814"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4edcceebb85ebfa49a3ddcde20ad891d36c08dc0fd592efdab0e7d313a4e36af"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3549123fca5bb817341025f98e8e49ca99f84596c7c4f92b658f8e5836040d4a"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:84c1032ae42628465b7a5cc35249906061e18a8193c9c27cbd2db54e9823a9a6"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9bcc91ebd8fc69a6bd3b5711c8250f5f4e70606b4da75ef415f57ad209978205"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-win32.whl", hash = "sha256:f3a70f341c4c111bad910d2df69c78577a98af140319a996af24c9385939335d"}, + {file = "rapidfuzz-3.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:354ad5fe655beb7b279390cb58334903931c5452ecbad1b1666ffb06786498e2"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1b86b93d93020c2b3edc1665d75c8855784845fc0a739b312c26c3a4bf0c80d5"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:28243086ed0e50808bb56632e5442c457241646aeafafd501ac87901f40a3237"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ed52461ae5a9ea4c400d38e2649c74a413f1a6d8fb8308b66f1fbd122514732f"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a46220f86a5f9cb016af31525e0d0865cad437d02239aa0d8aed2ab8bff1f1c"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81a630ed2fc3ec5fc7400eb66bab1f87e282b4d47f0abe3e48c6634dfa13b5e4"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8e5a437b9089df6242a718d9c31ab1742989e9400a0977af012ef483b63b4c2"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16270b5529de83b7bae7457e952e4d9cf3fbf029a837dd32d415bb9e0eb8e599"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5378c04102c7f084cde30a100154fa6d7e2baf0d51a6bdd2f912545559c1fb35"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f18397c8d6a65fc0b288d2fc29bc7baeea6ba91eeb95163a3cd98f23cd3bc85"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2acd2514defce81e6ff4bbff50252d5e7df8e85a731442c4b83e44c86cf1c916"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:1df2faf80201952e252413b6fac6f3e146080dcebb87bb1bb722508e67558ed8"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6440ed0b3007c1c9286b0b88fe2ab2d9e83edd60cd62293b3dfabb732b4e8a30"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4fcfa23b5553b27f4016df77c53172ea743454cf12c28cfa7c35a309a2be93b3"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-win32.whl", hash = "sha256:2d580d937146e803c8e5e1b87916cab8d6f84013b6392713e201efcda335c7d8"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:fe2a68be734e8e88af23385c68d6467e15818b6b1df1cbfebf7bff577226c957"}, + {file = "rapidfuzz-3.6.2-cp39-cp39-win_arm64.whl", hash = "sha256:6478f7803efebf5f644d0b758439c5b25728550fdfbb19783d150004c46a75a9"}, + {file = "rapidfuzz-3.6.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:36ce7b68a7b90b787cdd73480a68d2f1ca63c31a3a9d5a79a8736f978e1e9344"}, + {file = "rapidfuzz-3.6.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53597fd72a9340bcdd80d3620f4957c2b92f9b569313b969a3abdaffd193aae6"}, + {file = "rapidfuzz-3.6.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4f6de745fe6ce46a422d353ee10599013631d7d714a36d025f164b2d4e8c000"}, + {file = "rapidfuzz-3.6.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62df2136068e2515ed8beb01756381ff62c29384d785e3bf46e3111d4ea3ba1e"}, + {file = "rapidfuzz-3.6.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7382c90170f60c846c81a07ddd80bb2e8c43c8383754486fa37f67391a571897"}, + {file = "rapidfuzz-3.6.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f31314fd2e2f3dc3e519e6f93669462ce7953df2def1c344aa8f5345976d0eb2"}, + {file = "rapidfuzz-3.6.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:012221629d54d3bee954148247f711eb86d4d390b589ebfe03172ea0b37a7531"}, + {file = "rapidfuzz-3.6.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d41dd59a70decfce6595315367a2fea2af660d92a9d144acc6479030501014d7"}, + {file = "rapidfuzz-3.6.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f9fa14136a5b0cba1ec42531f7c3e0b0d3edb7fd6bc5e5ae7b498541f3855ab"}, + {file = "rapidfuzz-3.6.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:259364199cbfeca33b1af369fc7951f71717aa285184a3fa5a7b1772da1b89db"}, + {file = "rapidfuzz-3.6.2.tar.gz", hash = "sha256:cf911e792ab0c431694c9bf2648afabfd92099103f2e31492893e078ddca5e1a"}, ] [package.extras] @@ -2309,4 +2309,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "d7f9e04a55712b57cbc832aa237e3bd09666056a6014f8c45fe4f8a3840881fc" +content-hash = "6752769cbae53d3a1cdedd9dd68fa6b8b84a45ca40925f19da28763fbf15f46d" diff --git a/pyproject.toml b/pyproject.toml index 3e72583..94769b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,15 +16,15 @@ readme = "README.md" [tool.poetry.dependencies] python = "^3.12" fastapi = "^0.110.0" -fastf1 = "3.2.2" +fastf1 = "3.3.0" uvicorn = { extras = ["standard"], version = "^0.27.1" } -# Development (common) +# Development (common) dependencies [tool.poetry.group.dev.dependencies] commitizen = "*" pre-commit = "*" -# Formatting +# Formatting dependencies [tool.poetry.group.lint] optional = true @@ -52,7 +52,7 @@ formatters = ["autoflake", "isort", "black"] git-hooks-setup = "pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-commit" git-hooks-upate = "pre-commit autoupdate" pylint = "pylint run.py app" -tests = "pytest -rpP" +tests = "pytest -rpPfE tests" typings = "mypy run.py app" #-->> Configuration <<------------------------------------- diff --git a/tests/test_laps.py b/tests/test_laps.py index fa97fe9..55417b6 100644 --- a/tests/test_laps.py +++ b/tests/test_laps.py @@ -9,7 +9,7 @@ client = TestClient(app) -# region laps - good inputs +# region good inputs def test_get_laps(): @@ -164,9 +164,9 @@ def test_get_laps_with_session_and_driver_numbers(): } -# endregion laps - good inputs +# endregion good inputs -# region laps - bad inputs +# region bad inputs def test_get_laps_mixed_driver_numbers(): @@ -217,4 +217,4 @@ def test_get_laps_bad_driver_numbers(): assert response.json() == [] -# endregion laps - bad inputs +# endregion bad inputs diff --git a/tests/test_next_event.py b/tests/test_next_event.py index d56e48f..d525ecc 100644 --- a/tests/test_next_event.py +++ b/tests/test_next_event.py @@ -13,27 +13,27 @@ def test_get_next_event(): response = client.get("/next-event") assert response.status_code == status.HTTP_200_OK assert response.json() == { - "RoundNumber": 1, - "Country": "Bahrain", - "Location": "Sakhir", - "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2024", - "EventDate": "2024-03-02 00:00:00", - "EventName": "Bahrain Grand Prix", + "RoundNumber": 2, + "Country": "Saudi Arabia", + "Location": "Jeddah", + "OfficialEventName": "FORMULA 1 STC SAUDI ARABIAN GRAND PRIX 2024", + "EventDate": "2024-03-09 00:00:00", + "EventName": "Saudi Arabian Grand Prix", "EventFormat": "conventional", "Session1": "Practice 1", - "Session1Date": "2024-02-29 14:30:00+03:00", - "Session1DateUtc": "2024-02-29 11:30:00", + "Session1Date": "2024-03-07 16:30:00+03:00", + "Session1DateUtc": "2024-03-07 13:30:00", "Session2": "Practice 2", - "Session2Date": "2024-02-29 18:00:00+03:00", - "Session2DateUtc": "2024-02-29 15:00:00", + "Session2Date": "2024-03-07 20:00:00+03:00", + "Session2DateUtc": "2024-03-07 17:00:00", "Session3": "Practice 3", - "Session3Date": "2024-03-01 15:30:00+03:00", - "Session3DateUtc": "2024-03-01 12:30:00", + "Session3Date": "2024-03-08 16:30:00+03:00", + "Session3DateUtc": "2024-03-08 13:30:00", "Session4": "Qualifying", - "Session4Date": "2024-03-01 19:00:00+03:00", - "Session4DateUtc": "2024-03-01 16:00:00", + "Session4Date": "2024-03-08 20:00:00+03:00", + "Session4DateUtc": "2024-03-08 17:00:00", "Session5": "Race", - "Session5Date": "2024-03-02 18:00:00+03:00", - "Session5DateUtc": "2024-03-02 15:00:00", + "Session5Date": "2024-03-09 20:00:00+03:00", + "Session5DateUtc": "2024-03-09 17:00:00", "F1ApiSupport": True, } diff --git a/tests/test_results.py b/tests/test_results.py index ad990a1..013c8c1 100644 --- a/tests/test_results.py +++ b/tests/test_results.py @@ -9,7 +9,7 @@ client = TestClient(app) -# region results - good inputs +# region good inputs def test_get_results(): @@ -68,9 +68,9 @@ def test_get_results_with_session(): } -# endregion results - good inputs +# endregion good inputs -# region results - bad inputs +# region bad inputs def test_get_results_bad_round_invalid(): @@ -79,4 +79,4 @@ def test_get_results_bad_round_invalid(): assert response.json() == {"detail": "Bad Request. Invalid round: 25"} -# endregion results - bad inputs +# endregion bad inputs diff --git a/tests/test_schedule.py b/tests/test_schedule.py index 298d907..aa4f35a 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -12,30 +12,30 @@ def test_get_schedule(): response = client.get("/schedule") assert response.status_code == status.HTTP_200_OK - assert response.json()["year"] == 2023 + assert response.json()["year"] == 2024 assert response.json()["EventSchedule"][0] == { "RoundNumber": 1, "Country": "Bahrain", "Location": "Sakhir", - "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2023", - "EventDate": "2023-03-05", + "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2024", + "EventDate": "2024-03-02", "EventName": "Bahrain Grand Prix", "EventFormat": "conventional", "Session1": "Practice 1", - "Session1Date": "2023-03-03 14:30:00+03:00", - "Session1DateUtc": "2023-03-03 11:30:00", + "Session1Date": "2024-02-29 14:30:00+03:00", + "Session1DateUtc": "2024-02-29 11:30:00", "Session2": "Practice 2", - "Session2Date": "2023-03-03 18:00:00+03:00", - "Session2DateUtc": "2023-03-03 15:00:00", + "Session2Date": "2024-02-29 18:00:00+03:00", + "Session2DateUtc": "2024-02-29 15:00:00", "Session3": "Practice 3", - "Session3Date": "2023-03-04 14:30:00+03:00", - "Session3DateUtc": "2023-03-04 11:30:00", + "Session3Date": "2024-03-01 15:30:00+03:00", + "Session3DateUtc": "2024-03-01 12:30:00", "Session4": "Qualifying", - "Session4Date": "2023-03-04 18:00:00+03:00", - "Session4DateUtc": "2023-03-04 15:00:00", + "Session4Date": "2024-03-01 19:00:00+03:00", + "Session4DateUtc": "2024-03-01 16:00:00", "Session5": "Race", - "Session5Date": "2023-03-05 18:00:00+03:00", - "Session5DateUtc": "2023-03-05 15:00:00", + "Session5Date": "2024-03-02 18:00:00+03:00", + "Session5DateUtc": "2024-03-02 15:00:00", "F1ApiSupport": True, } diff --git a/tests/test_standings.py b/tests/test_standings.py index 937791f..3363385 100644 --- a/tests/test_standings.py +++ b/tests/test_standings.py @@ -9,19 +9,19 @@ client = TestClient(app) -# region standings - good inputs +# region good inputs def test_get_standings(): response = client.get("/standings") assert response.status_code == status.HTTP_200_OK - assert response.json()["season"] == 2023 - assert response.json()["round"] == 22 + assert response.json()["season"] == 2024 + assert response.json()["round"] == 1 assert response.json()["DriverStandings"][0] == { "position": "1", "positionText": "1", - "points": "575", - "wins": "19", + "points": "26", + "wins": "1", "Driver": { "driverId": "max_verstappen", "permanentNumber": "33", @@ -44,8 +44,8 @@ def test_get_standings(): assert response.json()["ConstructorStandings"][0] == { "position": "1", "positionText": "1", - "points": "860", - "wins": "21", + "points": "44", + "wins": "1", "Constructor": { "constructorId": "red_bull", "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", @@ -141,9 +141,9 @@ def test_get_standings_good_year_and_round(): } -# endregion standings - good inputs +# endregion good inputs -# region standings - no inputs +# region no inputs def test_get_standings_good_round_bad_year_no_input(): @@ -152,4 +152,4 @@ def test_get_standings_good_round_bad_year_no_input(): assert response.json() == {"detail": 'Bad request. Must provide the "year" parameter.'} -# endregion standings - no inputs +# endregion no inputs diff --git a/tests/test_telemetry.py b/tests/test_telemetry.py new file mode 100644 index 0000000..f684fc1 --- /dev/null +++ b/tests/test_telemetry.py @@ -0,0 +1,83 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +# region good inputs + + +def test_get_telemetry(): + response = client.get("/telemetry/2023/4/1/1?session=5&weather=false") + assert response.status_code == status.HTTP_200_OK + assert response.json()["Telemetry"][0] == { + "Time": 0, + "RPM": 10115, + "Speed": 0.0, + "nGear": 1, + "Throttle": 16.0, + "Brake": False, + "DRS": 1, + "Distance": 0.0019578773, + "X": 1811.0527567522, + "Y": -279.9800289003, + } + assert response.json()["Weather"] == None + + +def test_get_telemetry_with_weather(): + response = client.get("/telemetry/2023/4/1/1?session=5&weather=true") + assert response.status_code == status.HTTP_200_OK + assert response.json()["Telemetry"][0] == { + "Time": 0, + "RPM": 10115, + "Speed": 0.0, + "nGear": 1, + "Throttle": 16.0, + "Brake": False, + "DRS": 1, + "Distance": 0.0019578773, + "X": 1811.0527567522, + "Y": -279.9800289003, + } + assert response.json()["Weather"] == { + "Time": 3790336, + "AirTemp": 24.9, + "Humidity": 49.0, + "Pressure": 1008.7, + "Rainfall": False, + "TrackTemp": 43.4, + "WindDirection": 50, + "WindSpeed": 0.8, + } + + +# endregion good inputs + +# region bad inputs + + +def test_get_telemetry_bad_round(): + response = client.get("/telemetry/2023/25/1/1?session=5&weather=false") + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json() == {"detail": "Bad Request. Invalid round: 25"} + + +def test_get_telemetry_bad_driver_number(): + response = client.get("/telemetry/2023/4/3/1?session=5&weather=false") + assert response.status_code == status.HTTP_404_NOT_FOUND + assert response.json() == {"detail": "Laps for driver 3 not found."} + + +def test_get_telemetry_bad_lap(): + response = client.get("/telemetry/2023/4/1/80?session=5&weather=false") + assert response.status_code == status.HTTP_404_NOT_FOUND + assert response.json() == {"detail": "Requested lap for driver 1 not found."} + + +# endregion bad inputs diff --git a/useful_commands.md b/useful_commands.md index 03f3ae8..2d6c199 100644 --- a/useful_commands.md +++ b/useful_commands.md @@ -71,7 +71,6 @@ docker ps ```sh docker build --file Dockerfile.dev --tag backend-dev . -docker build --file Dockerfile.staging --tag backend-staging . docker build --file Dockerfile.prod --tag backend-prod . ``` @@ -79,7 +78,6 @@ docker build --file Dockerfile.prod --tag backend-prod . ```sh docker run --name backend-dev --publish 8081:8081 backend-dev --detach -docker run --name backend-staging --publish 80:80 backend-staging --detach docker run --name backend-prod --publish 80:80 backend-prod --detach ``` @@ -87,7 +85,6 @@ docker run --name backend-prod --publish 80:80 backend-prod --detach ```sh docker stop backend-dev -docker stop backend-staging docker stop backend-prod ``` @@ -95,7 +92,6 @@ docker stop backend-prod ```sh docker restart backend-dev -docker restart backend-staging docker restart backend-prod ```