diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35ba54b..98cb4ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,14 +20,11 @@ jobs: - name: Checkout repo uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - - name: Install poetry, isort, black - run: pipx install poetry isort black + - name: Install poetry + run: pipx install poetry - - name: View poetry, isort, black versions - run: | - poetry --version - isort --version-number - black --version + - name: View poetry + run: poetry --version - name: 🐍 Set up Python uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c @@ -35,16 +32,23 @@ jobs: python-version: 3.12 cache: "poetry" + - name: Add Poe the Poet plugin + run: poetry self add 'poethepoet[poetry_plugin]' + - name: Install dependencies - run: poetry install --no-root + run: poetry install --no-root --with dev,lint,test - - name: Python Lint (isort/black) - run: | - isort --check-only --quiet . - black --check . + - name: Python Format (autoflake/isort/black) + run: poetry poe formatters + + - name: Python Lint (pylint) + run: poetry poe pylint + + - name: Python Typecheck (mypy) + run: poetry poe typings - name: Run tests - run: poetry run pytest -rpP + run: poetry poe tests build: name: 🐳 Build and publish docker images diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1e3b1d8..dab9db5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,18 +1,35 @@ +# Pre-commit hooks repos: + # Execute external scripts - repo: https://github.com/commitizen-tools/commitizen rev: v3.13.0 hooks: - id: commitizen stages: [commit-msg] - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.1.0 + # Execute local scripts + - repo: local hooks: - - id: black - language_version: python3.12 + - id: run-formatter + name: Run formatter + entry: poetry poe formatters + language: system + pass_filenames: false stages: [pre-commit, pre-push] - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - language_version: python3.12 + - id: run-linter + name: Run linter + entry: poetry poe pylint + language: system + pass_filenames: false + stages: [pre-commit, pre-push] + - id: run-typings + name: Run typings + entry: poetry poe typings + language: system + pass_filenames: false stages: [pre-commit, pre-push] + - id: run-tests + name: Run tests + entry: poetry poe tests + language: system + pass_filenames: false + stages: [pre-push] diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..f2a5a9e --- /dev/null +++ b/.pylintrc @@ -0,0 +1,10 @@ +[MASTER] +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-whitelist= + +[MESSAGES CONTROL] +# https://pylint.readthedocs.io/en/latest/user_guide/checkers/features.html +disable=all,E0401,E0611,E1101,E1102,E1123 +enable=F,E diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..8531a3b --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12.2 diff --git a/.vscode/extensions.json b/.vscode/extensions.json index a8d7ca9..bc4e127 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -10,6 +10,7 @@ "christian-kohler.path-intellisense", "esbenp.prettier-vscode", "ms-python.vscode-pylance", + "ms-python.pylint", "ms-python.python", "Gruntfuggly.todo-tree" ] diff --git a/.vscode/settings.json b/.vscode/settings.json index 82758f8..e0a6210 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,5 +6,10 @@ } }, "editor.formatOnSave": true, - "isort.args": ["--profile", "black"] + "black-formatter.args": ["--line-length", "120", "--target-version", "py312"], + "isort.args": ["--settings-file", "${workspaceFolder}/pyproject.toml"], + "pylint.args": ["--rcfile", "${workspaceFolder}/.pylintrc"], + "python.testing.pytestArgs": ["tests"], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true } diff --git a/Dockerfile.dev b/Dockerfile.dev index 9fc62ce..8350c62 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM python:3.12.1-slim +FROM python:3.12.2-slim # Set the working directory to /code. WORKDIR /code @@ -16,7 +16,7 @@ RUN pip install --no-cache-dir poetry # Use Poetry to install dependencies RUN poetry config virtualenvs.create false \ - && poetry install --no-interaction --no-ansi --no-root + && poetry install --no-interaction --no-ansi --no-root --with dev,lint,test # Make port 8081 available to the world outside this container EXPOSE 8081 @@ -26,6 +26,6 @@ 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", "8081", "--reload", "--reload-exclude", "app/test_main.py"] +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8081", "--reload", "--reload-exclude", "tests/*.py"] -# CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "8081" "--reload", "--reload-exclude", "app/test_main.py"] +# CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "8081" "--reload", "--reload-exclude", "tests/*.py"] diff --git a/Dockerfile.prod b/Dockerfile.prod index 00f23c8..05ccd47 100644 --- a/Dockerfile.prod +++ b/Dockerfile.prod @@ -1,7 +1,7 @@ # https://fastapi.tiangolo.com/deployment/docker/#docker-image-with-poetry # First stage -FROM python:3.12.1-slim as requirements-stage +FROM python:3.12.2-slim as requirements-stage # Set /tmp as the current working directory. WORKDIR /tmp @@ -16,7 +16,7 @@ COPY ./pyproject.toml ./poetry.lock* /tmp/ 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.1-slim +FROM python:3.12.2-slim # Install gcc and other dependencies RUN apt-get update && apt-get install -y \ diff --git a/Dockerfile.staging b/Dockerfile.staging index 00f23c8..05ccd47 100644 --- a/Dockerfile.staging +++ b/Dockerfile.staging @@ -1,7 +1,7 @@ # https://fastapi.tiangolo.com/deployment/docker/#docker-image-with-poetry # First stage -FROM python:3.12.1-slim as requirements-stage +FROM python:3.12.2-slim as requirements-stage # Set /tmp as the current working directory. WORKDIR /tmp @@ -16,7 +16,7 @@ COPY ./pyproject.toml ./poetry.lock* /tmp/ 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.1-slim +FROM python:3.12.2-slim # Install gcc and other dependencies RUN apt-get update && apt-get install -y \ diff --git a/README.md b/README.md index 9cbd45b..74eddac 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,14 @@ Table of Contents: - [Python virtual environment](#python-virtual-environment) - [Installing dependencies](#installing-dependencies) - [Virtual environment sanity check](#virtual-environment-sanity-check) + - [Poe the Poet poetry plugin](#poe-the-poet-poetry-plugin) - [Installing git hooks](#installing-git-hooks) - - [Running the project](#running-the-project) + - [Running the project](#running-the-project) + - [Running tests](#running-tests) - [Docker](#docker) - [App only](#app-only) - [With Supabase](#with-supabase) - [Interactive API docs](#interactive-api-docs) - - [Running tests](#running-tests) - [Contribution Guidelines](#contribution-guidelines) - [Deployment](#deployment) @@ -38,13 +39,14 @@ Table of Contents: In `/docker`, create a copy of `.env.example` as `.env`. + ### Python virtual environment #### Installing dependencies ```sh poetry config virtualenvs.in-project true # OPTIONAL -poetry install --sync --no-root +poetry install --sync --no-root --with dev,lint,test ``` **Note**: Ensure that the python interpreter in your IDE is set to the newly created virtual environment by poetry. If you have not modified poetry configuration, you can find the virtual environment location as stated [here](https://python-poetry.org/docs/configuration/#cache-directory). @@ -58,19 +60,43 @@ poetry install --sync --no-root - Run `poetry shell` ***OR*** - Execute the `/Scripts/Activate` script from the virtual environment located [here](https://python-poetry.org/docs/configuration/#cache-directory). -#### Installing git hooks -Run this command in the python environment. +#### Poe the Poet poetry plugin + +```sh +poetry self add 'poethepoet[poetry_plugin]' +``` + +1. Check available tasks: + ```sh + poetry poe + ``` +2. Execute a task: + ```sh + poetry poe + ``` + For example, running the project formatters: + ```sh + poetry poe formatters + ``` + +#### Installing git hooks ```sh -pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-commit +poetry poe git-hooks-setup ``` -#### Running the project +### Running the project - Open up a terminal in your IDE. - Run `python run.py` to start the server. -- Open your browser at `http://localhost:8081`. +- Open your browser at [`http://localhost:8081`](http://localhost:8081). + +### Running tests + +```sh +poetry poe tests +``` ### Docker @@ -84,7 +110,7 @@ pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-c ```sh docker run --name backend-dev --publish 8081:8081 backend-dev --detach ``` -- Open your browser at `http://localhost/8081`. +- Open your browser at [`http://localhost:8081`](http://localhost:8081). #### With Supabase @@ -94,8 +120,8 @@ pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-c docker compose --file compose.dev.yaml up --detach ``` - Open your browser at - - `http://localhost/8081` for app - - `http://localhost/8000` for supabase dashboard + - [`http://localhost:8081`](http://localhost:8081) for app + - [`http://localhost:8000`](http://localhost:8000) for supabase dashboard - Username: `supabase` - Password: `this_password_is_insecure_and_should_be_updated` @@ -103,14 +129,8 @@ For other docker commands, see [useful_commands.md](./useful_commands.md) ### Interactive API docs -- Once the server is running, open your browser at `http://localhost/docs`. -- Alternate docs can be found at `http://localhost/redoc`, provided by [redoc](https://github.com/Redocly/redoc). - -### Running tests - -```sh -poetry run pytest -rpP -``` +- Once the server is running, open your browser at [`http://localhost/docs`](http://localhost/docs). +- Alternate docs can be found at [`http://localhost/redoc`](http://localhost/redoc), provided by [redoc](https://github.com/Redocly/redoc). ### Contribution Guidelines diff --git a/app/constants.py b/app/constants.py index 78fa4e4..edd1573 100644 --- a/app/constants.py +++ b/app/constants.py @@ -1,5 +1,7 @@ +# Built-in from datetime import datetime + METADATA_DESCRIPTION = """ Slick Telemetry backend written in python with fastf1. 🏎 @@ -31,4 +33,4 @@ MIN_SUPPORTED_SESSION = 1 MAX_SUPPORTED_SESSION = 5 -DEFAULT_SESSION_FOR_RESULTS = 5 # race +DEFAULT_SESSION = 5 # race diff --git a/app/main.py b/app/main.py index 01f5333..c9fd8b9 100644 --- a/app/main.py +++ b/app/main.py @@ -1,18 +1,19 @@ +# Built-in import json -import logging from datetime import datetime -from typing import Annotated +from typing import Annotated, List +# External import fastf1 from fastapi import FastAPI, HTTPException, Path, Query, status from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import FileResponse -from fastapi_utils.timing import add_timing_middleware from fastf1.ergast import Ergast from pandas import Timestamp +# App from .constants import ( - DEFAULT_SESSION_FOR_RESULTS, + DEFAULT_SESSION, EVENT_SCHEDULE_DATETIME_DTYPE_LIST, MAX_SUPPORTED_ROUND, MAX_SUPPORTED_SESSION, @@ -22,21 +23,19 @@ MIN_SUPPORTED_SESSION, MIN_SUPPORTED_YEAR, ) -from .models import EventSchedule, HealthCheck, Results, Schedule, Standings +from .models import EventSchedule, HealthCheck, Laps, Results, Root, Schedule, Standings from .utils import get_default_year -# fastf1.set_log_level("WARNING") # TODO use for production and staging + +fastf1.set_log_level("WARNING") # Cors Middleware origins = ["http://localhost:3000"] # Ergast configuration ergast = Ergast(result_type="raw", auto_cast=True) +# Others favicon_path = "favicon.ico" -# Logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - app = FastAPI( title="Slick Telemetry API", description=METADATA_DESCRIPTION, @@ -61,7 +60,6 @@ allow_headers=["*"], # HTTPSRedirectMiddleware # TODO use for production and staging ) -add_timing_middleware(app, record=logger.info, prefix="app") @app.get("/favicon.ico", include_in_schema=False) @@ -75,6 +73,7 @@ async def favicon(): summary="Read root", response_description="Return root info", status_code=status.HTTP_200_OK, + response_model=Root, ) def read_root(): return {"we_are": "SlickTelemetry"} @@ -106,8 +105,8 @@ def get_health() -> HealthCheck: @app.get( "/schedule", tags=["schedule"], - summary="Get events schedule for a Formula 1 calendar year", - response_description="Return list of events schedule for a Formula 1 calendar year", + summary="Get events schedule for a given year", + response_description="Return list of events schedule for a given year", status_code=status.HTTP_200_OK, response_model=Schedule, ) @@ -120,16 +119,16 @@ def get_schedule( ge=MIN_SUPPORTED_YEAR, le=MAX_SUPPORTED_YEAR, ), - ] = None + ] = None, ) -> Schedule: """ - ## Get events schedule for a Formula 1 calendar year - Endpoint to get events schedule for Formula 1 calendar year. + ## Get events schedule for a given year + Endpoint to get events schedule for a given year. **NOTE**: If `year` is not provided; we use the default year. Default year is defined as the year which has data for at least 1 race session. **Returns**: - list[Schedule]: Returns a JSON response with the list of event schedule + Schedule: Returns a JSON response with the list of event schedule """ if year is None: @@ -146,11 +145,13 @@ def get_schedule( event_schedule_as_json = event_schedule.to_json(orient="records") # Parse the JSON string to a JSON object - event_schedule_as_json_obj: list[EventSchedule] = json.loads(event_schedule_as_json) - schedule_as_json_obj: Schedule = { - "year": year, - "EventSchedule": event_schedule_as_json_obj, - } + event_schedule_as_json_obj: List[EventSchedule] = json.loads(event_schedule_as_json) + schedule_as_json_obj: Schedule = Schedule.model_validate( + { + "year": year, + "EventSchedule": event_schedule_as_json_obj, + } + ) return schedule_as_json_obj @@ -172,16 +173,12 @@ def get_next_event() -> EventSchedule: EventSchedule: Returns upcoming event """ - remaining_events = fastf1.get_events_remaining( - dt=datetime.now(), include_testing=False - ) + remaining_events = fastf1.get_events_remaining(dt=datetime.now(), include_testing=False) if len(remaining_events) == 0: # EITHER current season has ended OR new season's schedule has not yet been released - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, detail="Next event not found." - ) + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Next event not found.") else: # Current season EITHER has not yet started OR is in progress @@ -192,7 +189,7 @@ def get_next_event() -> EventSchedule: lambda x: str(x) if isinstance(x, Timestamp) else x, ) - # Convert the dataframe to a JSON string + # Convert the series to a JSON string next_event_as_json = next_event.to_json() # Parse the JSON string to a JSON object @@ -204,8 +201,8 @@ def get_next_event() -> EventSchedule: @app.get( "/standings", tags=["standings"], - summary="Get drivers and constructors standings", - response_description="Return a list of drivers and constructors standings at specific points of a season. If the season hasn't ended you will get the current standings.", + summary="Get drivers and constructors standing for a given year and round", + response_description="Return a list of drivers and constructors standings at specific points of a season for a given year and round. If the season hasn't ended you get the current standings.", status_code=status.HTTP_200_OK, response_model=Standings, ) @@ -213,8 +210,8 @@ def get_standings( year: Annotated[ int | None, Query( - title="The year for which to get the driver and constructors standing. If the season hasn't ended you will get the current standings.", - description="The year for which to get the driver and constructors standing. If the season hasn't ended you will get the current standings.", + 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, ), @@ -230,8 +227,8 @@ def get_standings( ] = None, ) -> Standings: """ - ## Get driver and constructor standings - Endpoint to get driver and constructor standings at specific points of a season. If the season hasn't ended you will get the current standings. + ## Get driver and constructor standings for a given year and round + Endpoint to get driver and constructor standings at specific points of a season for a given year and round. If the season hasn't ended you get the current standings. **NOTE**: If `year` is not provided; we use the default year. Default year is defined as the year which has data for at least 1 race session. @@ -261,12 +258,14 @@ def get_standings( if driver_standings_available and constructor_standings_available: # both driver and constructor standings are available - data: Standings = { - "season": driver_standings[0]["season"], - "round": driver_standings[0]["round"], - "DriverStandings": driver_standings[0]["DriverStandings"], - "ConstructorStandings": constructor_standings[0]["ConstructorStandings"], - } + data: Standings = Standings.model_validate( + { + "season": driver_standings[0]["season"], + "round": driver_standings[0]["round"], + "DriverStandings": driver_standings[0]["DriverStandings"], + "ConstructorStandings": constructor_standings[0]["ConstructorStandings"], + } + ) return data elif not driver_standings_available and not constructor_standings_available: # neither driver nor constructor standings are available @@ -282,14 +281,10 @@ def get_standings( ) elif constructor_standings_available: # only constructor standings are available - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, detail="Driver standings not found." - ) + 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=500, detail="Something went wrong. Investigate!") @app.get( @@ -298,7 +293,7 @@ def get_standings( summary="Get session results for a given year, round and session", response_description="Return session results for a given year, round and session.", status_code=status.HTTP_200_OK, - response_model=list[Results], + response_model=List[Results], ) def get_results( year: Annotated[ @@ -323,20 +318,20 @@ def get_results( int, 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. (5 = race)", + description="The session in a round for which to get the results. (Default = 5; ie race)", ge=MIN_SUPPORTED_SESSION, le=MAX_SUPPORTED_SESSION, ), - ] = DEFAULT_SESSION_FOR_RESULTS, -) -> list[Results]: + ] = DEFAULT_SESSION, +) -> List[Results]: """ ## Get session results for a given year, round and session Endpoint to get session results for a given year, round and session. - **NOTE**: If `session` is not provided; we use the default session. Default session is the race session (5). + **NOTE**: If `session` is not provided; we use the default session. Default = 5; ie race. **Returns**: - list[Results]: Returns a JSON response with the list of session results + List[Results]: Returns a JSON response with the list of session results """ try: @@ -353,15 +348,99 @@ def get_results( session_results_as_json = session_results.to_json(orient="records") # Parse the JSON string to a JSON object - session_results_as_json_obj = json.loads(session_results_as_json) + session_results_as_json_obj: List[Results] = json.loads(session_results_as_json) return session_results_as_json_obj 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_400_BAD_REQUEST, detail=f"Bad Request. {str(ve)}" + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Likely an error when fetching results data for a session that has yet to happen. {str(ke)}", ) + + +@app.get( + "/laps/{year}/{round}", + tags=["laps"], + summary="Get laps of one or more drivers for a given year, round and session", + response_description="Return laps of one or more drivers for a given year, round and session.", + status_code=status.HTTP_200_OK, + response_model=List[Laps], +) +def get_laps( + year: Annotated[ + int, + 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, + ), + ], + round: Annotated[ + int, + 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, + ), + ], + session: Annotated[ + int, + 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, + ), + ] = DEFAULT_SESSION, + driver_number: Annotated[ + List[int], + Query( + title="List of drivers for whom to get the laps", + description="List of drivers for whom to get the laps", + ), + ] = [], +) -> List[Laps]: + """ + ## Get laps of one or more drivers for a given year, round and session + Endpoint to get laps of one or more drivers for a given year, round and session. + + **NOTE**: + - If `session` is not provided; we use the default session. Default = 5; ie race. + - If no `driver_numbers` are provided; you get laps for all drivers. + + **Returns**: + 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: + if len(driver_number) > 0: + print(driver_number) + session_laps = session_laps.pick_drivers(driver_number) + + # Convert the dataframe to a JSON string + session_laps_as_json = session_laps.to_json(orient="records") + + # Parse the JSON string to a JSON object + session_laps_as_json_obj: List[Laps] = json.loads(session_laps_as_json) + + return session_laps_as_json_obj + 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 results data for a session that has yet to happen. {str(ke)}", + detail=f"Likely an error when fetching laps data for a session that has yet to happen. {str(ke)}", ) diff --git a/app/models.py b/app/models.py index cf89834..d13a5ac 100644 --- a/app/models.py +++ b/app/models.py @@ -1,8 +1,12 @@ +# Built-in +from typing import List + +# External from pydantic import BaseModel -class ReadRoot(BaseModel): - """Response model to validate and return when performing a health check.""" +class Root(BaseModel): + """Response model for root.""" we_are: str = "SlickTelemetry" @@ -39,7 +43,7 @@ class Schedule(BaseModel): """Response model for event schedule data with year""" year: int - EventSchedule: list[EventSchedule] + EventSchedule: List[EventSchedule] class HealthCheck(BaseModel): @@ -78,7 +82,7 @@ class DriverStandings(BaseModel): points: str wins: str Driver: Driver - Constructors: list[Constructor] + Constructors: List[Constructor] class ConstructorStandings(BaseModel): @@ -96,8 +100,8 @@ class Standings(BaseModel): season: int round: int - DriverStandings: list[DriverStandings] - ConstructorStandings: list[ConstructorStandings] + DriverStandings: List[DriverStandings] + ConstructorStandings: List[ConstructorStandings] class Results(BaseModel): @@ -124,3 +128,39 @@ class Results(BaseModel): Time: int | None Status: str 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 + LapTime: int | None + LapNumber: float + Stint: float + PitOutTime: int | None + PitInTime: int | None + Sector1Time: int | None + Sector2Time: int | None + Sector3Time: int | None + Sector1SessionTime: int | None + Sector2SessionTime: int | None + Sector3SessionTime: int | None + SpeedI1: float | None + SpeedI2: float | None + SpeedFL: float | None + SpeedST: float | None + IsPersonalBest: bool + Compound: str + TyreLife: float + FreshTyre: bool + Team: str + LapStartTime: int | None + LapStartDate: str | None + TrackStatus: str + Position: float | None + Deleted: bool | None + DeletedReason: str + FastF1Generated: bool + IsAccurate: bool diff --git a/app/test_main.py b/app/test_main.py deleted file mode 100644 index fc6db69..0000000 --- a/app/test_main.py +++ /dev/null @@ -1,4081 +0,0 @@ -from datetime import datetime - -from fastapi import status -from fastapi.testclient import TestClient - -from .constants import ( - MAX_SUPPORTED_ROUND, - MAX_SUPPORTED_YEAR, - MIN_SUPPORTED_ROUND, - MIN_SUPPORTED_YEAR, -) -from .main import app - -client = TestClient(app) - - -# region root - - -def test_read_root(): - response = client.get("/") - assert response.status_code == status.HTTP_200_OK - assert response.json() == {"we_are": "SlickTelemetry"} - - -# endregion root - - -# region healthcheck - - -def test_healthcheck(): - response = client.get("/health") - assert response.status_code == status.HTTP_200_OK - assert response.json() == {"status": "OK"} - - -# endregion healtcheck - - -# region schedule - -# region schedule - good inputs - - -def test_get_schedule(): - response = client.get("/schedule") - assert response.status_code == status.HTTP_200_OK - assert response.json() == { - "year": 2023, - "EventSchedule": [ - { - "RoundNumber": 1, - "Country": "Bahrain", - "Location": "Sakhir", - "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2023", - "EventDate": "2023-03-05", - "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", - "Session2": "Practice 2", - "Session2Date": "2023-03-03 18:00:00+03:00", - "Session2DateUtc": "2023-03-03 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-03-04 14:30:00+03:00", - "Session3DateUtc": "2023-03-04 11:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-03-04 18:00:00+03:00", - "Session4DateUtc": "2023-03-04 15:00:00", - "Session5": "Race", - "Session5Date": "2023-03-05 18:00:00+03:00", - "Session5DateUtc": "2023-03-05 15:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 2, - "Country": "Saudi Arabia", - "Location": "Jeddah", - "OfficialEventName": "FORMULA 1 STC SAUDI ARABIAN GRAND PRIX 2023", - "EventDate": "2023-03-19", - "EventName": "Saudi Arabian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-03-17 16:30:00+03:00", - "Session1DateUtc": "2023-03-17 13:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-03-17 20:00:00+03:00", - "Session2DateUtc": "2023-03-17 17:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-03-18 16:30:00+03:00", - "Session3DateUtc": "2023-03-18 13:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-03-18 20:00:00+03:00", - "Session4DateUtc": "2023-03-18 17:00:00", - "Session5": "Race", - "Session5Date": "2023-03-19 20:00:00+03:00", - "Session5DateUtc": "2023-03-19 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 3, - "Country": "Australia", - "Location": "Melbourne", - "OfficialEventName": "FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX 2023", - "EventDate": "2023-04-02", - "EventName": "Australian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-03-31 12:30:00+10:00", - "Session1DateUtc": "2023-03-31 02:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-03-31 16:00:00+10:00", - "Session2DateUtc": "2023-03-31 06:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-04-01 12:30:00+10:00", - "Session3DateUtc": "2023-04-01 02:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-04-01 16:00:00+10:00", - "Session4DateUtc": "2023-04-01 06:00:00", - "Session5": "Race", - "Session5Date": "2023-04-02 15:00:00+10:00", - "Session5DateUtc": "2023-04-02 05:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 4, - "Country": "Azerbaijan", - "Location": "Baku", - "OfficialEventName": "FORMULA 1 AZERBAIJAN GRAND PRIX 2023", - "EventDate": "2023-04-30", - "EventName": "Azerbaijan Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-04-28 13:30:00+04:00", - "Session1DateUtc": "2023-04-28 09:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-04-28 17:00:00+04:00", - "Session2DateUtc": "2023-04-28 13:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-04-29 12:30:00+04:00", - "Session3DateUtc": "2023-04-29 08:30:00", - "Session4": "Sprint", - "Session4Date": "2023-04-29 17:30:00+04:00", - "Session4DateUtc": "2023-04-29 13:30:00", - "Session5": "Race", - "Session5Date": "2023-04-30 15:00:00+04:00", - "Session5DateUtc": "2023-04-30 11:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 5, - "Country": "United States", - "Location": "Miami", - "OfficialEventName": "FORMULA 1 CRYPTO.COM MIAMI GRAND PRIX 2023", - "EventDate": "2023-05-07", - "EventName": "Miami Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-05-05 14:00:00-04:00", - "Session1DateUtc": "2023-05-05 18:00:00", - "Session2": "Practice 2", - "Session2Date": "2023-05-05 17:30:00-04:00", - "Session2DateUtc": "2023-05-05 21:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-05-06 12:30:00-04:00", - "Session3DateUtc": "2023-05-06 16:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-05-06 16:00:00-04:00", - "Session4DateUtc": "2023-05-06 20:00:00", - "Session5": "Race", - "Session5Date": "2023-05-07 15:30:00-04:00", - "Session5DateUtc": "2023-05-07 19:30:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 6, - "Country": "Monaco", - "Location": "Monaco", - "OfficialEventName": "FORMULA 1 GRAND PRIX DE MONACO 2023", - "EventDate": "2023-05-28", - "EventName": "Monaco Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-05-26 13:30:00+02:00", - "Session1DateUtc": "2023-05-26 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-05-26 17:00:00+02:00", - "Session2DateUtc": "2023-05-26 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-05-27 12:30:00+02:00", - "Session3DateUtc": "2023-05-27 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-05-27 16:00:00+02:00", - "Session4DateUtc": "2023-05-27 14:00:00", - "Session5": "Race", - "Session5Date": "2023-05-28 15:00:00+02:00", - "Session5DateUtc": "2023-05-28 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 7, - "Country": "Spain", - "Location": "Barcelona", - "OfficialEventName": "FORMULA 1 AWS GRAN PREMIO DE ESPAÑA 2023", - "EventDate": "2023-06-04", - "EventName": "Spanish Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-06-02 13:30:00+02:00", - "Session1DateUtc": "2023-06-02 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-06-02 17:00:00+02:00", - "Session2DateUtc": "2023-06-02 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-06-03 12:30:00+02:00", - "Session3DateUtc": "2023-06-03 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-06-03 16:00:00+02:00", - "Session4DateUtc": "2023-06-03 14:00:00", - "Session5": "Race", - "Session5Date": "2023-06-04 15:00:00+02:00", - "Session5DateUtc": "2023-06-04 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 8, - "Country": "Canada", - "Location": "Montréal", - "OfficialEventName": "FORMULA 1 PIRELLI GRAND PRIX DU CANADA 2023", - "EventDate": "2023-06-18", - "EventName": "Canadian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-06-16 13:30:00-04:00", - "Session1DateUtc": "2023-06-16 17:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-06-16 16:30:00-04:00", - "Session2DateUtc": "2023-06-16 20:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-06-17 12:30:00-04:00", - "Session3DateUtc": "2023-06-17 16:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-06-17 16:00:00-04:00", - "Session4DateUtc": "2023-06-17 20:00:00", - "Session5": "Race", - "Session5Date": "2023-06-18 14:00:00-04:00", - "Session5DateUtc": "2023-06-18 18:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 9, - "Country": "Austria", - "Location": "Spielberg", - "OfficialEventName": "FORMULA 1 ROLEX GROSSER PREIS VON ÖSTERREICH 2023", - "EventDate": "2023-07-02", - "EventName": "Austrian Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-06-30 13:30:00+02:00", - "Session1DateUtc": "2023-06-30 11:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-06-30 17:00:00+02:00", - "Session2DateUtc": "2023-06-30 15:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-07-01 12:00:00+02:00", - "Session3DateUtc": "2023-07-01 10:00:00", - "Session4": "Sprint", - "Session4Date": "2023-07-01 16:30:00+02:00", - "Session4DateUtc": "2023-07-01 14:30:00", - "Session5": "Race", - "Session5Date": "2023-07-02 15:00:00+02:00", - "Session5DateUtc": "2023-07-02 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 10, - "Country": "Great Britain", - "Location": "Silverstone", - "OfficialEventName": "FORMULA 1 ARAMCO BRITISH GRAND PRIX 2023", - "EventDate": "2023-07-09", - "EventName": "British Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-07-07 12:30:00+01:00", - "Session1DateUtc": "2023-07-07 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-07-07 16:00:00+01:00", - "Session2DateUtc": "2023-07-07 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-07-08 11:30:00+01:00", - "Session3DateUtc": "2023-07-08 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-07-08 15:00:00+01:00", - "Session4DateUtc": "2023-07-08 14:00:00", - "Session5": "Race", - "Session5Date": "2023-07-09 15:00:00+01:00", - "Session5DateUtc": "2023-07-09 14:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 11, - "Country": "Hungary", - "Location": "Budapest", - "OfficialEventName": "FORMULA 1 QATAR AIRWAYS HUNGARIAN GRAND PRIX 2023", - "EventDate": "2023-07-23", - "EventName": "Hungarian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-07-21 13:30:00+02:00", - "Session1DateUtc": "2023-07-21 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-07-21 17:00:00+02:00", - "Session2DateUtc": "2023-07-21 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-07-22 12:30:00+02:00", - "Session3DateUtc": "2023-07-22 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-07-22 16:00:00+02:00", - "Session4DateUtc": "2023-07-22 14:00:00", - "Session5": "Race", - "Session5Date": "2023-07-23 15:00:00+02:00", - "Session5DateUtc": "2023-07-23 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 12, - "Country": "Belgium", - "Location": "Spa-Francorchamps", - "OfficialEventName": "FORMULA 1 MSC CRUISES BELGIAN GRAND PRIX 2023", - "EventDate": "2023-07-30", - "EventName": "Belgian Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-07-28 13:30:00+02:00", - "Session1DateUtc": "2023-07-28 11:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-07-28 17:00:00+02:00", - "Session2DateUtc": "2023-07-28 15:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-07-29 12:00:00+02:00", - "Session3DateUtc": "2023-07-29 10:00:00", - "Session4": "Sprint", - "Session4Date": "2023-07-29 17:05:00+02:00", - "Session4DateUtc": "2023-07-29 15:05:00", - "Session5": "Race", - "Session5Date": "2023-07-30 15:00:00+02:00", - "Session5DateUtc": "2023-07-30 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 13, - "Country": "Netherlands", - "Location": "Zandvoort", - "OfficialEventName": "FORMULA 1 HEINEKEN DUTCH GRAND PRIX 2023", - "EventDate": "2023-08-27", - "EventName": "Dutch Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-08-25 12:30:00+02:00", - "Session1DateUtc": "2023-08-25 10:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-08-25 16:00:00+02:00", - "Session2DateUtc": "2023-08-25 14:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-08-26 11:30:00+02:00", - "Session3DateUtc": "2023-08-26 09:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-08-26 15:00:00+02:00", - "Session4DateUtc": "2023-08-26 13:00:00", - "Session5": "Race", - "Session5Date": "2023-08-27 15:00:00+02:00", - "Session5DateUtc": "2023-08-27 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 14, - "Country": "Italy", - "Location": "Monza", - "OfficialEventName": "FORMULA 1 PIRELLI GRAN PREMIO D’ITALIA 2023 ", - "EventDate": "2023-09-03", - "EventName": "Italian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-01 13:30:00+02:00", - "Session1DateUtc": "2023-09-01 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-01 17:00:00+02:00", - "Session2DateUtc": "2023-09-01 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-02 12:30:00+02:00", - "Session3DateUtc": "2023-09-02 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-02 16:00:00+02:00", - "Session4DateUtc": "2023-09-02 14:00:00", - "Session5": "Race", - "Session5Date": "2023-09-03 15:00:00+02:00", - "Session5DateUtc": "2023-09-03 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 15, - "Country": "Singapore", - "Location": "Marina Bay", - "OfficialEventName": "FORMULA 1 SINGAPORE AIRLINES SINGAPORE GRAND PRIX 2023 ", - "EventDate": "2023-09-17", - "EventName": "Singapore Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-15 17:30:00+08:00", - "Session1DateUtc": "2023-09-15 09:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-15 21:00:00+08:00", - "Session2DateUtc": "2023-09-15 13:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-16 17:30:00+08:00", - "Session3DateUtc": "2023-09-16 09:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-16 21:00:00+08:00", - "Session4DateUtc": "2023-09-16 13:00:00", - "Session5": "Race", - "Session5Date": "2023-09-17 20:00:00+08:00", - "Session5DateUtc": "2023-09-17 12:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 16, - "Country": "Japan", - "Location": "Suzuka", - "OfficialEventName": "FORMULA 1 LENOVO JAPANESE GRAND PRIX 2023 ", - "EventDate": "2023-09-24", - "EventName": "Japanese Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-22 11:30:00+09:00", - "Session1DateUtc": "2023-09-22 02:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-22 15:00:00+09:00", - "Session2DateUtc": "2023-09-22 06:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-23 11:30:00+09:00", - "Session3DateUtc": "2023-09-23 02:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-23 15:00:00+09:00", - "Session4DateUtc": "2023-09-23 06:00:00", - "Session5": "Race", - "Session5Date": "2023-09-24 14:00:00+09:00", - "Session5DateUtc": "2023-09-24 05:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 17, - "Country": "Qatar", - "Location": "Lusail", - "OfficialEventName": "FORMULA 1 QATAR AIRWAYS QATAR GRAND PRIX 2023", - "EventDate": "2023-10-08", - "EventName": "Qatar Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-10-06 16:30:00+03:00", - "Session1DateUtc": "2023-10-06 13:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-10-06 20:00:00+03:00", - "Session2DateUtc": "2023-10-06 17:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-10-07 16:20:00+03:00", - "Session3DateUtc": "2023-10-07 13:20:00", - "Session4": "Sprint", - "Session4Date": "2023-10-07 20:30:00+03:00", - "Session4DateUtc": "2023-10-07 17:30:00", - "Session5": "Race", - "Session5Date": "2023-10-08 20:00:00+03:00", - "Session5DateUtc": "2023-10-08 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 18, - "Country": "United States", - "Location": "Austin", - "OfficialEventName": "FORMULA 1 LENOVO UNITED STATES GRAND PRIX 2023", - "EventDate": "2023-10-22", - "EventName": "United States Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-10-20 12:30:00-05:00", - "Session1DateUtc": "2023-10-20 17:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-10-20 16:00:00-05:00", - "Session2DateUtc": "2023-10-20 21:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-10-21 12:30:00-05:00", - "Session3DateUtc": "2023-10-21 17:30:00", - "Session4": "Sprint", - "Session4Date": "2023-10-21 17:00:00-05:00", - "Session4DateUtc": "2023-10-21 22:00:00", - "Session5": "Race", - "Session5Date": "2023-10-22 14:00:00-05:00", - "Session5DateUtc": "2023-10-22 19:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 19, - "Country": "Mexico", - "Location": "Mexico City", - "OfficialEventName": "FORMULA 1 GRAN PREMIO DE LA CIUDAD DE MÉXICO 2023", - "EventDate": "2023-10-29", - "EventName": "Mexico City Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-10-27 12:30:00-06:00", - "Session1DateUtc": "2023-10-27 18:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-10-27 16:00:00-06:00", - "Session2DateUtc": "2023-10-27 22:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-10-28 11:30:00-06:00", - "Session3DateUtc": "2023-10-28 17:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-10-28 15:00:00-06:00", - "Session4DateUtc": "2023-10-28 21:00:00", - "Session5": "Race", - "Session5Date": "2023-10-29 14:00:00-06:00", - "Session5DateUtc": "2023-10-29 20:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 20, - "Country": "Brazil", - "Location": "São Paulo", - "OfficialEventName": "FORMULA 1 ROLEX GRANDE PRÊMIO DE SÃO PAULO 2023", - "EventDate": "2023-11-05", - "EventName": "São Paulo Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-11-03 11:30:00-03:00", - "Session1DateUtc": "2023-11-03 14:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-11-03 15:00:00-03:00", - "Session2DateUtc": "2023-11-03 18:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-11-04 11:00:00-03:00", - "Session3DateUtc": "2023-11-04 14:00:00", - "Session4": "Sprint", - "Session4Date": "2023-11-04 15:30:00-03:00", - "Session4DateUtc": "2023-11-04 18:30:00", - "Session5": "Race", - "Session5Date": "2023-11-05 14:00:00-03:00", - "Session5DateUtc": "2023-11-05 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 21, - "Country": "United States", - "Location": "Las Vegas", - "OfficialEventName": "FORMULA 1 HEINEKEN SILVER LAS VEGAS GRAND PRIX 2023", - "EventDate": "2023-11-18", - "EventName": "Las Vegas Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-11-16 20:30:00-08:00", - "Session1DateUtc": "2023-11-17 04:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-11-17 02:30:00-08:00", - "Session2DateUtc": "2023-11-17 10:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-11-17 20:30:00-08:00", - "Session3DateUtc": "2023-11-18 04:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-11-18 00:00:00-08:00", - "Session4DateUtc": "2023-11-18 08:00:00", - "Session5": "Race", - "Session5Date": "2023-11-18 22:00:00-08:00", - "Session5DateUtc": "2023-11-19 06:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 22, - "Country": "Abu Dhabi", - "Location": "Yas Island", - "OfficialEventName": "FORMULA 1 ETIHAD AIRWAYS ABU DHABI GRAND PRIX 2023 ", - "EventDate": "2023-11-26", - "EventName": "Abu Dhabi Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-11-24 13:30:00+04:00", - "Session1DateUtc": "2023-11-24 09:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-11-24 17:00:00+04:00", - "Session2DateUtc": "2023-11-24 13:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-11-25 14:30:00+04:00", - "Session3DateUtc": "2023-11-25 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-11-25 18:00:00+04:00", - "Session4DateUtc": "2023-11-25 14:00:00", - "Session5": "Race", - "Session5Date": "2023-11-26 17:00:00+04:00", - "Session5DateUtc": "2023-11-26 13:00:00", - "F1ApiSupport": True, - }, - ], - } - - -def test_get_schedule_good_year(): - response = client.get("/schedule?year=2023") - assert response.status_code == status.HTTP_200_OK - assert response.json() == { - "year": 2023, - "EventSchedule": [ - { - "RoundNumber": 1, - "Country": "Bahrain", - "Location": "Sakhir", - "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2023", - "EventDate": "2023-03-05", - "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", - "Session2": "Practice 2", - "Session2Date": "2023-03-03 18:00:00+03:00", - "Session2DateUtc": "2023-03-03 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-03-04 14:30:00+03:00", - "Session3DateUtc": "2023-03-04 11:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-03-04 18:00:00+03:00", - "Session4DateUtc": "2023-03-04 15:00:00", - "Session5": "Race", - "Session5Date": "2023-03-05 18:00:00+03:00", - "Session5DateUtc": "2023-03-05 15:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 2, - "Country": "Saudi Arabia", - "Location": "Jeddah", - "OfficialEventName": "FORMULA 1 STC SAUDI ARABIAN GRAND PRIX 2023", - "EventDate": "2023-03-19", - "EventName": "Saudi Arabian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-03-17 16:30:00+03:00", - "Session1DateUtc": "2023-03-17 13:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-03-17 20:00:00+03:00", - "Session2DateUtc": "2023-03-17 17:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-03-18 16:30:00+03:00", - "Session3DateUtc": "2023-03-18 13:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-03-18 20:00:00+03:00", - "Session4DateUtc": "2023-03-18 17:00:00", - "Session5": "Race", - "Session5Date": "2023-03-19 20:00:00+03:00", - "Session5DateUtc": "2023-03-19 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 3, - "Country": "Australia", - "Location": "Melbourne", - "OfficialEventName": "FORMULA 1 ROLEX AUSTRALIAN GRAND PRIX 2023", - "EventDate": "2023-04-02", - "EventName": "Australian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-03-31 12:30:00+10:00", - "Session1DateUtc": "2023-03-31 02:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-03-31 16:00:00+10:00", - "Session2DateUtc": "2023-03-31 06:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-04-01 12:30:00+10:00", - "Session3DateUtc": "2023-04-01 02:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-04-01 16:00:00+10:00", - "Session4DateUtc": "2023-04-01 06:00:00", - "Session5": "Race", - "Session5Date": "2023-04-02 15:00:00+10:00", - "Session5DateUtc": "2023-04-02 05:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 4, - "Country": "Azerbaijan", - "Location": "Baku", - "OfficialEventName": "FORMULA 1 AZERBAIJAN GRAND PRIX 2023", - "EventDate": "2023-04-30", - "EventName": "Azerbaijan Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-04-28 13:30:00+04:00", - "Session1DateUtc": "2023-04-28 09:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-04-28 17:00:00+04:00", - "Session2DateUtc": "2023-04-28 13:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-04-29 12:30:00+04:00", - "Session3DateUtc": "2023-04-29 08:30:00", - "Session4": "Sprint", - "Session4Date": "2023-04-29 17:30:00+04:00", - "Session4DateUtc": "2023-04-29 13:30:00", - "Session5": "Race", - "Session5Date": "2023-04-30 15:00:00+04:00", - "Session5DateUtc": "2023-04-30 11:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 5, - "Country": "United States", - "Location": "Miami", - "OfficialEventName": "FORMULA 1 CRYPTO.COM MIAMI GRAND PRIX 2023", - "EventDate": "2023-05-07", - "EventName": "Miami Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-05-05 14:00:00-04:00", - "Session1DateUtc": "2023-05-05 18:00:00", - "Session2": "Practice 2", - "Session2Date": "2023-05-05 17:30:00-04:00", - "Session2DateUtc": "2023-05-05 21:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-05-06 12:30:00-04:00", - "Session3DateUtc": "2023-05-06 16:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-05-06 16:00:00-04:00", - "Session4DateUtc": "2023-05-06 20:00:00", - "Session5": "Race", - "Session5Date": "2023-05-07 15:30:00-04:00", - "Session5DateUtc": "2023-05-07 19:30:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 6, - "Country": "Monaco", - "Location": "Monaco", - "OfficialEventName": "FORMULA 1 GRAND PRIX DE MONACO 2023", - "EventDate": "2023-05-28", - "EventName": "Monaco Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-05-26 13:30:00+02:00", - "Session1DateUtc": "2023-05-26 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-05-26 17:00:00+02:00", - "Session2DateUtc": "2023-05-26 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-05-27 12:30:00+02:00", - "Session3DateUtc": "2023-05-27 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-05-27 16:00:00+02:00", - "Session4DateUtc": "2023-05-27 14:00:00", - "Session5": "Race", - "Session5Date": "2023-05-28 15:00:00+02:00", - "Session5DateUtc": "2023-05-28 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 7, - "Country": "Spain", - "Location": "Barcelona", - "OfficialEventName": "FORMULA 1 AWS GRAN PREMIO DE ESPAÑA 2023", - "EventDate": "2023-06-04", - "EventName": "Spanish Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-06-02 13:30:00+02:00", - "Session1DateUtc": "2023-06-02 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-06-02 17:00:00+02:00", - "Session2DateUtc": "2023-06-02 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-06-03 12:30:00+02:00", - "Session3DateUtc": "2023-06-03 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-06-03 16:00:00+02:00", - "Session4DateUtc": "2023-06-03 14:00:00", - "Session5": "Race", - "Session5Date": "2023-06-04 15:00:00+02:00", - "Session5DateUtc": "2023-06-04 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 8, - "Country": "Canada", - "Location": "Montréal", - "OfficialEventName": "FORMULA 1 PIRELLI GRAND PRIX DU CANADA 2023", - "EventDate": "2023-06-18", - "EventName": "Canadian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-06-16 13:30:00-04:00", - "Session1DateUtc": "2023-06-16 17:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-06-16 16:30:00-04:00", - "Session2DateUtc": "2023-06-16 20:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-06-17 12:30:00-04:00", - "Session3DateUtc": "2023-06-17 16:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-06-17 16:00:00-04:00", - "Session4DateUtc": "2023-06-17 20:00:00", - "Session5": "Race", - "Session5Date": "2023-06-18 14:00:00-04:00", - "Session5DateUtc": "2023-06-18 18:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 9, - "Country": "Austria", - "Location": "Spielberg", - "OfficialEventName": "FORMULA 1 ROLEX GROSSER PREIS VON ÖSTERREICH 2023", - "EventDate": "2023-07-02", - "EventName": "Austrian Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-06-30 13:30:00+02:00", - "Session1DateUtc": "2023-06-30 11:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-06-30 17:00:00+02:00", - "Session2DateUtc": "2023-06-30 15:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-07-01 12:00:00+02:00", - "Session3DateUtc": "2023-07-01 10:00:00", - "Session4": "Sprint", - "Session4Date": "2023-07-01 16:30:00+02:00", - "Session4DateUtc": "2023-07-01 14:30:00", - "Session5": "Race", - "Session5Date": "2023-07-02 15:00:00+02:00", - "Session5DateUtc": "2023-07-02 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 10, - "Country": "Great Britain", - "Location": "Silverstone", - "OfficialEventName": "FORMULA 1 ARAMCO BRITISH GRAND PRIX 2023", - "EventDate": "2023-07-09", - "EventName": "British Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-07-07 12:30:00+01:00", - "Session1DateUtc": "2023-07-07 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-07-07 16:00:00+01:00", - "Session2DateUtc": "2023-07-07 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-07-08 11:30:00+01:00", - "Session3DateUtc": "2023-07-08 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-07-08 15:00:00+01:00", - "Session4DateUtc": "2023-07-08 14:00:00", - "Session5": "Race", - "Session5Date": "2023-07-09 15:00:00+01:00", - "Session5DateUtc": "2023-07-09 14:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 11, - "Country": "Hungary", - "Location": "Budapest", - "OfficialEventName": "FORMULA 1 QATAR AIRWAYS HUNGARIAN GRAND PRIX 2023", - "EventDate": "2023-07-23", - "EventName": "Hungarian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-07-21 13:30:00+02:00", - "Session1DateUtc": "2023-07-21 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-07-21 17:00:00+02:00", - "Session2DateUtc": "2023-07-21 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-07-22 12:30:00+02:00", - "Session3DateUtc": "2023-07-22 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-07-22 16:00:00+02:00", - "Session4DateUtc": "2023-07-22 14:00:00", - "Session5": "Race", - "Session5Date": "2023-07-23 15:00:00+02:00", - "Session5DateUtc": "2023-07-23 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 12, - "Country": "Belgium", - "Location": "Spa-Francorchamps", - "OfficialEventName": "FORMULA 1 MSC CRUISES BELGIAN GRAND PRIX 2023", - "EventDate": "2023-07-30", - "EventName": "Belgian Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-07-28 13:30:00+02:00", - "Session1DateUtc": "2023-07-28 11:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-07-28 17:00:00+02:00", - "Session2DateUtc": "2023-07-28 15:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-07-29 12:00:00+02:00", - "Session3DateUtc": "2023-07-29 10:00:00", - "Session4": "Sprint", - "Session4Date": "2023-07-29 17:05:00+02:00", - "Session4DateUtc": "2023-07-29 15:05:00", - "Session5": "Race", - "Session5Date": "2023-07-30 15:00:00+02:00", - "Session5DateUtc": "2023-07-30 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 13, - "Country": "Netherlands", - "Location": "Zandvoort", - "OfficialEventName": "FORMULA 1 HEINEKEN DUTCH GRAND PRIX 2023", - "EventDate": "2023-08-27", - "EventName": "Dutch Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-08-25 12:30:00+02:00", - "Session1DateUtc": "2023-08-25 10:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-08-25 16:00:00+02:00", - "Session2DateUtc": "2023-08-25 14:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-08-26 11:30:00+02:00", - "Session3DateUtc": "2023-08-26 09:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-08-26 15:00:00+02:00", - "Session4DateUtc": "2023-08-26 13:00:00", - "Session5": "Race", - "Session5Date": "2023-08-27 15:00:00+02:00", - "Session5DateUtc": "2023-08-27 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 14, - "Country": "Italy", - "Location": "Monza", - "OfficialEventName": "FORMULA 1 PIRELLI GRAN PREMIO D’ITALIA 2023 ", - "EventDate": "2023-09-03", - "EventName": "Italian Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-01 13:30:00+02:00", - "Session1DateUtc": "2023-09-01 11:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-01 17:00:00+02:00", - "Session2DateUtc": "2023-09-01 15:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-02 12:30:00+02:00", - "Session3DateUtc": "2023-09-02 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-02 16:00:00+02:00", - "Session4DateUtc": "2023-09-02 14:00:00", - "Session5": "Race", - "Session5Date": "2023-09-03 15:00:00+02:00", - "Session5DateUtc": "2023-09-03 13:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 15, - "Country": "Singapore", - "Location": "Marina Bay", - "OfficialEventName": "FORMULA 1 SINGAPORE AIRLINES SINGAPORE GRAND PRIX 2023 ", - "EventDate": "2023-09-17", - "EventName": "Singapore Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-15 17:30:00+08:00", - "Session1DateUtc": "2023-09-15 09:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-15 21:00:00+08:00", - "Session2DateUtc": "2023-09-15 13:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-16 17:30:00+08:00", - "Session3DateUtc": "2023-09-16 09:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-16 21:00:00+08:00", - "Session4DateUtc": "2023-09-16 13:00:00", - "Session5": "Race", - "Session5Date": "2023-09-17 20:00:00+08:00", - "Session5DateUtc": "2023-09-17 12:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 16, - "Country": "Japan", - "Location": "Suzuka", - "OfficialEventName": "FORMULA 1 LENOVO JAPANESE GRAND PRIX 2023 ", - "EventDate": "2023-09-24", - "EventName": "Japanese Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-09-22 11:30:00+09:00", - "Session1DateUtc": "2023-09-22 02:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-09-22 15:00:00+09:00", - "Session2DateUtc": "2023-09-22 06:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-09-23 11:30:00+09:00", - "Session3DateUtc": "2023-09-23 02:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-09-23 15:00:00+09:00", - "Session4DateUtc": "2023-09-23 06:00:00", - "Session5": "Race", - "Session5Date": "2023-09-24 14:00:00+09:00", - "Session5DateUtc": "2023-09-24 05:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 17, - "Country": "Qatar", - "Location": "Lusail", - "OfficialEventName": "FORMULA 1 QATAR AIRWAYS QATAR GRAND PRIX 2023", - "EventDate": "2023-10-08", - "EventName": "Qatar Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-10-06 16:30:00+03:00", - "Session1DateUtc": "2023-10-06 13:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-10-06 20:00:00+03:00", - "Session2DateUtc": "2023-10-06 17:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-10-07 16:20:00+03:00", - "Session3DateUtc": "2023-10-07 13:20:00", - "Session4": "Sprint", - "Session4Date": "2023-10-07 20:30:00+03:00", - "Session4DateUtc": "2023-10-07 17:30:00", - "Session5": "Race", - "Session5Date": "2023-10-08 20:00:00+03:00", - "Session5DateUtc": "2023-10-08 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 18, - "Country": "United States", - "Location": "Austin", - "OfficialEventName": "FORMULA 1 LENOVO UNITED STATES GRAND PRIX 2023", - "EventDate": "2023-10-22", - "EventName": "United States Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-10-20 12:30:00-05:00", - "Session1DateUtc": "2023-10-20 17:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-10-20 16:00:00-05:00", - "Session2DateUtc": "2023-10-20 21:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-10-21 12:30:00-05:00", - "Session3DateUtc": "2023-10-21 17:30:00", - "Session4": "Sprint", - "Session4Date": "2023-10-21 17:00:00-05:00", - "Session4DateUtc": "2023-10-21 22:00:00", - "Session5": "Race", - "Session5Date": "2023-10-22 14:00:00-05:00", - "Session5DateUtc": "2023-10-22 19:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 19, - "Country": "Mexico", - "Location": "Mexico City", - "OfficialEventName": "FORMULA 1 GRAN PREMIO DE LA CIUDAD DE MÉXICO 2023", - "EventDate": "2023-10-29", - "EventName": "Mexico City Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-10-27 12:30:00-06:00", - "Session1DateUtc": "2023-10-27 18:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-10-27 16:00:00-06:00", - "Session2DateUtc": "2023-10-27 22:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-10-28 11:30:00-06:00", - "Session3DateUtc": "2023-10-28 17:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-10-28 15:00:00-06:00", - "Session4DateUtc": "2023-10-28 21:00:00", - "Session5": "Race", - "Session5Date": "2023-10-29 14:00:00-06:00", - "Session5DateUtc": "2023-10-29 20:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 20, - "Country": "Brazil", - "Location": "São Paulo", - "OfficialEventName": "FORMULA 1 ROLEX GRANDE PRÊMIO DE SÃO PAULO 2023", - "EventDate": "2023-11-05", - "EventName": "São Paulo Grand Prix", - "EventFormat": "sprint_shootout", - "Session1": "Practice 1", - "Session1Date": "2023-11-03 11:30:00-03:00", - "Session1DateUtc": "2023-11-03 14:30:00", - "Session2": "Qualifying", - "Session2Date": "2023-11-03 15:00:00-03:00", - "Session2DateUtc": "2023-11-03 18:00:00", - "Session3": "Sprint Shootout", - "Session3Date": "2023-11-04 11:00:00-03:00", - "Session3DateUtc": "2023-11-04 14:00:00", - "Session4": "Sprint", - "Session4Date": "2023-11-04 15:30:00-03:00", - "Session4DateUtc": "2023-11-04 18:30:00", - "Session5": "Race", - "Session5Date": "2023-11-05 14:00:00-03:00", - "Session5DateUtc": "2023-11-05 17:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 21, - "Country": "United States", - "Location": "Las Vegas", - "OfficialEventName": "FORMULA 1 HEINEKEN SILVER LAS VEGAS GRAND PRIX 2023", - "EventDate": "2023-11-18", - "EventName": "Las Vegas Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-11-16 20:30:00-08:00", - "Session1DateUtc": "2023-11-17 04:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-11-17 02:30:00-08:00", - "Session2DateUtc": "2023-11-17 10:30:00", - "Session3": "Practice 3", - "Session3Date": "2023-11-17 20:30:00-08:00", - "Session3DateUtc": "2023-11-18 04:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-11-18 00:00:00-08:00", - "Session4DateUtc": "2023-11-18 08:00:00", - "Session5": "Race", - "Session5Date": "2023-11-18 22:00:00-08:00", - "Session5DateUtc": "2023-11-19 06:00:00", - "F1ApiSupport": True, - }, - { - "RoundNumber": 22, - "Country": "Abu Dhabi", - "Location": "Yas Island", - "OfficialEventName": "FORMULA 1 ETIHAD AIRWAYS ABU DHABI GRAND PRIX 2023 ", - "EventDate": "2023-11-26", - "EventName": "Abu Dhabi Grand Prix", - "EventFormat": "conventional", - "Session1": "Practice 1", - "Session1Date": "2023-11-24 13:30:00+04:00", - "Session1DateUtc": "2023-11-24 09:30:00", - "Session2": "Practice 2", - "Session2Date": "2023-11-24 17:00:00+04:00", - "Session2DateUtc": "2023-11-24 13:00:00", - "Session3": "Practice 3", - "Session3Date": "2023-11-25 14:30:00+04:00", - "Session3DateUtc": "2023-11-25 10:30:00", - "Session4": "Qualifying", - "Session4Date": "2023-11-25 18:00:00+04:00", - "Session4DateUtc": "2023-11-25 14:00:00", - "Session5": "Race", - "Session5Date": "2023-11-26 17:00:00+04:00", - "Session5DateUtc": "2023-11-26 13:00:00", - "F1ApiSupport": True, - }, - ], - } - - -# endregion schedule - good inputs - -# endregion schedule - - -# region standings - -# region standings - good inputs - - -def test_get_standings(): - response = client.get("/standings") - assert response.status_code == status.HTTP_200_OK - assert response.json() == { - "season": 2023, - "round": 22, - "DriverStandings": [ - { - "position": "1", - "positionText": "1", - "points": "575", - "wins": "19", - "Driver": { - "driverId": "max_verstappen", - "permanentNumber": "33", - "code": "VER", - "url": "http://en.wikipedia.org/wiki/Max_Verstappen", - "givenName": "Max", - "familyName": "Verstappen", - "dateOfBirth": "1997-09-30", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "2", - "positionText": "2", - "points": "285", - "wins": "2", - "Driver": { - "driverId": "perez", - "permanentNumber": "11", - "code": "PER", - "url": "http://en.wikipedia.org/wiki/Sergio_P%C3%A9rez", - "givenName": "Sergio", - "familyName": "Pérez", - "dateOfBirth": "1990-01-26", - "nationality": "Mexican", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "3", - "positionText": "3", - "points": "234", - "wins": "0", - "Driver": { - "driverId": "hamilton", - "permanentNumber": "44", - "code": "HAM", - "url": "http://en.wikipedia.org/wiki/Lewis_Hamilton", - "givenName": "Lewis", - "familyName": "Hamilton", - "dateOfBirth": "1985-01-07", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "4", - "positionText": "4", - "points": "206", - "wins": "0", - "Driver": { - "driverId": "alonso", - "permanentNumber": "14", - "code": "ALO", - "url": "http://en.wikipedia.org/wiki/Fernando_Alonso", - "givenName": "Fernando", - "familyName": "Alonso", - "dateOfBirth": "1981-07-29", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "5", - "positionText": "5", - "points": "206", - "wins": "0", - "Driver": { - "driverId": "leclerc", - "permanentNumber": "16", - "code": "LEC", - "url": "http://en.wikipedia.org/wiki/Charles_Leclerc", - "givenName": "Charles", - "familyName": "Leclerc", - "dateOfBirth": "1997-10-16", - "nationality": "Monegasque", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "6", - "positionText": "6", - "points": "205", - "wins": "0", - "Driver": { - "driverId": "norris", - "permanentNumber": "4", - "code": "NOR", - "url": "http://en.wikipedia.org/wiki/Lando_Norris", - "givenName": "Lando", - "familyName": "Norris", - "dateOfBirth": "1999-11-13", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "7", - "positionText": "7", - "points": "200", - "wins": "1", - "Driver": { - "driverId": "sainz", - "permanentNumber": "55", - "code": "SAI", - "url": "http://en.wikipedia.org/wiki/Carlos_Sainz_Jr.", - "givenName": "Carlos", - "familyName": "Sainz", - "dateOfBirth": "1994-09-01", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "8", - "positionText": "8", - "points": "175", - "wins": "0", - "Driver": { - "driverId": "russell", - "permanentNumber": "63", - "code": "RUS", - "url": "http://en.wikipedia.org/wiki/George_Russell_(racing_driver)", - "givenName": "George", - "familyName": "Russell", - "dateOfBirth": "1998-02-15", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "9", - "positionText": "9", - "points": "97", - "wins": "0", - "Driver": { - "driverId": "piastri", - "permanentNumber": "81", - "code": "PIA", - "url": "http://en.wikipedia.org/wiki/Oscar_Piastri", - "givenName": "Oscar", - "familyName": "Piastri", - "dateOfBirth": "2001-04-06", - "nationality": "Australian", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "10", - "positionText": "10", - "points": "74", - "wins": "0", - "Driver": { - "driverId": "stroll", - "permanentNumber": "18", - "code": "STR", - "url": "http://en.wikipedia.org/wiki/Lance_Stroll", - "givenName": "Lance", - "familyName": "Stroll", - "dateOfBirth": "1998-10-29", - "nationality": "Canadian", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "11", - "positionText": "11", - "points": "62", - "wins": "0", - "Driver": { - "driverId": "gasly", - "permanentNumber": "10", - "code": "GAS", - "url": "http://en.wikipedia.org/wiki/Pierre_Gasly", - "givenName": "Pierre", - "familyName": "Gasly", - "dateOfBirth": "1996-02-07", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "12", - "positionText": "12", - "points": "58", - "wins": "0", - "Driver": { - "driverId": "ocon", - "permanentNumber": "31", - "code": "OCO", - "url": "http://en.wikipedia.org/wiki/Esteban_Ocon", - "givenName": "Esteban", - "familyName": "Ocon", - "dateOfBirth": "1996-09-17", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "13", - "positionText": "13", - "points": "27", - "wins": "0", - "Driver": { - "driverId": "albon", - "permanentNumber": "23", - "code": "ALB", - "url": "http://en.wikipedia.org/wiki/Alexander_Albon", - "givenName": "Alexander", - "familyName": "Albon", - "dateOfBirth": "1996-03-23", - "nationality": "Thai", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "14", - "positionText": "14", - "points": "17", - "wins": "0", - "Driver": { - "driverId": "tsunoda", - "permanentNumber": "22", - "code": "TSU", - "url": "http://en.wikipedia.org/wiki/Yuki_Tsunoda", - "givenName": "Yuki", - "familyName": "Tsunoda", - "dateOfBirth": "2000-05-11", - "nationality": "Japanese", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "15", - "positionText": "15", - "points": "10", - "wins": "0", - "Driver": { - "driverId": "bottas", - "permanentNumber": "77", - "code": "BOT", - "url": "http://en.wikipedia.org/wiki/Valtteri_Bottas", - "givenName": "Valtteri", - "familyName": "Bottas", - "dateOfBirth": "1989-08-28", - "nationality": "Finnish", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "16", - "positionText": "16", - "points": "9", - "wins": "0", - "Driver": { - "driverId": "hulkenberg", - "permanentNumber": "27", - "code": "HUL", - "url": "http://en.wikipedia.org/wiki/Nico_H%C3%BClkenberg", - "givenName": "Nico", - "familyName": "Hülkenberg", - "dateOfBirth": "1987-08-19", - "nationality": "German", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "17", - "positionText": "17", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "ricciardo", - "permanentNumber": "3", - "code": "RIC", - "url": "http://en.wikipedia.org/wiki/Daniel_Ricciardo", - "givenName": "Daniel", - "familyName": "Ricciardo", - "dateOfBirth": "1989-07-01", - "nationality": "Australian", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "18", - "positionText": "18", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "zhou", - "permanentNumber": "24", - "code": "ZHO", - "url": "http://en.wikipedia.org/wiki/Zhou_Guanyu", - "givenName": "Guanyu", - "familyName": "Zhou", - "dateOfBirth": "1999-05-30", - "nationality": "Chinese", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "19", - "positionText": "19", - "points": "3", - "wins": "0", - "Driver": { - "driverId": "kevin_magnussen", - "permanentNumber": "20", - "code": "MAG", - "url": "http://en.wikipedia.org/wiki/Kevin_Magnussen", - "givenName": "Kevin", - "familyName": "Magnussen", - "dateOfBirth": "1992-10-05", - "nationality": "Danish", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "20", - "positionText": "20", - "points": "2", - "wins": "0", - "Driver": { - "driverId": "lawson", - "permanentNumber": "40", - "code": "LAW", - "url": "http://en.wikipedia.org/wiki/Liam_Lawson", - "givenName": "Liam", - "familyName": "Lawson", - "dateOfBirth": "2002-02-11", - "nationality": "New Zealander", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "21", - "positionText": "21", - "points": "1", - "wins": "0", - "Driver": { - "driverId": "sargeant", - "permanentNumber": "2", - "code": "SAR", - "url": "http://en.wikipedia.org/wiki/Logan_Sargeant", - "givenName": "Logan", - "familyName": "Sargeant", - "dateOfBirth": "2000-12-31", - "nationality": "American", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "22", - "positionText": "22", - "points": "0", - "wins": "0", - "Driver": { - "driverId": "de_vries", - "permanentNumber": "21", - "code": "DEV", - "url": "http://en.wikipedia.org/wiki/Nyck_de_Vries", - "givenName": "Nyck", - "familyName": "de Vries", - "dateOfBirth": "1995-02-06", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - ], - "ConstructorStandings": [ - { - "position": "1", - "positionText": "1", - "points": "860", - "wins": "21", - "Constructor": { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - }, - }, - { - "position": "2", - "positionText": "2", - "points": "409", - "wins": "0", - "Constructor": { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - }, - }, - { - "position": "3", - "positionText": "3", - "points": "406", - "wins": "1", - "Constructor": { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - }, - }, - { - "position": "4", - "positionText": "4", - "points": "302", - "wins": "0", - "Constructor": { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - }, - }, - { - "position": "5", - "positionText": "5", - "points": "280", - "wins": "0", - "Constructor": { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - }, - }, - { - "position": "6", - "positionText": "6", - "points": "120", - "wins": "0", - "Constructor": { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - }, - }, - { - "position": "7", - "positionText": "7", - "points": "28", - "wins": "0", - "Constructor": { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - }, - }, - { - "position": "8", - "positionText": "8", - "points": "25", - "wins": "0", - "Constructor": { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - }, - }, - { - "position": "9", - "positionText": "9", - "points": "16", - "wins": "0", - "Constructor": { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - }, - }, - { - "position": "10", - "positionText": "10", - "points": "12", - "wins": "0", - "Constructor": { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - }, - }, - ], - } - - -def test_get_standings_good_year_only(): - response = client.get("/standings?year=2023") - assert response.status_code == status.HTTP_200_OK - assert response.json() == { - "season": 2023, - "round": 22, - "DriverStandings": [ - { - "position": "1", - "positionText": "1", - "points": "575", - "wins": "19", - "Driver": { - "driverId": "max_verstappen", - "permanentNumber": "33", - "code": "VER", - "url": "http://en.wikipedia.org/wiki/Max_Verstappen", - "givenName": "Max", - "familyName": "Verstappen", - "dateOfBirth": "1997-09-30", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "2", - "positionText": "2", - "points": "285", - "wins": "2", - "Driver": { - "driverId": "perez", - "permanentNumber": "11", - "code": "PER", - "url": "http://en.wikipedia.org/wiki/Sergio_P%C3%A9rez", - "givenName": "Sergio", - "familyName": "Pérez", - "dateOfBirth": "1990-01-26", - "nationality": "Mexican", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "3", - "positionText": "3", - "points": "234", - "wins": "0", - "Driver": { - "driverId": "hamilton", - "permanentNumber": "44", - "code": "HAM", - "url": "http://en.wikipedia.org/wiki/Lewis_Hamilton", - "givenName": "Lewis", - "familyName": "Hamilton", - "dateOfBirth": "1985-01-07", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "4", - "positionText": "4", - "points": "206", - "wins": "0", - "Driver": { - "driverId": "alonso", - "permanentNumber": "14", - "code": "ALO", - "url": "http://en.wikipedia.org/wiki/Fernando_Alonso", - "givenName": "Fernando", - "familyName": "Alonso", - "dateOfBirth": "1981-07-29", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "5", - "positionText": "5", - "points": "206", - "wins": "0", - "Driver": { - "driverId": "leclerc", - "permanentNumber": "16", - "code": "LEC", - "url": "http://en.wikipedia.org/wiki/Charles_Leclerc", - "givenName": "Charles", - "familyName": "Leclerc", - "dateOfBirth": "1997-10-16", - "nationality": "Monegasque", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "6", - "positionText": "6", - "points": "205", - "wins": "0", - "Driver": { - "driverId": "norris", - "permanentNumber": "4", - "code": "NOR", - "url": "http://en.wikipedia.org/wiki/Lando_Norris", - "givenName": "Lando", - "familyName": "Norris", - "dateOfBirth": "1999-11-13", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "7", - "positionText": "7", - "points": "200", - "wins": "1", - "Driver": { - "driverId": "sainz", - "permanentNumber": "55", - "code": "SAI", - "url": "http://en.wikipedia.org/wiki/Carlos_Sainz_Jr.", - "givenName": "Carlos", - "familyName": "Sainz", - "dateOfBirth": "1994-09-01", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "8", - "positionText": "8", - "points": "175", - "wins": "0", - "Driver": { - "driverId": "russell", - "permanentNumber": "63", - "code": "RUS", - "url": "http://en.wikipedia.org/wiki/George_Russell_(racing_driver)", - "givenName": "George", - "familyName": "Russell", - "dateOfBirth": "1998-02-15", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "9", - "positionText": "9", - "points": "97", - "wins": "0", - "Driver": { - "driverId": "piastri", - "permanentNumber": "81", - "code": "PIA", - "url": "http://en.wikipedia.org/wiki/Oscar_Piastri", - "givenName": "Oscar", - "familyName": "Piastri", - "dateOfBirth": "2001-04-06", - "nationality": "Australian", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "10", - "positionText": "10", - "points": "74", - "wins": "0", - "Driver": { - "driverId": "stroll", - "permanentNumber": "18", - "code": "STR", - "url": "http://en.wikipedia.org/wiki/Lance_Stroll", - "givenName": "Lance", - "familyName": "Stroll", - "dateOfBirth": "1998-10-29", - "nationality": "Canadian", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "11", - "positionText": "11", - "points": "62", - "wins": "0", - "Driver": { - "driverId": "gasly", - "permanentNumber": "10", - "code": "GAS", - "url": "http://en.wikipedia.org/wiki/Pierre_Gasly", - "givenName": "Pierre", - "familyName": "Gasly", - "dateOfBirth": "1996-02-07", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "12", - "positionText": "12", - "points": "58", - "wins": "0", - "Driver": { - "driverId": "ocon", - "permanentNumber": "31", - "code": "OCO", - "url": "http://en.wikipedia.org/wiki/Esteban_Ocon", - "givenName": "Esteban", - "familyName": "Ocon", - "dateOfBirth": "1996-09-17", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "13", - "positionText": "13", - "points": "27", - "wins": "0", - "Driver": { - "driverId": "albon", - "permanentNumber": "23", - "code": "ALB", - "url": "http://en.wikipedia.org/wiki/Alexander_Albon", - "givenName": "Alexander", - "familyName": "Albon", - "dateOfBirth": "1996-03-23", - "nationality": "Thai", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "14", - "positionText": "14", - "points": "17", - "wins": "0", - "Driver": { - "driverId": "tsunoda", - "permanentNumber": "22", - "code": "TSU", - "url": "http://en.wikipedia.org/wiki/Yuki_Tsunoda", - "givenName": "Yuki", - "familyName": "Tsunoda", - "dateOfBirth": "2000-05-11", - "nationality": "Japanese", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "15", - "positionText": "15", - "points": "10", - "wins": "0", - "Driver": { - "driverId": "bottas", - "permanentNumber": "77", - "code": "BOT", - "url": "http://en.wikipedia.org/wiki/Valtteri_Bottas", - "givenName": "Valtteri", - "familyName": "Bottas", - "dateOfBirth": "1989-08-28", - "nationality": "Finnish", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "16", - "positionText": "16", - "points": "9", - "wins": "0", - "Driver": { - "driverId": "hulkenberg", - "permanentNumber": "27", - "code": "HUL", - "url": "http://en.wikipedia.org/wiki/Nico_H%C3%BClkenberg", - "givenName": "Nico", - "familyName": "Hülkenberg", - "dateOfBirth": "1987-08-19", - "nationality": "German", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "17", - "positionText": "17", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "ricciardo", - "permanentNumber": "3", - "code": "RIC", - "url": "http://en.wikipedia.org/wiki/Daniel_Ricciardo", - "givenName": "Daniel", - "familyName": "Ricciardo", - "dateOfBirth": "1989-07-01", - "nationality": "Australian", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "18", - "positionText": "18", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "zhou", - "permanentNumber": "24", - "code": "ZHO", - "url": "http://en.wikipedia.org/wiki/Zhou_Guanyu", - "givenName": "Guanyu", - "familyName": "Zhou", - "dateOfBirth": "1999-05-30", - "nationality": "Chinese", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "19", - "positionText": "19", - "points": "3", - "wins": "0", - "Driver": { - "driverId": "kevin_magnussen", - "permanentNumber": "20", - "code": "MAG", - "url": "http://en.wikipedia.org/wiki/Kevin_Magnussen", - "givenName": "Kevin", - "familyName": "Magnussen", - "dateOfBirth": "1992-10-05", - "nationality": "Danish", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "20", - "positionText": "20", - "points": "2", - "wins": "0", - "Driver": { - "driverId": "lawson", - "permanentNumber": "40", - "code": "LAW", - "url": "http://en.wikipedia.org/wiki/Liam_Lawson", - "givenName": "Liam", - "familyName": "Lawson", - "dateOfBirth": "2002-02-11", - "nationality": "New Zealander", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "21", - "positionText": "21", - "points": "1", - "wins": "0", - "Driver": { - "driverId": "sargeant", - "permanentNumber": "2", - "code": "SAR", - "url": "http://en.wikipedia.org/wiki/Logan_Sargeant", - "givenName": "Logan", - "familyName": "Sargeant", - "dateOfBirth": "2000-12-31", - "nationality": "American", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "22", - "positionText": "22", - "points": "0", - "wins": "0", - "Driver": { - "driverId": "de_vries", - "permanentNumber": "21", - "code": "DEV", - "url": "http://en.wikipedia.org/wiki/Nyck_de_Vries", - "givenName": "Nyck", - "familyName": "de Vries", - "dateOfBirth": "1995-02-06", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - ], - "ConstructorStandings": [ - { - "position": "1", - "positionText": "1", - "points": "860", - "wins": "21", - "Constructor": { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - }, - }, - { - "position": "2", - "positionText": "2", - "points": "409", - "wins": "0", - "Constructor": { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - }, - }, - { - "position": "3", - "positionText": "3", - "points": "406", - "wins": "1", - "Constructor": { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - }, - }, - { - "position": "4", - "positionText": "4", - "points": "302", - "wins": "0", - "Constructor": { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - }, - }, - { - "position": "5", - "positionText": "5", - "points": "280", - "wins": "0", - "Constructor": { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - }, - }, - { - "position": "6", - "positionText": "6", - "points": "120", - "wins": "0", - "Constructor": { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - }, - }, - { - "position": "7", - "positionText": "7", - "points": "28", - "wins": "0", - "Constructor": { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - }, - }, - { - "position": "8", - "positionText": "8", - "points": "25", - "wins": "0", - "Constructor": { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - }, - }, - { - "position": "9", - "positionText": "9", - "points": "16", - "wins": "0", - "Constructor": { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - }, - }, - { - "position": "10", - "positionText": "10", - "points": "12", - "wins": "0", - "Constructor": { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - }, - }, - ], - } - - -def test_get_standings_good_year_and_round(): - response = client.get("/standings?year=2023&round=5") - assert response.status_code == status.HTTP_200_OK - assert response.json() == { - "season": 2023, - "round": 5, - "DriverStandings": [ - { - "position": "1", - "positionText": "1", - "points": "119", - "wins": "3", - "Driver": { - "driverId": "max_verstappen", - "permanentNumber": "33", - "code": "VER", - "url": "http://en.wikipedia.org/wiki/Max_Verstappen", - "givenName": "Max", - "familyName": "Verstappen", - "dateOfBirth": "1997-09-30", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "2", - "positionText": "2", - "points": "105", - "wins": "2", - "Driver": { - "driverId": "perez", - "permanentNumber": "11", - "code": "PER", - "url": "http://en.wikipedia.org/wiki/Sergio_P%C3%A9rez", - "givenName": "Sergio", - "familyName": "Pérez", - "dateOfBirth": "1990-01-26", - "nationality": "Mexican", - }, - "Constructors": [ - { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - } - ], - }, - { - "position": "3", - "positionText": "3", - "points": "75", - "wins": "0", - "Driver": { - "driverId": "alonso", - "permanentNumber": "14", - "code": "ALO", - "url": "http://en.wikipedia.org/wiki/Fernando_Alonso", - "givenName": "Fernando", - "familyName": "Alonso", - "dateOfBirth": "1981-07-29", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "4", - "positionText": "4", - "points": "56", - "wins": "0", - "Driver": { - "driverId": "hamilton", - "permanentNumber": "44", - "code": "HAM", - "url": "http://en.wikipedia.org/wiki/Lewis_Hamilton", - "givenName": "Lewis", - "familyName": "Hamilton", - "dateOfBirth": "1985-01-07", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "5", - "positionText": "5", - "points": "44", - "wins": "0", - "Driver": { - "driverId": "sainz", - "permanentNumber": "55", - "code": "SAI", - "url": "http://en.wikipedia.org/wiki/Carlos_Sainz_Jr.", - "givenName": "Carlos", - "familyName": "Sainz", - "dateOfBirth": "1994-09-01", - "nationality": "Spanish", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "6", - "positionText": "6", - "points": "40", - "wins": "0", - "Driver": { - "driverId": "russell", - "permanentNumber": "63", - "code": "RUS", - "url": "http://en.wikipedia.org/wiki/George_Russell_(racing_driver)", - "givenName": "George", - "familyName": "Russell", - "dateOfBirth": "1998-02-15", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - } - ], - }, - { - "position": "7", - "positionText": "7", - "points": "34", - "wins": "0", - "Driver": { - "driverId": "leclerc", - "permanentNumber": "16", - "code": "LEC", - "url": "http://en.wikipedia.org/wiki/Charles_Leclerc", - "givenName": "Charles", - "familyName": "Leclerc", - "dateOfBirth": "1997-10-16", - "nationality": "Monegasque", - }, - "Constructors": [ - { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - } - ], - }, - { - "position": "8", - "positionText": "8", - "points": "27", - "wins": "0", - "Driver": { - "driverId": "stroll", - "permanentNumber": "18", - "code": "STR", - "url": "http://en.wikipedia.org/wiki/Lance_Stroll", - "givenName": "Lance", - "familyName": "Stroll", - "dateOfBirth": "1998-10-29", - "nationality": "Canadian", - }, - "Constructors": [ - { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - } - ], - }, - { - "position": "9", - "positionText": "9", - "points": "10", - "wins": "0", - "Driver": { - "driverId": "norris", - "permanentNumber": "4", - "code": "NOR", - "url": "http://en.wikipedia.org/wiki/Lando_Norris", - "givenName": "Lando", - "familyName": "Norris", - "dateOfBirth": "1999-11-13", - "nationality": "British", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "10", - "positionText": "10", - "points": "8", - "wins": "0", - "Driver": { - "driverId": "gasly", - "permanentNumber": "10", - "code": "GAS", - "url": "http://en.wikipedia.org/wiki/Pierre_Gasly", - "givenName": "Pierre", - "familyName": "Gasly", - "dateOfBirth": "1996-02-07", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "11", - "positionText": "11", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "hulkenberg", - "permanentNumber": "27", - "code": "HUL", - "url": "http://en.wikipedia.org/wiki/Nico_H%C3%BClkenberg", - "givenName": "Nico", - "familyName": "Hülkenberg", - "dateOfBirth": "1987-08-19", - "nationality": "German", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "12", - "positionText": "12", - "points": "6", - "wins": "0", - "Driver": { - "driverId": "ocon", - "permanentNumber": "31", - "code": "OCO", - "url": "http://en.wikipedia.org/wiki/Esteban_Ocon", - "givenName": "Esteban", - "familyName": "Ocon", - "dateOfBirth": "1996-09-17", - "nationality": "French", - }, - "Constructors": [ - { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - } - ], - }, - { - "position": "13", - "positionText": "13", - "points": "4", - "wins": "0", - "Driver": { - "driverId": "bottas", - "permanentNumber": "77", - "code": "BOT", - "url": "http://en.wikipedia.org/wiki/Valtteri_Bottas", - "givenName": "Valtteri", - "familyName": "Bottas", - "dateOfBirth": "1989-08-28", - "nationality": "Finnish", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "14", - "positionText": "14", - "points": "4", - "wins": "0", - "Driver": { - "driverId": "piastri", - "permanentNumber": "81", - "code": "PIA", - "url": "http://en.wikipedia.org/wiki/Oscar_Piastri", - "givenName": "Oscar", - "familyName": "Piastri", - "dateOfBirth": "2001-04-06", - "nationality": "Australian", - }, - "Constructors": [ - { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - } - ], - }, - { - "position": "15", - "positionText": "15", - "points": "2", - "wins": "0", - "Driver": { - "driverId": "zhou", - "permanentNumber": "24", - "code": "ZHO", - "url": "http://en.wikipedia.org/wiki/Zhou_Guanyu", - "givenName": "Guanyu", - "familyName": "Zhou", - "dateOfBirth": "1999-05-30", - "nationality": "Chinese", - }, - "Constructors": [ - { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - } - ], - }, - { - "position": "16", - "positionText": "16", - "points": "2", - "wins": "0", - "Driver": { - "driverId": "tsunoda", - "permanentNumber": "22", - "code": "TSU", - "url": "http://en.wikipedia.org/wiki/Yuki_Tsunoda", - "givenName": "Yuki", - "familyName": "Tsunoda", - "dateOfBirth": "2000-05-11", - "nationality": "Japanese", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - { - "position": "17", - "positionText": "17", - "points": "2", - "wins": "0", - "Driver": { - "driverId": "kevin_magnussen", - "permanentNumber": "20", - "code": "MAG", - "url": "http://en.wikipedia.org/wiki/Kevin_Magnussen", - "givenName": "Kevin", - "familyName": "Magnussen", - "dateOfBirth": "1992-10-05", - "nationality": "Danish", - }, - "Constructors": [ - { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - } - ], - }, - { - "position": "18", - "positionText": "18", - "points": "1", - "wins": "0", - "Driver": { - "driverId": "albon", - "permanentNumber": "23", - "code": "ALB", - "url": "http://en.wikipedia.org/wiki/Alexander_Albon", - "givenName": "Alexander", - "familyName": "Albon", - "dateOfBirth": "1996-03-23", - "nationality": "Thai", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "19", - "positionText": "19", - "points": "0", - "wins": "0", - "Driver": { - "driverId": "sargeant", - "permanentNumber": "2", - "code": "SAR", - "url": "http://en.wikipedia.org/wiki/Logan_Sargeant", - "givenName": "Logan", - "familyName": "Sargeant", - "dateOfBirth": "2000-12-31", - "nationality": "American", - }, - "Constructors": [ - { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - } - ], - }, - { - "position": "20", - "positionText": "20", - "points": "0", - "wins": "0", - "Driver": { - "driverId": "de_vries", - "permanentNumber": "21", - "code": "DEV", - "url": "http://en.wikipedia.org/wiki/Nyck_de_Vries", - "givenName": "Nyck", - "familyName": "de Vries", - "dateOfBirth": "1995-02-06", - "nationality": "Dutch", - }, - "Constructors": [ - { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - } - ], - }, - ], - "ConstructorStandings": [ - { - "position": "1", - "positionText": "1", - "points": "224", - "wins": "5", - "Constructor": { - "constructorId": "red_bull", - "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", - "name": "Red Bull", - "nationality": "Austrian", - }, - }, - { - "position": "2", - "positionText": "2", - "points": "102", - "wins": "0", - "Constructor": { - "constructorId": "aston_martin", - "url": "http://en.wikipedia.org/wiki/Aston_Martin_in_Formula_One", - "name": "Aston Martin", - "nationality": "British", - }, - }, - { - "position": "3", - "positionText": "3", - "points": "96", - "wins": "0", - "Constructor": { - "constructorId": "mercedes", - "url": "http://en.wikipedia.org/wiki/Mercedes-Benz_in_Formula_One", - "name": "Mercedes", - "nationality": "German", - }, - }, - { - "position": "4", - "positionText": "4", - "points": "78", - "wins": "0", - "Constructor": { - "constructorId": "ferrari", - "url": "http://en.wikipedia.org/wiki/Scuderia_Ferrari", - "name": "Ferrari", - "nationality": "Italian", - }, - }, - { - "position": "5", - "positionText": "5", - "points": "14", - "wins": "0", - "Constructor": { - "constructorId": "mclaren", - "url": "http://en.wikipedia.org/wiki/McLaren", - "name": "McLaren", - "nationality": "British", - }, - }, - { - "position": "6", - "positionText": "6", - "points": "14", - "wins": "0", - "Constructor": { - "constructorId": "alpine", - "url": "http://en.wikipedia.org/wiki/Alpine_F1_Team", - "name": "Alpine F1 Team", - "nationality": "French", - }, - }, - { - "position": "7", - "positionText": "7", - "points": "8", - "wins": "0", - "Constructor": { - "constructorId": "haas", - "url": "http://en.wikipedia.org/wiki/Haas_F1_Team", - "name": "Haas F1 Team", - "nationality": "American", - }, - }, - { - "position": "8", - "positionText": "8", - "points": "6", - "wins": "0", - "Constructor": { - "constructorId": "alfa", - "url": "http://en.wikipedia.org/wiki/Alfa_Romeo_in_Formula_One", - "name": "Alfa Romeo", - "nationality": "Swiss", - }, - }, - { - "position": "9", - "positionText": "9", - "points": "2", - "wins": "0", - "Constructor": { - "constructorId": "alphatauri", - "url": "http://en.wikipedia.org/wiki/Scuderia_AlphaTauri", - "name": "AlphaTauri", - "nationality": "Italian", - }, - }, - { - "position": "10", - "positionText": "10", - "points": "1", - "wins": "0", - "Constructor": { - "constructorId": "williams", - "url": "http://en.wikipedia.org/wiki/Williams_Grand_Prix_Engineering", - "name": "Williams", - "nationality": "British", - }, - }, - ], - } - - -# endregion standings - good inputs - -# region standings - no inputs - - -def test_get_standings_good_round_bad_year_no_input(): - response = client.get("/standings?round=3") - assert response.status_code == status.HTTP_400_BAD_REQUEST - assert response.json() == { - "detail": 'Bad request. Must provide the "year" parameter.' - } - - -# endregion standings - no inputs - -# endregion standings - - -# region results - -# region results - good inputs - - -def test_get_results(): - response = client.get("/results/2023/5") - assert response.status_code == status.HTTP_200_OK - assert response.json() == [ - { - "DriverNumber": "1", - "BroadcastName": "M VERSTAPPEN", - "Abbreviation": "VER", - "DriverId": "max_verstappen", - "TeamName": "Red Bull Racing", - "TeamColor": "3671C6", - "TeamId": "red_bull", - "FirstName": "Max", - "LastName": "Verstappen", - "FullName": "Max Verstappen", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/M/MAXVER01_Max_Verstappen/maxver01.png.transform/1col/image.png", - "CountryCode": "NED", - "Position": 1, - "ClassifiedPosition": "1", - "GridPosition": 9, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 5258241, - "Status": "Finished", - "Points": 26, - }, - { - "DriverNumber": "11", - "BroadcastName": "S PEREZ", - "Abbreviation": "PER", - "DriverId": "perez", - "TeamName": "Red Bull Racing", - "TeamColor": "3671C6", - "TeamId": "red_bull", - "FirstName": "Sergio", - "LastName": "Perez", - "FullName": "Sergio Perez", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/S/SERPER01_Sergio_Perez/serper01.png.transform/1col/image.png", - "CountryCode": "MEX", - "Position": 2, - "ClassifiedPosition": "2", - "GridPosition": 1, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 5384, - "Status": "Finished", - "Points": 18, - }, - { - "DriverNumber": "14", - "BroadcastName": "F ALONSO", - "Abbreviation": "ALO", - "DriverId": "alonso", - "TeamName": "Aston Martin", - "TeamColor": "358C75", - "TeamId": "aston_martin", - "FirstName": "Fernando", - "LastName": "Alonso", - "FullName": "Fernando Alonso", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/F/FERALO01_Fernando_Alonso/feralo01.png.transform/1col/image.png", - "CountryCode": "ESP", - "Position": 3, - "ClassifiedPosition": "3", - "GridPosition": 2, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 26305, - "Status": "Finished", - "Points": 15, - }, - { - "DriverNumber": "63", - "BroadcastName": "G RUSSELL", - "Abbreviation": "RUS", - "DriverId": "russell", - "TeamName": "Mercedes", - "TeamColor": "6CD3BF", - "TeamId": "mercedes", - "FirstName": "George", - "LastName": "Russell", - "FullName": "George Russell", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/G/GEORUS01_George_Russell/georus01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 4, - "ClassifiedPosition": "4", - "GridPosition": 6, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 33229, - "Status": "Finished", - "Points": 12, - }, - { - "DriverNumber": "55", - "BroadcastName": "C SAINZ", - "Abbreviation": "SAI", - "DriverId": "sainz", - "TeamName": "Ferrari", - "TeamColor": "F91536", - "TeamId": "ferrari", - "FirstName": "Carlos", - "LastName": "Sainz", - "FullName": "Carlos Sainz", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/C/CARSAI01_Carlos_Sainz/carsai01.png.transform/1col/image.png", - "CountryCode": "ESP", - "Position": 5, - "ClassifiedPosition": "5", - "GridPosition": 3, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 42511, - "Status": "Finished", - "Points": 10, - }, - { - "DriverNumber": "44", - "BroadcastName": "L HAMILTON", - "Abbreviation": "HAM", - "DriverId": "hamilton", - "TeamName": "Mercedes", - "TeamColor": "6CD3BF", - "TeamId": "mercedes", - "FirstName": "Lewis", - "LastName": "Hamilton", - "FullName": "Lewis Hamilton", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LEWHAM01_Lewis_Hamilton/lewham01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 6, - "ClassifiedPosition": "6", - "GridPosition": 13, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 51249, - "Status": "Finished", - "Points": 8, - }, - { - "DriverNumber": "16", - "BroadcastName": "C LECLERC", - "Abbreviation": "LEC", - "DriverId": "leclerc", - "TeamName": "Ferrari", - "TeamColor": "F91536", - "TeamId": "ferrari", - "FirstName": "Charles", - "LastName": "Leclerc", - "FullName": "Charles Leclerc", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/C/CHALEC01_Charles_Leclerc/chalec01.png.transform/1col/image.png", - "CountryCode": "MON", - "Position": 7, - "ClassifiedPosition": "7", - "GridPosition": 7, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 52988, - "Status": "Finished", - "Points": 6, - }, - { - "DriverNumber": "10", - "BroadcastName": "P GASLY", - "Abbreviation": "GAS", - "DriverId": "gasly", - "TeamName": "Alpine", - "TeamColor": "2293D1", - "TeamId": "alpine", - "FirstName": "Pierre", - "LastName": "Gasly", - "FullName": "Pierre Gasly", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/P/PIEGAS01_Pierre_Gasly/piegas01.png.transform/1col/image.png", - "CountryCode": "FRA", - "Position": 8, - "ClassifiedPosition": "8", - "GridPosition": 5, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 55670, - "Status": "Finished", - "Points": 4, - }, - { - "DriverNumber": "31", - "BroadcastName": "E OCON", - "Abbreviation": "OCO", - "DriverId": "ocon", - "TeamName": "Alpine", - "TeamColor": "2293D1", - "TeamId": "alpine", - "FirstName": "Esteban", - "LastName": "Ocon", - "FullName": "Esteban Ocon", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/E/ESTOCO01_Esteban_Ocon/estoco01.png.transform/1col/image.png", - "CountryCode": "FRA", - "Position": 9, - "ClassifiedPosition": "9", - "GridPosition": 8, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 58123, - "Status": "Finished", - "Points": 2, - }, - { - "DriverNumber": "20", - "BroadcastName": "K MAGNUSSEN", - "Abbreviation": "MAG", - "DriverId": "kevin_magnussen", - "TeamName": "Haas F1 Team", - "TeamColor": "B6BABD", - "TeamId": "haas", - "FirstName": "Kevin", - "LastName": "Magnussen", - "FullName": "Kevin Magnussen", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/K/KEVMAG01_Kevin_Magnussen/kevmag01.png.transform/1col/image.png", - "CountryCode": "DEN", - "Position": 10, - "ClassifiedPosition": "10", - "GridPosition": 4, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 62945, - "Status": "Finished", - "Points": 1, - }, - { - "DriverNumber": "22", - "BroadcastName": "Y TSUNODA", - "Abbreviation": "TSU", - "DriverId": "tsunoda", - "TeamName": "AlphaTauri", - "TeamColor": "5E8FAA", - "TeamId": "alphatauri", - "FirstName": "Yuki", - "LastName": "Tsunoda", - "FullName": "Yuki Tsunoda", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/Y/YUKTSU01_Yuki_Tsunoda/yuktsu01.png.transform/1col/image.png", - "CountryCode": "JPN", - "Position": 11, - "ClassifiedPosition": "11", - "GridPosition": 17, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 64309, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "18", - "BroadcastName": "L STROLL", - "Abbreviation": "STR", - "DriverId": "stroll", - "TeamName": "Aston Martin", - "TeamColor": "358C75", - "TeamId": "aston_martin", - "FirstName": "Lance", - "LastName": "Stroll", - "FullName": "Lance Stroll", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LANSTR01_Lance_Stroll/lanstr01.png.transform/1col/image.png", - "CountryCode": "CAN", - "Position": 12, - "ClassifiedPosition": "12", - "GridPosition": 18, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 64754, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "77", - "BroadcastName": "V BOTTAS", - "Abbreviation": "BOT", - "DriverId": "bottas", - "TeamName": "Alfa Romeo", - "TeamColor": "C92D4B", - "TeamId": "alfa", - "FirstName": "Valtteri", - "LastName": "Bottas", - "FullName": "Valtteri Bottas", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/V/VALBOT01_Valtteri_Bottas/valbot01.png.transform/1col/image.png", - "CountryCode": "FIN", - "Position": 13, - "ClassifiedPosition": "13", - "GridPosition": 10, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 71637, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "23", - "BroadcastName": "A ALBON", - "Abbreviation": "ALB", - "DriverId": "albon", - "TeamName": "Williams", - "TeamColor": "37BEDD", - "TeamId": "williams", - "FirstName": "Alexander", - "LastName": "Albon", - "FullName": "Alexander Albon", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/A/ALEALB01_Alexander_Albon/alealb01.png.transform/1col/image.png", - "CountryCode": "THA", - "Position": 14, - "ClassifiedPosition": "14", - "GridPosition": 11, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 72861, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "27", - "BroadcastName": "N HULKENBERG", - "Abbreviation": "HUL", - "DriverId": "hulkenberg", - "TeamName": "Haas F1 Team", - "TeamColor": "B6BABD", - "TeamId": "haas", - "FirstName": "Nico", - "LastName": "Hulkenberg", - "FullName": "Nico Hulkenberg", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/N/NICHUL01_Nico_Hulkenberg/nichul01.png.transform/1col/image.png", - "CountryCode": "GER", - "Position": 15, - "ClassifiedPosition": "15", - "GridPosition": 12, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 74950, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "24", - "BroadcastName": "G ZHOU", - "Abbreviation": "ZHO", - "DriverId": "zhou", - "TeamName": "Alfa Romeo", - "TeamColor": "C92D4B", - "TeamId": "alfa", - "FirstName": "Guanyu", - "LastName": "Zhou", - "FullName": "Guanyu Zhou", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/G/GUAZHO01_Guanyu_Zhou/guazho01.png.transform/1col/image.png", - "CountryCode": "CHN", - "Position": 16, - "ClassifiedPosition": "16", - "GridPosition": 14, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 78440, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "4", - "BroadcastName": "L NORRIS", - "Abbreviation": "NOR", - "DriverId": "norris", - "TeamName": "McLaren", - "TeamColor": "F58020", - "TeamId": "mclaren", - "FirstName": "Lando", - "LastName": "Norris", - "FullName": "Lando Norris", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LANNOR01_Lando_Norris/lannor01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 17, - "ClassifiedPosition": "17", - "GridPosition": 16, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 87717, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "21", - "BroadcastName": "N DE VRIES", - "Abbreviation": "DEV", - "DriverId": "de_vries", - "TeamName": "AlphaTauri", - "TeamColor": "5E8FAA", - "TeamId": "alphatauri", - "FirstName": "Nyck", - "LastName": "De Vries", - "FullName": "Nyck De Vries", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/N/NYCDEV01_Nyck_De%20Vries/nycdev01.png.transform/1col/image.png", - "CountryCode": "NED", - "Position": 18, - "ClassifiedPosition": "18", - "GridPosition": 15, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": 88949, - "Status": "Finished", - "Points": 0, - }, - { - "DriverNumber": "81", - "BroadcastName": "O PIASTRI", - "Abbreviation": "PIA", - "DriverId": "piastri", - "TeamName": "McLaren", - "TeamColor": "F58020", - "TeamId": "mclaren", - "FirstName": "Oscar", - "LastName": "Piastri", - "FullName": "Oscar Piastri", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/O/OSCPIA01_Oscar_Piastri/oscpia01.png.transform/1col/image.png", - "CountryCode": "AUS", - "Position": 19, - "ClassifiedPosition": "19", - "GridPosition": 19, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "+1 Lap", - "Points": 0, - }, - { - "DriverNumber": "2", - "BroadcastName": "L SARGEANT", - "Abbreviation": "SAR", - "DriverId": "sargeant", - "TeamName": "Williams", - "TeamColor": "37BEDD", - "TeamId": "williams", - "FirstName": "Logan", - "LastName": "Sargeant", - "FullName": "Logan Sargeant", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LOGSAR01_Logan_Sargeant/logsar01.png.transform/1col/image.png", - "CountryCode": "USA", - "Position": 20, - "ClassifiedPosition": "20", - "GridPosition": 20, - "Q1": None, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "+1 Lap", - "Points": 0, - }, - ] - - -def test_get_results_with_session(): - response = client.get("/results/2023/5?session=4") - assert response.status_code == status.HTTP_200_OK - assert response.json() == [ - { - "DriverNumber": "11", - "BroadcastName": "S PEREZ", - "Abbreviation": "PER", - "DriverId": "perez", - "TeamName": "Red Bull Racing", - "TeamColor": "3671C6", - "TeamId": "red_bull", - "FirstName": "Sergio", - "LastName": "Perez", - "FullName": "Sergio Perez", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/S/SERPER01_Sergio_Perez/serper01.png.transform/1col/image.png", - "CountryCode": "MEX", - "Position": 1, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87713, - "Q2": 87328, - "Q3": 86841, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "14", - "BroadcastName": "F ALONSO", - "Abbreviation": "ALO", - "DriverId": "alonso", - "TeamName": "Aston Martin", - "TeamColor": "358C75", - "TeamId": "aston_martin", - "FirstName": "Fernando", - "LastName": "Alonso", - "FullName": "Fernando Alonso", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/F/FERALO01_Fernando_Alonso/feralo01.png.transform/1col/image.png", - "CountryCode": "ESP", - "Position": 2, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88179, - "Q2": 87097, - "Q3": 87202, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "55", - "BroadcastName": "C SAINZ", - "Abbreviation": "SAI", - "DriverId": "sainz", - "TeamName": "Ferrari", - "TeamColor": "F91536", - "TeamId": "ferrari", - "FirstName": "Carlos", - "LastName": "Sainz", - "FullName": "Carlos Sainz", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/C/CARSAI01_Carlos_Sainz/carsai01.png.transform/1col/image.png", - "CountryCode": "ESP", - "Position": 3, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87686, - "Q2": 87148, - "Q3": 87349, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "20", - "BroadcastName": "K MAGNUSSEN", - "Abbreviation": "MAG", - "DriverId": "kevin_magnussen", - "TeamName": "Haas F1 Team", - "TeamColor": "B6BABD", - "TeamId": "haas", - "FirstName": "Kevin", - "LastName": "Magnussen", - "FullName": "Kevin Magnussen", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/K/KEVMAG01_Kevin_Magnussen/kevmag01.png.transform/1col/image.png", - "CountryCode": "DEN", - "Position": 4, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87809, - "Q2": 87673, - "Q3": 87767, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "10", - "BroadcastName": "P GASLY", - "Abbreviation": "GAS", - "DriverId": "gasly", - "TeamName": "Alpine", - "TeamColor": "2293D1", - "TeamId": "alpine", - "FirstName": "Pierre", - "LastName": "Gasly", - "FullName": "Pierre Gasly", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/P/PIEGAS01_Pierre_Gasly/piegas01.png.transform/1col/image.png", - "CountryCode": "FRA", - "Position": 5, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88061, - "Q2": 87612, - "Q3": 87786, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "63", - "BroadcastName": "G RUSSELL", - "Abbreviation": "RUS", - "DriverId": "russell", - "TeamName": "Mercedes", - "TeamColor": "6CD3BF", - "TeamId": "mercedes", - "FirstName": "George", - "LastName": "Russell", - "FullName": "George Russell", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/G/GEORUS01_George_Russell/georus01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 6, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88086, - "Q2": 87743, - "Q3": 87804, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "16", - "BroadcastName": "C LECLERC", - "Abbreviation": "LEC", - "DriverId": "leclerc", - "TeamName": "Ferrari", - "TeamColor": "F91536", - "TeamId": "ferrari", - "FirstName": "Charles", - "LastName": "Leclerc", - "FullName": "Charles Leclerc", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/C/CHALEC01_Charles_Leclerc/chalec01.png.transform/1col/image.png", - "CountryCode": "MON", - "Position": 7, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87713, - "Q2": 86964, - "Q3": 87861, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "31", - "BroadcastName": "E OCON", - "Abbreviation": "OCO", - "DriverId": "ocon", - "TeamName": "Alpine", - "TeamColor": "2293D1", - "TeamId": "alpine", - "FirstName": "Esteban", - "LastName": "Ocon", - "FullName": "Esteban Ocon", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/E/ESTOCO01_Esteban_Ocon/estoco01.png.transform/1col/image.png", - "CountryCode": "FRA", - "Position": 8, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87872, - "Q2": 87444, - "Q3": 87935, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "1", - "BroadcastName": "M VERSTAPPEN", - "Abbreviation": "VER", - "DriverId": "max_verstappen", - "TeamName": "Red Bull Racing", - "TeamColor": "3671C6", - "TeamId": "red_bull", - "FirstName": "Max", - "LastName": "Verstappen", - "FullName": "Max Verstappen", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/M/MAXVER01_Max_Verstappen/maxver01.png.transform/1col/image.png", - "CountryCode": "NED", - "Position": 9, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87363, - "Q2": 86814, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "77", - "BroadcastName": "V BOTTAS", - "Abbreviation": "BOT", - "DriverId": "bottas", - "TeamName": "Alfa Romeo", - "TeamColor": "C92D4B", - "TeamId": "alfa", - "FirstName": "Valtteri", - "LastName": "Bottas", - "FullName": "Valtteri Bottas", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/V/VALBOT01_Valtteri_Bottas/valbot01.png.transform/1col/image.png", - "CountryCode": "FIN", - "Position": 10, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87864, - "Q2": 87564, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "23", - "BroadcastName": "A ALBON", - "Abbreviation": "ALB", - "DriverId": "albon", - "TeamName": "Williams", - "TeamColor": "37BEDD", - "TeamId": "williams", - "FirstName": "Alexander", - "LastName": "Albon", - "FullName": "Alexander Albon", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/A/ALEALB01_Alexander_Albon/alealb01.png.transform/1col/image.png", - "CountryCode": "THA", - "Position": 11, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88234, - "Q2": 87795, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "27", - "BroadcastName": "N HULKENBERG", - "Abbreviation": "HUL", - "DriverId": "hulkenberg", - "TeamName": "Haas F1 Team", - "TeamColor": "B6BABD", - "TeamId": "haas", - "FirstName": "Nico", - "LastName": "Hulkenberg", - "FullName": "Nico Hulkenberg", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/N/NICHUL01_Nico_Hulkenberg/nichul01.png.transform/1col/image.png", - "CountryCode": "GER", - "Position": 12, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87945, - "Q2": 87903, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "44", - "BroadcastName": "L HAMILTON", - "Abbreviation": "HAM", - "DriverId": "hamilton", - "TeamName": "Mercedes", - "TeamColor": "6CD3BF", - "TeamId": "mercedes", - "FirstName": "Lewis", - "LastName": "Hamilton", - "FullName": "Lewis Hamilton", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LEWHAM01_Lewis_Hamilton/lewham01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 13, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 87846, - "Q2": 87975, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "24", - "BroadcastName": "G ZHOU", - "Abbreviation": "ZHO", - "DriverId": "zhou", - "TeamName": "Alfa Romeo", - "TeamColor": "C92D4B", - "TeamId": "alfa", - "FirstName": "Guanyu", - "LastName": "Zhou", - "FullName": "Guanyu Zhou", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/G/GUAZHO01_Guanyu_Zhou/guazho01.png.transform/1col/image.png", - "CountryCode": "CHN", - "Position": 14, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88180, - "Q2": 88091, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "21", - "BroadcastName": "N DE VRIES", - "Abbreviation": "DEV", - "DriverId": "de_vries", - "TeamName": "AlphaTauri", - "TeamColor": "5E8FAA", - "TeamId": "alphatauri", - "FirstName": "Nyck", - "LastName": "De Vries", - "FullName": "Nyck De Vries", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/N/NYCDEV01_Nyck_De%20Vries/nycdev01.png.transform/1col/image.png", - "CountryCode": "NED", - "Position": 15, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88325, - "Q2": 88395, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "4", - "BroadcastName": "L NORRIS", - "Abbreviation": "NOR", - "DriverId": "norris", - "TeamName": "McLaren", - "TeamColor": "F58020", - "TeamId": "mclaren", - "FirstName": "Lando", - "LastName": "Norris", - "FullName": "Lando Norris", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LANNOR01_Lando_Norris/lannor01.png.transform/1col/image.png", - "CountryCode": "GBR", - "Position": 16, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88394, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "22", - "BroadcastName": "Y TSUNODA", - "Abbreviation": "TSU", - "DriverId": "tsunoda", - "TeamName": "AlphaTauri", - "TeamColor": "5E8FAA", - "TeamId": "alphatauri", - "FirstName": "Yuki", - "LastName": "Tsunoda", - "FullName": "Yuki Tsunoda", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/Y/YUKTSU01_Yuki_Tsunoda/yuktsu01.png.transform/1col/image.png", - "CountryCode": "JPN", - "Position": 17, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88429, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "18", - "BroadcastName": "L STROLL", - "Abbreviation": "STR", - "DriverId": "stroll", - "TeamName": "Aston Martin", - "TeamColor": "358C75", - "TeamId": "aston_martin", - "FirstName": "Lance", - "LastName": "Stroll", - "FullName": "Lance Stroll", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LANSTR01_Lance_Stroll/lanstr01.png.transform/1col/image.png", - "CountryCode": "CAN", - "Position": 18, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88476, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "81", - "BroadcastName": "O PIASTRI", - "Abbreviation": "PIA", - "DriverId": "piastri", - "TeamName": "McLaren", - "TeamColor": "F58020", - "TeamId": "mclaren", - "FirstName": "Oscar", - "LastName": "Piastri", - "FullName": "Oscar Piastri", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/O/OSCPIA01_Oscar_Piastri/oscpia01.png.transform/1col/image.png", - "CountryCode": "AUS", - "Position": 19, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88484, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - { - "DriverNumber": "2", - "BroadcastName": "L SARGEANT", - "Abbreviation": "SAR", - "DriverId": "sargeant", - "TeamName": "Williams", - "TeamColor": "37BEDD", - "TeamId": "williams", - "FirstName": "Logan", - "LastName": "Sargeant", - "FullName": "Logan Sargeant", - "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/L/LOGSAR01_Logan_Sargeant/logsar01.png.transform/1col/image.png", - "CountryCode": "USA", - "Position": 20, - "ClassifiedPosition": "", - "GridPosition": None, - "Q1": 88577, - "Q2": None, - "Q3": None, - "Time": None, - "Status": "", - "Points": None, - }, - ] - - -# endregion results - good inputs - -# region results - bad inputs - - -def test_get_results_bad_round_invalid(): - response = client.get("/results/2023/25?session=2") - assert response.status_code == status.HTTP_400_BAD_REQUEST - assert response.json() == {"detail": "Bad Request. Invalid round: 25"} - - -# endregion results - bad inputs - -# endregion results diff --git a/app/utils.py b/app/utils.py index 744e56c..263e79c 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1,5 +1,7 @@ +# Built-in from datetime import datetime +# External import fastf1 @@ -18,9 +20,7 @@ def get_default_year() -> int: # per current (2023-01-22) fastf1/ergast implementation, the value is 1. race_event_round_number = event_schedule.iloc[0]["RoundNumber"] # create a fastf1.core.Session object - first_race_event_session_obj = fastf1.get_session( - current_year, race_event_round_number, "Race" - ) + first_race_event_session_obj = fastf1.get_session(current_year, race_event_round_number, "Race") # load session data first_race_event_session_obj.load() except (ValueError, KeyError): diff --git a/poetry.lock b/poetry.lock index c6fe831..a921e4a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,14 +1,25 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] @@ -34,6 +45,17 @@ files = [ [package.extras] test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] +[[package]] +name = "astroid" +version = "3.1.0" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "astroid-3.1.0-py3-none-any.whl", hash = "sha256:951798f922990137ac090c53af473db7ab4e70c770e6d7fae0cec59f74411819"}, + {file = "astroid-3.1.0.tar.gz", hash = "sha256:ac248253bfa4bd924a0de213707e7ebeeb3138abeb48d798784ead1e56d419d4"}, +] + [[package]] name = "attrs" version = "23.2.0" @@ -53,35 +75,49 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] +[[package]] +name = "autoflake" +version = "2.3.0" +description = "Removes unused imports and unused variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "autoflake-2.3.0-py3-none-any.whl", hash = "sha256:79a51eb8c0744759d2efe052455ab20aa6a314763510c3fd897499a402126327"}, + {file = "autoflake-2.3.0.tar.gz", hash = "sha256:8c2011fa34701b9d7dcf05b9873bc4859d4fce4e62dfea90dffefd1576f5f01d"}, +] + +[package.dependencies] +pyflakes = ">=3.0.0" + [[package]] name = "black" -version = "24.1.1" +version = "24.2.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-24.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2588021038bd5ada078de606f2a804cadd0a3cc6a79cb3e9bb3a8bf581325a4c"}, - {file = "black-24.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a95915c98d6e32ca43809d46d932e2abc5f1f7d582ffbe65a5b4d1588af7445"}, - {file = "black-24.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fa6a0e965779c8f2afb286f9ef798df770ba2b6cee063c650b96adec22c056a"}, - {file = "black-24.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:5242ecd9e990aeb995b6d03dc3b2d112d4a78f2083e5a8e86d566340ae80fec4"}, - {file = "black-24.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fc1ec9aa6f4d98d022101e015261c056ddebe3da6a8ccfc2c792cbe0349d48b7"}, - {file = "black-24.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0269dfdea12442022e88043d2910429bed717b2d04523867a85dacce535916b8"}, - {file = "black-24.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3d64db762eae4a5ce04b6e3dd745dcca0fb9560eb931a5be97472e38652a161"}, - {file = "black-24.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5d7b06ea8816cbd4becfe5f70accae953c53c0e53aa98730ceccb0395520ee5d"}, - {file = "black-24.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e2c8dfa14677f90d976f68e0c923947ae68fa3961d61ee30976c388adc0b02c8"}, - {file = "black-24.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a21725862d0e855ae05da1dd25e3825ed712eaaccef6b03017fe0853a01aa45e"}, - {file = "black-24.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07204d078e25327aad9ed2c64790d681238686bce254c910de640c7cc4fc3aa6"}, - {file = "black-24.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:a83fe522d9698d8f9a101b860b1ee154c1d25f8a82ceb807d319f085b2627c5b"}, - {file = "black-24.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:08b34e85170d368c37ca7bf81cf67ac863c9d1963b2c1780c39102187ec8dd62"}, - {file = "black-24.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7258c27115c1e3b5de9ac6c4f9957e3ee2c02c0b39222a24dc7aa03ba0e986f5"}, - {file = "black-24.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40657e1b78212d582a0edecafef133cf1dd02e6677f539b669db4746150d38f6"}, - {file = "black-24.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e298d588744efda02379521a19639ebcd314fba7a49be22136204d7ed1782717"}, - {file = "black-24.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:34afe9da5056aa123b8bfda1664bfe6fb4e9c6f311d8e4a6eb089da9a9173bf9"}, - {file = "black-24.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:854c06fb86fd854140f37fb24dbf10621f5dab9e3b0c29a690ba595e3d543024"}, - {file = "black-24.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3897ae5a21ca132efa219c029cce5e6bfc9c3d34ed7e892113d199c0b1b444a2"}, - {file = "black-24.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:ecba2a15dfb2d97105be74bbfe5128bc5e9fa8477d8c46766505c1dda5883aac"}, - {file = "black-24.1.1-py3-none-any.whl", hash = "sha256:5cdc2e2195212208fbcae579b931407c1fa9997584f0a415421748aeafff1168"}, - {file = "black-24.1.1.tar.gz", hash = "sha256:48b5760dcbfe5cf97fd4fba23946681f3a81514c6ab8a45b50da67ac8fbc6c7b"}, + {file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"}, + {file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"}, + {file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"}, + {file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"}, + {file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"}, + {file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"}, + {file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"}, + {file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"}, + {file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"}, + {file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"}, + {file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"}, + {file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"}, + {file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"}, + {file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"}, + {file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"}, + {file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"}, + {file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"}, + {file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"}, + {file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"}, + {file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"}, + {file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"}, + {file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"}, ] [package.dependencies] @@ -268,13 +304,13 @@ files = [ [[package]] name = "commitizen" -version = "3.14.1" +version = "3.16.0" description = "Python commitizen client tool" optional = false python-versions = ">=3.8" files = [ - {file = "commitizen-3.14.1-py3-none-any.whl", hash = "sha256:e0f0bb2eb19a6bcc540902d32e5e3b53c2f7636e888bb1894f83efb416af8762"}, - {file = "commitizen-3.14.1.tar.gz", hash = "sha256:21e19143d209fd6b1feb6332430ad91cf5d37ba09990c74d1f941ef1e9087898"}, + {file = "commitizen-3.16.0-py3-none-any.whl", hash = "sha256:a880005352fd35b908d9c3951e71e155b157f4a4ec61ca9c080a9637bf98e0a1"}, + {file = "commitizen-3.16.0.tar.gz", hash = "sha256:1269619d383d12809f436ff196fb786a3d49fc50987562e6e566cd9c2908735c"}, ] [package.dependencies] @@ -379,6 +415,21 @@ files = [ {file = "decli-0.6.1.tar.gz", hash = "sha256:ed88ccb947701e8e5509b7945fda56e150e2ac74a69f25d47ac85ef30ab0c0f0"}, ] +[[package]] +name = "dill" +version = "0.3.8" +description = "serialize all of Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, + {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] +profile = ["gprof2dot (>=2022.7.29)"] + [[package]] name = "distlib" version = "0.3.8" @@ -392,13 +443,13 @@ files = [ [[package]] name = "fastapi" -version = "0.109.2" +version = "0.110.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.109.2-py3-none-any.whl", hash = "sha256:2c9bab24667293b501cad8dd388c05240c850b58ec5876ee3283c47d6e1e3a4d"}, - {file = "fastapi-0.109.2.tar.gz", hash = "sha256:f3817eac96fe4f65a2ebb4baa000f394e55f5fccdaf7f75250804bc58f354f73"}, + {file = "fastapi-0.110.0-py3-none-any.whl", hash = "sha256:87a1f6fb632a218222c5984be540055346a8f5d8a68e8f6fb647b1dc9934de4b"}, + {file = "fastapi-0.110.0.tar.gz", hash = "sha256:266775f0dcc95af9d3ef39bad55cff525329a931d5fd51930aadd4f428bf7ff3"}, ] [package.dependencies] @@ -409,22 +460,6 @@ typing-extensions = ">=4.8.0" [package.extras] all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -[[package]] -name = "fastapi-utils" -version = "0.2.1" -description = "Reusable utilities for FastAPI" -optional = false -python-versions = ">=3.6,<4.0" -files = [ - {file = "fastapi-utils-0.2.1.tar.gz", hash = "sha256:0e6c7fc1870b80e681494957abf65d4f4f42f4c7f70005918e9181b22f1bd759"}, - {file = "fastapi_utils-0.2.1-py3-none-any.whl", hash = "sha256:dd0be7dc7f03fa681b25487a206651d99f2330d5a567fb8ab6cb5f8a06a29360"}, -] - -[package.dependencies] -fastapi = "*" -pydantic = ">=1.0,<2.0" -sqlalchemy = ">=1.3.12,<2.0.0" - [[package]] name = "fastf1" version = "3.2.2" @@ -466,53 +501,53 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "fonttools" -version = "4.48.1" +version = "4.49.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:702ae93058c81f46461dc4b2c79f11d3c3d8fd7296eaf8f75b4ba5bbf813cd5f"}, - {file = "fonttools-4.48.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:97f0a49fa6aa2d6205c6f72f4f98b74ef4b9bfdcb06fd78e6fe6c7af4989b63e"}, - {file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3260db55f1843e57115256e91247ad9f68cb02a434b51262fe0019e95a98738"}, - {file = "fonttools-4.48.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e740a7602c2bb71e1091269b5dbe89549749a8817dc294b34628ffd8b2bf7124"}, - {file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4108b1d247953dd7c90ec8f457a2dec5fceb373485973cc852b14200118a51ee"}, - {file = "fonttools-4.48.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56339ec557f0c342bddd7c175f5e41c45fc21282bee58a86bd9aa322bec715f2"}, - {file = "fonttools-4.48.1-cp310-cp310-win32.whl", hash = "sha256:bff5b38d0e76eb18e0b8abbf35d384e60b3371be92f7be36128ee3e67483b3ec"}, - {file = "fonttools-4.48.1-cp310-cp310-win_amd64.whl", hash = "sha256:f7449493886da6a17472004d3818cc050ba3f4a0aa03fb47972e4fa5578e6703"}, - {file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18b35fd1a850ed7233a99bbd6774485271756f717dac8b594958224b54118b61"}, - {file = "fonttools-4.48.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cad5cfd044ea2e306fda44482b3dd32ee47830fa82dfa4679374b41baa294f5f"}, - {file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f30e605c7565d0da6f0aec75a30ec372072d016957cd8fc4469721a36ea59b7"}, - {file = "fonttools-4.48.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee76fd81a8571c68841d6ef0da750d5ff08ff2c5f025576473016f16ac3bcf7"}, - {file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5057ade278e67923000041e2b195c9ea53e87f227690d499b6a4edd3702f7f01"}, - {file = "fonttools-4.48.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b10633aafc5932995a391ec07eba5e79f52af0003a1735b2306b3dab8a056d48"}, - {file = "fonttools-4.48.1-cp311-cp311-win32.whl", hash = "sha256:0d533f89819f9b3ee2dbedf0fed3825c425850e32bdda24c558563c71be0064e"}, - {file = "fonttools-4.48.1-cp311-cp311-win_amd64.whl", hash = "sha256:d20588466367f05025bb1efdf4e5d498ca6d14bde07b6928b79199c588800f0a"}, - {file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0a2417547462e468edf35b32e3dd06a6215ac26aa6316b41e03b8eeaf9f079ea"}, - {file = "fonttools-4.48.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cf5a0cd974f85a80b74785db2d5c3c1fd6cc09a2ba3c837359b2b5da629ee1b0"}, - {file = "fonttools-4.48.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0452fcbfbce752ba596737a7c5ec5cf76bc5f83847ce1781f4f90eab14ece252"}, - {file = "fonttools-4.48.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578c00f93868f64a4102ecc5aa600a03b49162c654676c3fadc33de2ddb88a81"}, - {file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:63dc592a16cd08388d8c4c7502b59ac74190b23e16dfc863c69fe1ea74605b68"}, - {file = "fonttools-4.48.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9b58638d8a85e3a1b32ec0a91d9f8171a877b4b81c408d4cb3257d0dee63e092"}, - {file = "fonttools-4.48.1-cp312-cp312-win32.whl", hash = "sha256:d10979ef14a8beaaa32f613bb698743f7241d92f437a3b5e32356dfb9769c65d"}, - {file = "fonttools-4.48.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdfd7557d1bd294a200bd211aa665ca3b02998dcc18f8211a5532da5b8fad5c5"}, - {file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3cdb9a92521b81bf717ebccf592bd0292e853244d84115bfb4db0c426de58348"}, - {file = "fonttools-4.48.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b4ec6d42a7555f5ae35f3b805482f0aad0f1baeeef54859492ea3b782959d4a"}, - {file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:902e9c4e9928301912f34a6638741b8ae0b64824112b42aaf240e06b735774b1"}, - {file = "fonttools-4.48.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8c8b54bd1420c184a995f980f1a8076f87363e2bb24239ef8c171a369d85a31"}, - {file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:12ee86abca46193359ea69216b3a724e90c66ab05ab220d39e3fc068c1eb72ac"}, - {file = "fonttools-4.48.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6978bade7b6c0335095bdd0bd97f8f3d590d2877b370f17e03e0865241694eb5"}, - {file = "fonttools-4.48.1-cp38-cp38-win32.whl", hash = "sha256:bcd77f89fc1a6b18428e7a55dde8ef56dae95640293bfb8f4e929929eba5e2a2"}, - {file = "fonttools-4.48.1-cp38-cp38-win_amd64.whl", hash = "sha256:f40441437b039930428e04fb05ac3a132e77458fb57666c808d74a556779e784"}, - {file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0d2b01428f7da26f229a5656defc824427b741e454b4e210ad2b25ed6ea2aed4"}, - {file = "fonttools-4.48.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:df48798f9a4fc4c315ab46e17873436c8746f5df6eddd02fad91299b2af7af95"}, - {file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2eb4167bde04e172a93cf22c875d8b0cff76a2491f67f5eb069566215302d45d"}, - {file = "fonttools-4.48.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c900508c46274d32d308ae8e82335117f11aaee1f7d369ac16502c9a78930b0a"}, - {file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:594206b31c95fcfa65f484385171fabb4ec69f7d2d7f56d27f17db26b7a31814"}, - {file = "fonttools-4.48.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:292922dc356d7f11f5063b4111a8b719efb8faea92a2a88ed296408d449d8c2e"}, - {file = "fonttools-4.48.1-cp39-cp39-win32.whl", hash = "sha256:4709c5bf123ba10eac210d2d5c9027d3f472591d9f1a04262122710fa3d23199"}, - {file = "fonttools-4.48.1-cp39-cp39-win_amd64.whl", hash = "sha256:63c73b9dd56a94a3cbd2f90544b5fca83666948a9e03370888994143b8d7c070"}, - {file = "fonttools-4.48.1-py3-none-any.whl", hash = "sha256:e3e33862fc5261d46d9aae3544acb36203b1a337d00bdb5d3753aae50dac860e"}, - {file = "fonttools-4.48.1.tar.gz", hash = "sha256:8b8a45254218679c7f1127812761e7854ed5c8e34349aebf581e8c9204e7495a"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d970ecca0aac90d399e458f0b7a8a597e08f95de021f17785fb68e2dc0b99717"}, + {file = "fonttools-4.49.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac9a745b7609f489faa65e1dc842168c18530874a5f5b742ac3dd79e26bca8bc"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ba0e00620ca28d4ca11fc700806fd69144b463aa3275e1b36e56c7c09915559"}, + {file = "fonttools-4.49.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdee3ab220283057e7840d5fb768ad4c2ebe65bdba6f75d5d7bf47f4e0ed7d29"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ce7033cb61f2bb65d8849658d3786188afd80f53dad8366a7232654804529532"}, + {file = "fonttools-4.49.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:07bc5ea02bb7bc3aa40a1eb0481ce20e8d9b9642a9536cde0218290dd6085828"}, + {file = "fonttools-4.49.0-cp310-cp310-win32.whl", hash = "sha256:86eef6aab7fd7c6c8545f3ebd00fd1d6729ca1f63b0cb4d621bccb7d1d1c852b"}, + {file = "fonttools-4.49.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fac1b7eebfce75ea663e860e7c5b4a8831b858c17acd68263bc156125201abf"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:edc0cce355984bb3c1d1e89d6a661934d39586bb32191ebff98c600f8957c63e"}, + {file = "fonttools-4.49.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:83a0d9336de2cba86d886507dd6e0153df333ac787377325a39a2797ec529814"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36c8865bdb5cfeec88f5028e7e592370a0657b676c6f1d84a2108e0564f90e22"}, + {file = "fonttools-4.49.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33037d9e56e2562c710c8954d0f20d25b8386b397250d65581e544edc9d6b942"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8fb022d799b96df3eaa27263e9eea306bd3d437cc9aa981820850281a02b6c9a"}, + {file = "fonttools-4.49.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33c584c0ef7dc54f5dd4f84082eabd8d09d1871a3d8ca2986b0c0c98165f8e86"}, + {file = "fonttools-4.49.0-cp311-cp311-win32.whl", hash = "sha256:cbe61b158deb09cffdd8540dc4a948d6e8f4d5b4f3bf5cd7db09bd6a61fee64e"}, + {file = "fonttools-4.49.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc11e5114f3f978d0cea7e9853627935b30d451742eeb4239a81a677bdee6bf6"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d647a0e697e5daa98c87993726da8281c7233d9d4ffe410812a4896c7c57c075"}, + {file = "fonttools-4.49.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f3bbe672df03563d1f3a691ae531f2e31f84061724c319652039e5a70927167e"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bebd91041dda0d511b0d303180ed36e31f4f54b106b1259b69fade68413aa7ff"}, + {file = "fonttools-4.49.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4145f91531fd43c50f9eb893faa08399816bb0b13c425667c48475c9f3a2b9b5"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ea329dafb9670ffbdf4dbc3b0e5c264104abcd8441d56de77f06967f032943cb"}, + {file = "fonttools-4.49.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c076a9e548521ecc13d944b1d261ff3d7825048c338722a4bd126d22316087b7"}, + {file = "fonttools-4.49.0-cp312-cp312-win32.whl", hash = "sha256:b607ea1e96768d13be26d2b400d10d3ebd1456343eb5eaddd2f47d1c4bd00880"}, + {file = "fonttools-4.49.0-cp312-cp312-win_amd64.whl", hash = "sha256:a974c49a981e187381b9cc2c07c6b902d0079b88ff01aed34695ec5360767034"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b85ec0bdd7bdaa5c1946398cbb541e90a6dfc51df76dfa88e0aaa41b335940cb"}, + {file = "fonttools-4.49.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:af20acbe198a8a790618ee42db192eb128afcdcc4e96d99993aca0b60d1faeb4"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d418b1fee41a1d14931f7ab4b92dc0bc323b490e41d7a333eec82c9f1780c75"}, + {file = "fonttools-4.49.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b44a52b8e6244b6548851b03b2b377a9702b88ddc21dcaf56a15a0393d425cb9"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7c7125068e04a70739dad11857a4d47626f2b0bd54de39e8622e89701836eabd"}, + {file = "fonttools-4.49.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29e89d0e1a7f18bc30f197cfadcbef5a13d99806447c7e245f5667579a808036"}, + {file = "fonttools-4.49.0-cp38-cp38-win32.whl", hash = "sha256:9d95fa0d22bf4f12d2fb7b07a46070cdfc19ef5a7b1c98bc172bfab5bf0d6844"}, + {file = "fonttools-4.49.0-cp38-cp38-win_amd64.whl", hash = "sha256:768947008b4dc552d02772e5ebd49e71430a466e2373008ce905f953afea755a"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:08877e355d3dde1c11973bb58d4acad1981e6d1140711230a4bfb40b2b937ccc"}, + {file = "fonttools-4.49.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fdb54b076f25d6b0f0298dc706acee5052de20c83530fa165b60d1f2e9cbe3cb"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0af65c720520710cc01c293f9c70bd69684365c6015cc3671db2b7d807fe51f2"}, + {file = "fonttools-4.49.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f255ce8ed7556658f6d23f6afd22a6d9bbc3edb9b96c96682124dc487e1bf42"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d00af0884c0e65f60dfaf9340e26658836b935052fdd0439952ae42e44fdd2be"}, + {file = "fonttools-4.49.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:263832fae27481d48dfafcc43174644b6706639661e242902ceb30553557e16c"}, + {file = "fonttools-4.49.0-cp39-cp39-win32.whl", hash = "sha256:0404faea044577a01bb82d47a8fa4bc7a54067fa7e324785dd65d200d6dd1133"}, + {file = "fonttools-4.49.0-cp39-cp39-win_amd64.whl", hash = "sha256:b050d362df50fc6e38ae3954d8c29bf2da52be384649ee8245fdb5186b620836"}, + {file = "fonttools-4.49.0-py3-none-any.whl", hash = "sha256:af281525e5dd7fa0b39fb1667b8d5ca0e2a9079967e14c4bfe90fd1cd13e0f18"}, + {file = "fonttools-4.49.0.tar.gz", hash = "sha256:ebf46e7f01b7af7861310417d7c49591a85d99146fc23a5ba82fdb28af156321"}, ] [package.extras] @@ -529,77 +564,6 @@ ufo = ["fs (>=2.2.0,<3)"] unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] -[[package]] -name = "greenlet" -version = "3.0.3" -description = "Lightweight in-process concurrent programming" -optional = false -python-versions = ">=3.7" -files = [ - {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"}, - {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"}, - {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"}, - {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"}, - {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"}, - {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"}, - {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"}, - {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"}, - {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"}, - {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"}, - {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"}, - {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"}, - {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"}, - {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"}, - {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"}, - {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"}, - {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"}, - {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"}, - {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"}, - {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"}, - {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"}, - {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"}, - {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"}, - {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"}, - {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"}, - {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"}, - {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"}, - {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"}, -] - -[package.extras] -docs = ["Sphinx", "furo"] -test = ["objgraph", "psutil"] - [[package]] name = "h11" version = "0.14.0" @@ -613,13 +577,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.2" +version = "1.0.4" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.2-py3-none-any.whl", hash = "sha256:096cc05bca73b8e459a1fc3dcf585148f63e534eae4339559c9b8a8d6399acc7"}, - {file = "httpcore-1.0.2.tar.gz", hash = "sha256:9fc092e4799b26174648e54b74ed5f683132a464e95643b226e00c2ed2fa6535"}, + {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, + {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, ] [package.dependencies] @@ -630,7 +594,7 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.23.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [[package]] name = "httptools" @@ -682,13 +646,13 @@ test = ["Cython (>=0.29.24,<0.30.0)"] [[package]] name = "httpx" -version = "0.26.0" +version = "0.27.0" description = "The next generation HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpx-0.26.0-py3-none-any.whl", hash = "sha256:8915f5a3627c4d47b73e8202457cb28f1266982d1159bd5779d86a80c0eab1cd"}, - {file = "httpx-0.26.0.tar.gz", hash = "sha256:451b55c30d5185ea6b23c2c793abf9bb237d2a7dfb901ced6ff69ad37ec1dfaf"}, + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, ] [package.dependencies] @@ -706,13 +670,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "identify" -version = "2.5.34" +version = "2.5.35" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.34-py2.py3-none-any.whl", hash = "sha256:a4316013779e433d08b96e5eabb7f641e6c7942e4ab5d4c509ebd2e7a8994aed"}, - {file = "identify-2.5.34.tar.gz", hash = "sha256:ee17bc9d499899bc9eaec1ac7bf2dc9eedd480db9d88b96d123d3b64a9d34f5d"}, + {file = "identify-2.5.35-py2.py3-none-any.whl", hash = "sha256:c4de0081837b211594f8e877a6b4fad7ca32bbfc1a9307fdd61c28bfe923f13e"}, + {file = "identify-2.5.35.tar.gz", hash = "sha256:10a7ca245cfcd756a554a7288159f72ff105ad233c7c4b9c6f0f4d108f5f6791"}, ] [package.extras] @@ -974,39 +938,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.2" +version = "3.8.3" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, - {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, - {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, - {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, - {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, - {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, - {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, - {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, - {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, - {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, - {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, - {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, - {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, - {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, - {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, - {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, - {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, - {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, - {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cf60138ccc8004f117ab2a2bad513cc4d122e55864b4fe7adf4db20ca68a078f"}, + {file = "matplotlib-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f557156f7116be3340cdeef7f128fa99b0d5d287d5f41a16e169819dcf22357"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f386cf162b059809ecfac3bcc491a9ea17da69fa35c8ded8ad154cd4b933d5ec"}, + {file = "matplotlib-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3c5f96f57b0369c288bf6f9b5274ba45787f7e0589a34d24bdbaf6d3344632f"}, + {file = "matplotlib-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:83e0f72e2c116ca7e571c57aa29b0fe697d4c6425c4e87c6e994159e0c008635"}, + {file = "matplotlib-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:1c5c8290074ba31a41db1dc332dc2b62def469ff33766cbe325d32a3ee291aea"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:5184e07c7e1d6d1481862ee361905b7059f7fe065fc837f7c3dc11eeb3f2f900"}, + {file = "matplotlib-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7e7e0993d0758933b1a241a432b42c2db22dfa37d4108342ab4afb9557cbe3e"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04b36ad07eac9740fc76c2aa16edf94e50b297d6eb4c081e3add863de4bb19a7"}, + {file = "matplotlib-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c42dae72a62f14982f1474f7e5c9959fc4bc70c9de11cc5244c6e766200ba65"}, + {file = "matplotlib-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf5932eee0d428192c40b7eac1399d608f5d995f975cdb9d1e6b48539a5ad8d0"}, + {file = "matplotlib-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:40321634e3a05ed02abf7c7b47a50be50b53ef3eaa3a573847431a545585b407"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:09074f8057917d17ab52c242fdf4916f30e99959c1908958b1fc6032e2d0f6d4"}, + {file = "matplotlib-3.8.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5745f6d0fb5acfabbb2790318db03809a253096e98c91b9a31969df28ee604aa"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97653d869a71721b639714b42d87cda4cfee0ee74b47c569e4874c7590c55c5"}, + {file = "matplotlib-3.8.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:242489efdb75b690c9c2e70bb5c6550727058c8a614e4c7716f363c27e10bba1"}, + {file = "matplotlib-3.8.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:83c0653c64b73926730bd9ea14aa0f50f202ba187c307a881673bad4985967b7"}, + {file = "matplotlib-3.8.3-cp312-cp312-win_amd64.whl", hash = "sha256:ef6c1025a570354297d6c15f7d0f296d95f88bd3850066b7f1e7b4f2f4c13a39"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c4af3f7317f8a1009bbb2d0bf23dfaba859eb7dd4ccbd604eba146dccaaaf0a4"}, + {file = "matplotlib-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c6e00a65d017d26009bac6808f637b75ceade3e1ff91a138576f6b3065eeeba"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7b49ab49a3bea17802df6872f8d44f664ba8f9be0632a60c99b20b6db2165b7"}, + {file = "matplotlib-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6728dde0a3997396b053602dbd907a9bd64ec7d5cf99e728b404083698d3ca01"}, + {file = "matplotlib-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:813925d08fb86aba139f2d31864928d67511f64e5945ca909ad5bc09a96189bb"}, + {file = "matplotlib-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:cd3a0c2be76f4e7be03d34a14d49ded6acf22ef61f88da600a18a5cd8b3c5f3c"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fa93695d5c08544f4a0dfd0965f378e7afc410d8672816aff1e81be1f45dbf2e"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9764df0e8778f06414b9d281a75235c1e85071f64bb5d71564b97c1306a2afc"}, + {file = "matplotlib-3.8.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5e431a09e6fab4012b01fc155db0ce6dccacdbabe8198197f523a4ef4805eb26"}, + {file = "matplotlib-3.8.3.tar.gz", hash = "sha256:7b416239e9ae38be54b028abbf9048aff5054a9aba5416bef0bd17f9162ce161"}, ] [package.dependencies] @@ -1020,6 +984,63 @@ pillow = ">=8" pyparsing = ">=2.3.1" python-dateutil = ">=2.7" +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.8.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"}, + {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"}, + {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"}, + {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"}, + {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"}, + {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"}, + {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"}, + {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"}, + {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"}, + {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"}, + {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"}, + {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"}, + {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"}, + {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"}, + {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"}, + {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"}, + {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"}, + {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"}, + {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"}, + {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"}, + {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"}, + {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"}, + {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + [[package]] name = "mypy-extensions" version = "1.0.0" @@ -1103,40 +1124,40 @@ files = [ [[package]] name = "pandas" -version = "2.2.0" +version = "2.2.1" description = "Powerful data structures for data analysis, time series, and statistics" optional = false python-versions = ">=3.9" files = [ - {file = "pandas-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8108ee1712bb4fa2c16981fba7e68b3f6ea330277f5ca34fa8d557e986a11670"}, - {file = "pandas-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:736da9ad4033aeab51d067fc3bd69a0ba36f5a60f66a527b3d72e2030e63280a"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e0b4fc3ddceb56ec8a287313bc22abe17ab0eb184069f08fc6a9352a769b18"}, - {file = "pandas-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20404d2adefe92aed3b38da41d0847a143a09be982a31b85bc7dd565bdba0f4e"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7ea3ee3f125032bfcade3a4cf85131ed064b4f8dd23e5ce6fa16473e48ebcaf5"}, - {file = "pandas-2.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9670b3ac00a387620489dfc1bca66db47a787f4e55911f1293063a78b108df1"}, - {file = "pandas-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a946f210383c7e6d16312d30b238fd508d80d927014f3b33fb5b15c2f895430"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a1b438fa26b208005c997e78672f1aa8138f67002e833312e6230f3e57fa87d5"}, - {file = "pandas-2.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8ce2fbc8d9bf303ce54a476116165220a1fedf15985b09656b4b4275300e920b"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2707514a7bec41a4ab81f2ccce8b382961a29fbe9492eab1305bb075b2b1ff4f"}, - {file = "pandas-2.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85793cbdc2d5bc32620dc8ffa715423f0c680dacacf55056ba13454a5be5de88"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cfd6c2491dc821b10c716ad6776e7ab311f7df5d16038d0b7458bc0b67dc10f3"}, - {file = "pandas-2.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a146b9dcacc3123aa2b399df1a284de5f46287a4ab4fbfc237eac98a92ebcb71"}, - {file = "pandas-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:fbc1b53c0e1fdf16388c33c3cca160f798d38aea2978004dd3f4d3dec56454c9"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a41d06f308a024981dcaa6c41f2f2be46a6b186b902c94c2674e8cb5c42985bc"}, - {file = "pandas-2.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:159205c99d7a5ce89ecfc37cb08ed179de7783737cea403b295b5eda8e9c56d1"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1e1f3861ea9132b32f2133788f3b14911b68102d562715d71bd0013bc45440"}, - {file = "pandas-2.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:761cb99b42a69005dec2b08854fb1d4888fdf7b05db23a8c5a099e4b886a2106"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a20628faaf444da122b2a64b1e5360cde100ee6283ae8effa0d8745153809a2e"}, - {file = "pandas-2.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f5be5d03ea2073627e7111f61b9f1f0d9625dc3c4d8dda72cc827b0c58a1d042"}, - {file = "pandas-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a626795722d893ed6aacb64d2401d017ddc8a2341b49e0384ab9bf7112bdec30"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9f66419d4a41132eb7e9a73dcec9486cf5019f52d90dd35547af11bc58f8637d"}, - {file = "pandas-2.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:57abcaeda83fb80d447f28ab0cc7b32b13978f6f733875ebd1ed14f8fbc0f4ab"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e60f1f7dba3c2d5ca159e18c46a34e7ca7247a73b5dd1a22b6d59707ed6b899a"}, - {file = "pandas-2.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb61dc8567b798b969bcc1fc964788f5a68214d333cade8319c7ab33e2b5d88a"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52826b5f4ed658fa2b729264d63f6732b8b29949c7fd234510d57c61dbeadfcd"}, - {file = "pandas-2.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bde2bc699dbd80d7bc7f9cab1e23a95c4375de615860ca089f34e7c64f4a8de7"}, - {file = "pandas-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:3de918a754bbf2da2381e8a3dcc45eede8cd7775b047b923f9006d5f876802ae"}, - {file = "pandas-2.2.0.tar.gz", hash = "sha256:30b83f7c3eb217fb4d1b494a57a2fda5444f17834f5df2de6b2ffff68dc3c8e2"}, + {file = "pandas-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8df8612be9cd1c7797c93e1c5df861b2ddda0b48b08f2c3eaa0702cf88fb5f88"}, + {file = "pandas-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0f573ab277252ed9aaf38240f3b54cfc90fff8e5cab70411ee1d03f5d51f3944"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f02a3a6c83df4026e55b63c1f06476c9aa3ed6af3d89b4f04ea656ccdaaaa359"}, + {file = "pandas-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c38ce92cb22a4bea4e3929429aa1067a454dcc9c335799af93ba9be21b6beb51"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c2ce852e1cf2509a69e98358e8458775f89599566ac3775e70419b98615f4b06"}, + {file = "pandas-2.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53680dc9b2519cbf609c62db3ed7c0b499077c7fefda564e330286e619ff0dd9"}, + {file = "pandas-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:94e714a1cca63e4f5939cdce5f29ba8d415d85166be3441165edd427dc9f6bc0"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f821213d48f4ab353d20ebc24e4faf94ba40d76680642fb7ce2ea31a3ad94f9b"}, + {file = "pandas-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c70e00c2d894cb230e5c15e4b1e1e6b2b478e09cf27cc593a11ef955b9ecc81a"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97fbb5387c69209f134893abc788a6486dbf2f9e511070ca05eed4b930b1b02"}, + {file = "pandas-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101d0eb9c5361aa0146f500773395a03839a5e6ecde4d4b6ced88b7e5a1a6403"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7d2ed41c319c9fb4fd454fe25372028dfa417aacb9790f68171b2e3f06eae8cd"}, + {file = "pandas-2.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:af5d3c00557d657c8773ef9ee702c61dd13b9d7426794c9dfeb1dc4a0bf0ebc7"}, + {file = "pandas-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:06cf591dbaefb6da9de8472535b185cba556d0ce2e6ed28e21d919704fef1a9e"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:88ecb5c01bb9ca927ebc4098136038519aa5d66b44671861ffab754cae75102c"}, + {file = "pandas-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:04f6ec3baec203c13e3f8b139fb0f9f86cd8c0b94603ae3ae8ce9a422e9f5bee"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a935a90a76c44fe170d01e90a3594beef9e9a6220021acfb26053d01426f7dc2"}, + {file = "pandas-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c391f594aae2fd9f679d419e9a4d5ba4bce5bb13f6a989195656e7dc4b95c8f0"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9d1265545f579edf3f8f0cb6f89f234f5e44ba725a34d86535b1a1d38decbccc"}, + {file = "pandas-2.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:11940e9e3056576ac3244baef2fedade891977bcc1cb7e5cc8f8cc7d603edc89"}, + {file = "pandas-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acf681325ee1c7f950d058b05a820441075b0dd9a2adf5c4835b9bc056bf4fb"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9bd8a40f47080825af4317d0340c656744f2bfdb6819f818e6ba3cd24c0e1397"}, + {file = "pandas-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:df0c37ebd19e11d089ceba66eba59a168242fc6b7155cba4ffffa6eccdfb8f16"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:739cc70eaf17d57608639e74d63387b0d8594ce02f69e7a0b046f117974b3019"}, + {file = "pandas-2.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9d3558d263073ed95e46f4650becff0c5e1ffe0fc3a015de3c79283dfbdb3df"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4aa1d8707812a658debf03824016bf5ea0d516afdea29b7dc14cf687bc4d4ec6"}, + {file = "pandas-2.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:76f27a809cda87e07f192f001d11adc2b930e93a2b0c4a236fde5429527423be"}, + {file = "pandas-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:1ba21b1d5c0e43416218db63037dbe1a01fc101dc6e6024bcad08123e48004ab"}, + {file = "pandas-2.2.1.tar.gz", hash = "sha256:0ab90f87093c13f3e8fa45b48ba9f39181046e8f3317d3aadb2fffbb1b978572"}, ] [package.dependencies] @@ -1164,6 +1185,7 @@ parquet = ["pyarrow (>=10.0.1)"] performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"] plot = ["matplotlib (>=3.6.3)"] postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"] +pyarrow = ["pyarrow (>=10.0.1)"] spss = ["pyreadstat (>=1.2.0)"] sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"] test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] @@ -1297,13 +1319,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.6.1" +version = "3.6.2" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-3.6.1-py2.py3-none-any.whl", hash = "sha256:9fe989afcf095d2c4796ce7c553cf28d4d4a9b9346de3cda079bcf40748454a4"}, - {file = "pre_commit-3.6.1.tar.gz", hash = "sha256:c90961d8aa706f75d60935aba09469a6b0bcb8345f127c3fbee4bdc5f114cf4b"}, + {file = "pre_commit-3.6.2-py2.py3-none-any.whl", hash = "sha256:ba637c2d7a670c10daedc059f5c49b5bd0aadbccfcd7ec15592cf9665117532c"}, + {file = "pre_commit-3.6.2.tar.gz", hash = "sha256:c3ef34f463045c88658c5b99f38c1e297abdcc0ff13f98d3370055fbbfabc67e"}, ] [package.dependencies] @@ -1329,55 +1351,148 @@ wcwidth = "*" [[package]] name = "pydantic" -version = "1.10.14" -description = "Data validation and settings management using python type hints" +version = "2.6.2" +description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-1.10.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7f4fcec873f90537c382840f330b90f4715eebc2bc9925f04cb92de593eae054"}, - {file = "pydantic-1.10.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e3a76f571970fcd3c43ad982daf936ae39b3e90b8a2e96c04113a369869dc87"}, - {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d886bd3c3fbeaa963692ef6b643159ccb4b4cefaf7ff1617720cbead04fd1d"}, - {file = "pydantic-1.10.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:798a3d05ee3b71967844a1164fd5bdb8c22c6d674f26274e78b9f29d81770c4e"}, - {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:23d47a4b57a38e8652bcab15a658fdb13c785b9ce217cc3a729504ab4e1d6bc9"}, - {file = "pydantic-1.10.14-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f9f674b5c3bebc2eba401de64f29948ae1e646ba2735f884d1594c5f675d6f2a"}, - {file = "pydantic-1.10.14-cp310-cp310-win_amd64.whl", hash = "sha256:24a7679fab2e0eeedb5a8924fc4a694b3bcaac7d305aeeac72dd7d4e05ecbebf"}, - {file = "pydantic-1.10.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d578ac4bf7fdf10ce14caba6f734c178379bd35c486c6deb6f49006e1ba78a7"}, - {file = "pydantic-1.10.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa7790e94c60f809c95602a26d906eba01a0abee9cc24150e4ce2189352deb1b"}, - {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aad4e10efa5474ed1a611b6d7f0d130f4aafadceb73c11d9e72823e8f508e663"}, - {file = "pydantic-1.10.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245f4f61f467cb3dfeced2b119afef3db386aec3d24a22a1de08c65038b255f"}, - {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:21efacc678a11114c765eb52ec0db62edffa89e9a562a94cbf8fa10b5db5c046"}, - {file = "pydantic-1.10.14-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:412ab4a3f6dbd2bf18aefa9f79c7cca23744846b31f1d6555c2ee2b05a2e14ca"}, - {file = "pydantic-1.10.14-cp311-cp311-win_amd64.whl", hash = "sha256:e897c9f35281f7889873a3e6d6b69aa1447ceb024e8495a5f0d02ecd17742a7f"}, - {file = "pydantic-1.10.14-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d604be0f0b44d473e54fdcb12302495fe0467c56509a2f80483476f3ba92b33c"}, - {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42c7d17706911199798d4c464b352e640cab4351efe69c2267823d619a937e5"}, - {file = "pydantic-1.10.14-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:596f12a1085e38dbda5cbb874d0973303e34227b400b6414782bf205cc14940c"}, - {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bfb113860e9288d0886e3b9e49d9cf4a9d48b441f52ded7d96db7819028514cc"}, - {file = "pydantic-1.10.14-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:bc3ed06ab13660b565eed80887fcfbc0070f0aa0691fbb351657041d3e874efe"}, - {file = "pydantic-1.10.14-cp37-cp37m-win_amd64.whl", hash = "sha256:ad8c2bc677ae5f6dbd3cf92f2c7dc613507eafe8f71719727cbc0a7dec9a8c01"}, - {file = "pydantic-1.10.14-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c37c28449752bb1f47975d22ef2882d70513c546f8f37201e0fec3a97b816eee"}, - {file = "pydantic-1.10.14-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49a46a0994dd551ec051986806122767cf144b9702e31d47f6d493c336462597"}, - {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53e3819bd20a42470d6dd0fe7fc1c121c92247bca104ce608e609b59bc7a77ee"}, - {file = "pydantic-1.10.14-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbb503bbbbab0c588ed3cd21975a1d0d4163b87e360fec17a792f7d8c4ff29f"}, - {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:336709883c15c050b9c55a63d6c7ff09be883dbc17805d2b063395dd9d9d0022"}, - {file = "pydantic-1.10.14-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4ae57b4d8e3312d486e2498d42aed3ece7b51848336964e43abbf9671584e67f"}, - {file = "pydantic-1.10.14-cp38-cp38-win_amd64.whl", hash = "sha256:dba49d52500c35cfec0b28aa8b3ea5c37c9df183ffc7210b10ff2a415c125c4a"}, - {file = "pydantic-1.10.14-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c66609e138c31cba607d8e2a7b6a5dc38979a06c900815495b2d90ce6ded35b4"}, - {file = "pydantic-1.10.14-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d986e115e0b39604b9eee3507987368ff8148222da213cd38c359f6f57b3b347"}, - {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:646b2b12df4295b4c3148850c85bff29ef6d0d9621a8d091e98094871a62e5c7"}, - {file = "pydantic-1.10.14-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282613a5969c47c83a8710cc8bfd1e70c9223feb76566f74683af889faadc0ea"}, - {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:466669501d08ad8eb3c4fecd991c5e793c4e0bbd62299d05111d4f827cded64f"}, - {file = "pydantic-1.10.14-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:13e86a19dca96373dcf3190fcb8797d40a6f12f154a244a8d1e8e03b8f280593"}, - {file = "pydantic-1.10.14-cp39-cp39-win_amd64.whl", hash = "sha256:08b6ec0917c30861e3fe71a93be1648a2aa4f62f866142ba21670b24444d7fd8"}, - {file = "pydantic-1.10.14-py3-none-any.whl", hash = "sha256:8ee853cd12ac2ddbf0ecbac1c289f95882b2d4482258048079d13be700aa114c"}, - {file = "pydantic-1.10.14.tar.gz", hash = "sha256:46f17b832fe27de7850896f3afee50ea682220dd218f7e9c88d436788419dca6"}, + {file = "pydantic-2.6.2-py3-none-any.whl", hash = "sha256:37a5432e54b12fecaa1049c5195f3d860a10e01bdfd24f1840ef14bd0d3aeab3"}, + {file = "pydantic-2.6.2.tar.gz", hash = "sha256:a09be1c3d28f3abe37f8a78af58284b236a92ce520105ddc91a6d29ea1176ba7"}, ] [package.dependencies] -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.16.3" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.16.3" +description = "" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pyflakes" +version = "3.2.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, + {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, +] + +[[package]] +name = "pylint" +version = "3.1.0" +description = "python code static checker" +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "pylint-3.1.0-py3-none-any.whl", hash = "sha256:507a5b60953874766d8a366e8e8c7af63e058b26345cfcb5f91f89d987fd6b74"}, + {file = "pylint-3.1.0.tar.gz", hash = "sha256:6a69beb4a6f63debebaab0a3477ecd0f559aa726af4954fc948c51f7a2549e23"}, +] + +[package.dependencies] +astroid = ">=3.1.0,<=3.2.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = {version = ">=0.3.7", markers = "python_version >= \"3.12\""} +isort = ">=4.2.5,<5.13.0 || >5.13.0,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomlkit = ">=0.10.1" + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] [[package]] name = "pyparsing" @@ -1393,15 +1508,30 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyproject-autoflake" +version = "1.0.2" +description = "pyproject-autoflake (pautoflake), a monkey patching wrapper to connect autoflake with pyproject.toml configuration." +optional = false +python-versions = ">=3.6.2,<4.0.0" +files = [ + {file = "pyproject-autoflake-1.0.2.tar.gz", hash = "sha256:7ad1ab8c8e522bd04f05728f2656935853288b7b974a47850174c6cf6cc378ad"}, + {file = "pyproject_autoflake-1.0.2-py3-none-any.whl", hash = "sha256:db7220bec762cbc8cfe93f1d23f3a564d0c076529bc1ebafc2dcb023c5ee265c"}, +] + +[package.dependencies] +autoflake = "*" +toml = ">=0.10.1" + [[package]] name = "pytest" -version = "8.0.0" +version = "8.0.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.0.0-py3-none-any.whl", hash = "sha256:50fb9cbe836c3f20f0dfa99c565201fb75dc54c8d76373cd1bde06b06657bdb6"}, - {file = "pytest-8.0.0.tar.gz", hash = "sha256:249b1b0864530ba251b7438274c4d251c58d868edaaec8762893ad4a0d71c36c"}, + {file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"}, + {file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"}, ] [package.dependencies] @@ -1477,7 +1607,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -1651,13 +1780,13 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "requests-cache" -version = "1.1.1" +version = "1.2.0" description = "A persistent cache for python requests" optional = false -python-versions = ">=3.7,<4.0" +python-versions = ">=3.8" files = [ - {file = "requests_cache-1.1.1-py3-none-any.whl", hash = "sha256:c8420cf096f3aafde13c374979c21844752e2694ffd8710e6764685bb577ac90"}, - {file = "requests_cache-1.1.1.tar.gz", hash = "sha256:764f93d3fa860be72125a568c2cc8eafb151cf29b4dc2515433a56ee657e1c60"}, + {file = "requests_cache-1.2.0-py3-none-any.whl", hash = "sha256:490324301bf0cb924ff4e6324bd2613453e7e1f847353928b08adb0fdfb7f722"}, + {file = "requests_cache-1.2.0.tar.gz", hash = "sha256:db1c709ca343cc1cd5b6c8b1a5387298eceed02306a6040760db538c885e3838"}, ] [package.dependencies] @@ -1669,15 +1798,15 @@ url-normalize = ">=1.4" urllib3 = ">=1.25.5" [package.extras] -all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=5.4)", "redis (>=3)", "ujson (>=5.4)"] +all = ["boto3 (>=1.15)", "botocore (>=1.18)", "itsdangerous (>=2.0)", "pymongo (>=3)", "pyyaml (>=6.0.1)", "redis (>=3)", "ujson (>=5.4)"] bson = ["bson (>=0.5)"] -docs = ["furo (>=2023.3,<2024.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.6)"] +docs = ["furo (>=2023.3,<2024.0)", "linkify-it-py (>=2.0,<3.0)", "myst-parser (>=1.0,<2.0)", "sphinx (>=5.0.2,<6.0.0)", "sphinx-autodoc-typehints (>=1.19)", "sphinx-automodapi (>=0.14)", "sphinx-copybutton (>=0.5)", "sphinx-design (>=0.2)", "sphinx-notfound-page (>=0.8)", "sphinxcontrib-apidoc (>=0.3)", "sphinxext-opengraph (>=0.9)"] dynamodb = ["boto3 (>=1.15)", "botocore (>=1.18)"] json = ["ujson (>=5.4)"] mongodb = ["pymongo (>=3)"] redis = ["redis (>=3)"] security = ["itsdangerous (>=2.0)"] -yaml = ["pyyaml (>=5.4)"] +yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "scipy" @@ -1723,19 +1852,19 @@ test = ["asv", "gmpy2", "hypothesis", "mpmath", "pooch", "pytest", "pytest-cov", [[package]] name = "setuptools" -version = "69.0.3" +version = "69.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "setuptools-69.1.1-py3-none-any.whl", hash = "sha256:02fa291a0471b3a18b2b2481ed902af520c69e8ae0919c13da936542754b4c56"}, + {file = "setuptools-69.1.1.tar.gz", hash = "sha256:5c0806c7d9af348e6dd3777b4f4dbb42c7ad85b190104837488eab9a7c945cf8"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1750,94 +1879,15 @@ files = [ [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, -] - -[[package]] -name = "sqlalchemy" -version = "1.4.51" -description = "Database Abstraction Library" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "SQLAlchemy-1.4.51-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:1a09d5bd1a40d76ad90e5570530e082ddc000e1d92de495746f6257dc08f166b"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2be4e6294c53f2ec8ea36486b56390e3bcaa052bf3a9a47005687ccf376745d1"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca484ca11c65e05639ffe80f20d45e6be81fbec7683d6c9a15cd421e6e8b340"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0535d5b57d014d06ceeaeffd816bb3a6e2dddeb670222570b8c4953e2d2ea678"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af55cc207865d641a57f7044e98b08b09220da3d1b13a46f26487cc2f898a072"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-win32.whl", hash = "sha256:7af40425ac535cbda129d9915edcaa002afe35d84609fd3b9d6a8c46732e02ee"}, - {file = "SQLAlchemy-1.4.51-cp310-cp310-win_amd64.whl", hash = "sha256:8d1d7d63e5d2f4e92a39ae1e897a5d551720179bb8d1254883e7113d3826d43c"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eaeeb2464019765bc4340214fca1143081d49972864773f3f1e95dba5c7edc7d"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7deeae5071930abb3669b5185abb6c33ddfd2398f87660fafdb9e6a5fb0f3f2f"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0892e7ac8bc76da499ad3ee8de8da4d7905a3110b952e2a35a940dab1ffa550e"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-win32.whl", hash = "sha256:50e074aea505f4427151c286955ea025f51752fa42f9939749336672e0674c81"}, - {file = "SQLAlchemy-1.4.51-cp311-cp311-win_amd64.whl", hash = "sha256:3b0cd89a7bd03f57ae58263d0f828a072d1b440c8c2949f38f3b446148321171"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a33cb3f095e7d776ec76e79d92d83117438b6153510770fcd57b9c96f9ef623d"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cacc0b2dd7d22a918a9642fc89840a5d3cee18a0e1fe41080b1141b23b10916"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:245c67c88e63f1523e9216cad6ba3107dea2d3ee19adc359597a628afcabfbcb"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-win32.whl", hash = "sha256:8e702e7489f39375601c7ea5a0bef207256828a2bc5986c65cb15cd0cf097a87"}, - {file = "SQLAlchemy-1.4.51-cp312-cp312-win_amd64.whl", hash = "sha256:0525c4905b4b52d8ccc3c203c9d7ab2a80329ffa077d4bacf31aefda7604dc65"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1980e6eb6c9be49ea8f89889989127daafc43f0b1b6843d71efab1514973cca0"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ec7a0ed9b32afdf337172678a4a0e6419775ba4e649b66f49415615fa47efbd"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352df882088a55293f621328ec33b6ffca936ad7f23013b22520542e1ab6ad1b"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86a22143a4001f53bf58027b044da1fb10d67b62a785fc1390b5c7f089d9838c"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c37bc677690fd33932182b85d37433845de612962ed080c3e4d92f758d1bd894"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-win32.whl", hash = "sha256:d0a83afab5e062abffcdcbcc74f9d3ba37b2385294dd0927ad65fc6ebe04e054"}, - {file = "SQLAlchemy-1.4.51-cp36-cp36m-win_amd64.whl", hash = "sha256:a61184c7289146c8cff06b6b41807c6994c6d437278e72cf00ff7fe1c7a263d1"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:3f0ef620ecbab46e81035cf3dedfb412a7da35340500ba470f9ce43a1e6c423b"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c55040d8ea65414de7c47f1a23823cd9f3fad0dc93e6b6b728fee81230f817b"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ef80328e3fee2be0a1abe3fe9445d3a2e52a1282ba342d0dab6edf1fef4707"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f8cafa6f885a0ff5e39efa9325195217bb47d5929ab0051636610d24aef45ade"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8f2df79a46e130235bc5e1bbef4de0583fb19d481eaa0bffa76e8347ea45ec6"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-win32.whl", hash = "sha256:f2e5b6f5cf7c18df66d082604a1d9c7a2d18f7d1dbe9514a2afaccbb51cc4fc3"}, - {file = "SQLAlchemy-1.4.51-cp37-cp37m-win_amd64.whl", hash = "sha256:5e180fff133d21a800c4f050733d59340f40d42364fcb9d14f6a67764bdc48d2"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7d8139ca0b9f93890ab899da678816518af74312bb8cd71fb721436a93a93298"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb18549b770351b54e1ab5da37d22bc530b8bfe2ee31e22b9ebe650640d2ef12"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55e699466106d09f028ab78d3c2e1f621b5ef2c8694598242259e4515715da7c"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2ad16880ccd971ac8e570550fbdef1385e094b022d6fc85ef3ce7df400dddad3"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b97fd5bb6b7c1a64b7ac0632f7ce389b8ab362e7bd5f60654c2a418496be5d7f"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-win32.whl", hash = "sha256:cecb66492440ae8592797dd705a0cbaa6abe0555f4fa6c5f40b078bd2740fc6b"}, - {file = "SQLAlchemy-1.4.51-cp38-cp38-win_amd64.whl", hash = "sha256:39b02b645632c5fe46b8dd30755682f629ffbb62ff317ecc14c998c21b2896ff"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b03850c290c765b87102959ea53299dc9addf76ca08a06ea98383348ae205c99"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e646b19f47d655261b22df9976e572f588185279970efba3d45c377127d35349"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf56cc36d42908495760b223ca9c2c0f9f0002b4eddc994b24db5fcb86a9e4"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0d661cff58c91726c601cc0ee626bf167b20cc4d7941c93c5f3ac28dc34ddbea"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3823dda635988e6744d4417e13f2e2b5fe76c4bf29dd67e95f98717e1b094cad"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-win32.whl", hash = "sha256:b00cf0471888823b7a9f722c6c41eb6985cf34f077edcf62695ac4bed6ec01ee"}, - {file = "SQLAlchemy-1.4.51-cp39-cp39-win_amd64.whl", hash = "sha256:a055ba17f4675aadcda3005df2e28a86feb731fdcc865e1f6b4f209ed1225cba"}, - {file = "SQLAlchemy-1.4.51.tar.gz", hash = "sha256:e7908c2025eb18394e32d65dd02d2e37e17d733cdbe7d78231c2b6d7eb20cdb9"}, + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] -[package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} - -[package.extras] -aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"] -aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"] -asyncio = ["greenlet (!=0.4.17)"] -asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] -mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] -mssql = ["pyodbc"] -mssql-pymssql = ["pymssql"] -mssql-pyodbc = ["pyodbc"] -mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] -mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] -mysql-connector = ["mysql-connector-python"] -oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"] -postgresql = ["psycopg2 (>=2.7)"] -postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] -postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] -postgresql-psycopg2binary = ["psycopg2-binary"] -postgresql-psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] -sqlcipher = ["sqlcipher3_binary"] - [[package]] name = "starlette" version = "0.36.3" @@ -1898,37 +1948,48 @@ files = [ matplotlib = "*" numpy = "*" +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "tomlkit" -version = "0.12.3" +version = "0.12.4" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, - {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, + {file = "tomlkit-0.12.4-py3-none-any.whl", hash = "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b"}, + {file = "tomlkit-0.12.4.tar.gz", hash = "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3"}, ] [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "tzdata" -version = "2023.4" +version = "2024.1" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, - {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, ] [[package]] @@ -1947,13 +2008,13 @@ six = "*" [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] @@ -2033,13 +2094,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.25.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.25.1-py3-none-any.whl", hash = "sha256:961c026ac520bac5f69acb8ea063e8a4f071bcc9457b9c1f28f6b085c511583a"}, + {file = "virtualenv-20.25.1.tar.gz", hash = "sha256:e08e13ecdca7a0bd53798f356d5831434afa5b07b93f0abdf0797b7a06ffe197"}, ] [package.dependencies] @@ -2248,4 +2309,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "725d9324e4ab55620b0458bdcfd5e261b5009a7ecf4fd9a402df5e4842d46e46" +content-hash = "d7f9e04a55712b57cbc832aa237e3bd09666056a6014f8c45fe4f8a3840881fc" diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..e8effc6 --- /dev/null +++ b/poetry.toml @@ -0,0 +1,4 @@ +[virtualenvs] +create = true +in-project = true +prompt = "{project_name}-py{python_version}" diff --git a/pyproject.toml b/pyproject.toml index 2b3ca0f..5f15ba0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,9 @@ +#-->> System <<-------------------------------------------- +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +#-->> Metadata <<------------------------------------------ [tool.poetry] name = "backend" version = "0.2.0" @@ -5,27 +11,68 @@ description = "Slick Telemetry backend written in python" authors = ["Slick Telemetry "] readme = "README.md" +#-->> Dependencies <<-------------------------------------- +# Main dependencies (required by application) [tool.poetry.dependencies] python = "^3.12" -fastapi = "^0.109.2" -fastf1 = "^3.2.2" -fastapi-utils = "^0.2.1" +fastapi = "^0.110.0" +fastf1 = "3.2.2" uvicorn = { extras = ["standard"], version = "^0.27.1" } +# Development (common) [tool.poetry.group.dev.dependencies] -black = "^24.1.1" -commitizen = "^3.14.1" -isort = "^5.13.2" -pre-commit = "^3.6.0" -pytest = "^8.0.0" -httpx = "^0.26.0" +commitizen = "*" +pre-commit = "*" -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +# Formatting +[tool.poetry.group.lint] +optional = true -[tool.isort] -profile = "black" +[tool.poetry.group.lint.dependencies] +black = "*" +isort = "*" +mypy = "*" +pylint = "*" +pyproject-autoflake = "*" + +# Testing dependencies +[tool.poetry.group.test] +optional = true + +[tool.poetry.group.test.dependencies] +httpx = "*" +pytest = "*" + +#-->> Scripts <<------------------------------------------- +[tool.poe.tasks] +autoflake = "pautoflake run.py app" +black = "black run.py app" +isort = "isort run.py app" +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" +typings = "mypy run.py app" + +#-->> Configuration <<------------------------------------- +[tool.autoflake] +# return error code if changes are needed +check = false +# make changes to files instead of printing diffs +in-place = true +# exclude __init__.py when removing unused imports +ignore-init-module-imports = true +# remove all unused imports (not just those from the standard library) +remove-all-unused-imports = true +# remove unused variables +remove-unused-variables = true +# drill down directories recursively +recursive = true + +[tool.black] +line-length = 120 +target-version = ["py312"] [tool.commitizen] version = "0.2.0" @@ -36,3 +83,23 @@ version_files = [ ] update_changelog_on_bump = true major_version_zero = true + +[tool.isort] +profile = "black" +lines_after_imports = 2 +line_length = 120 +multi_line_output = 3 +import_heading_stdlib = "Built-in" +import_heading_thirdparty = "External" +import_heading_firstparty = "Project" +import_heading_localfolder = "App" + +[tool.mypy] +enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"] +files = ["app/*.py"] +ignore_missing_imports = true +pretty = true +show_error_codes = true +show_error_context = true +warn_unreachable = true +warn_return_any = true diff --git a/run.py b/run.py index f535f93..70491f5 100644 --- a/run.py +++ b/run.py @@ -1,14 +1,15 @@ +# External import uvicorn def start_server(): uvicorn.run( "app.main:app", - host="127.0.0.1", + host="localhost", port=8081, reload=True, log_level="info", - reload_excludes=["app/test_main.py"], + reload_excludes=["tests/*.py"], ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_healthcheck.py b/tests/test_healthcheck.py new file mode 100644 index 0000000..629a68f --- /dev/null +++ b/tests/test_healthcheck.py @@ -0,0 +1,15 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +def test_healthcheck(): + response = client.get("/health") + assert response.status_code == status.HTTP_200_OK + assert response.json() == {"status": "OK"} diff --git a/tests/test_laps.py b/tests/test_laps.py new file mode 100644 index 0000000..fa97fe9 --- /dev/null +++ b/tests/test_laps.py @@ -0,0 +1,220 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +# region laps - good inputs + + +def test_get_laps(): + response = client.get("/laps/2023/5") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "Time": 3868310, + "Driver": "VER", + "DriverNumber": "1", + "LapTime": 101724, + "LapNumber": 1.0, + "Stint": 1.0, + "PitOutTime": None, + "PitInTime": None, + "Sector1Time": None, + "Sector2Time": 36216, + "Sector3Time": 26263, + "Sector1SessionTime": None, + "Sector2SessionTime": 3842065, + "Sector3SessionTime": 3868409, + "SpeedI1": 212.0, + "SpeedI2": 186.0, + "SpeedFL": 274.0, + "SpeedST": 306.0, + "IsPersonalBest": False, + "Compound": "HARD", + "TyreLife": 1.0, + "FreshTyre": True, + "Team": "Red Bull Racing", + "LapStartTime": 3766300, + "LapStartDate": None, + "TrackStatus": "1", + "Position": 9.0, + "Deleted": False, + "DeletedReason": "", + "FastF1Generated": False, + "IsAccurate": False, + } + + +def test_get_laps_with_session_only(): + response = client.get("/laps/2023/5?session=4") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "Time": 1098400, + "Driver": "PER", + "DriverNumber": "11", + "LapTime": None, + "LapNumber": 1.0, + "Stint": 1.0, + "PitOutTime": 979230, + "PitInTime": None, + "Sector1Time": None, + "Sector2Time": 46024, + "Sector3Time": 33583, + "Sector1SessionTime": None, + "Sector2SessionTime": 1064838, + "Sector3SessionTime": 1098400, + "SpeedI1": 205.0, + "SpeedI2": 110.0, + "SpeedFL": 284.0, + "SpeedST": 266.0, + "IsPersonalBest": False, + "Compound": "SOFT", + "TyreLife": 1.0, + "FreshTyre": True, + "Team": "Red Bull Racing", + "LapStartTime": 979230, + "LapStartDate": None, + "TrackStatus": "1", + "Position": None, + "Deleted": False, + "DeletedReason": "", + "FastF1Generated": False, + "IsAccurate": False, + } + + +def test_get_laps_with_driver_numbers_only(): + response = client.get("/laps/2023/5?driver_number=1&driver_number=44") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "Time": 3868310, + "Driver": "VER", + "DriverNumber": "1", + "LapTime": 101724, + "LapNumber": 1.0, + "Stint": 1.0, + "PitOutTime": None, + "PitInTime": None, + "Sector1Time": None, + "Sector2Time": 36216, + "Sector3Time": 26263, + "Sector1SessionTime": None, + "Sector2SessionTime": 3842065, + "Sector3SessionTime": 3868409, + "SpeedI1": 212.0, + "SpeedI2": 186.0, + "SpeedFL": 274.0, + "SpeedST": 306.0, + "IsPersonalBest": False, + "Compound": "HARD", + "TyreLife": 1.0, + "FreshTyre": True, + "Team": "Red Bull Racing", + "LapStartTime": 3766300, + "LapStartDate": None, + "TrackStatus": "1", + "Position": 9.0, + "Deleted": False, + "DeletedReason": "", + "FastF1Generated": False, + "IsAccurate": False, + } + + +def test_get_laps_with_session_and_driver_numbers(): + response = client.get("/laps/2023/5?session=4&driver_number=1&driver_number=44") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "Time": 1087970, + "Driver": "VER", + "DriverNumber": "1", + "LapTime": None, + "LapNumber": 1.0, + "Stint": 1.0, + "PitOutTime": 972293, + "PitInTime": None, + "Sector1Time": None, + "Sector2Time": 44852, + "Sector3Time": 31773, + "Sector1SessionTime": None, + "Sector2SessionTime": 1056197, + "Sector3SessionTime": 1088025, + "SpeedI1": 202.0, + "SpeedI2": 79.0, + "SpeedFL": 283.0, + "SpeedST": 257.0, + "IsPersonalBest": False, + "Compound": "SOFT", + "TyreLife": 1.0, + "FreshTyre": True, + "Team": "Red Bull Racing", + "LapStartTime": 972293, + "LapStartDate": None, + "TrackStatus": "1", + "Position": None, + "Deleted": False, + "DeletedReason": "", + "FastF1Generated": False, + "IsAccurate": False, + } + + +# endregion laps - good inputs + +# region laps - bad inputs + + +def test_get_laps_mixed_driver_numbers(): + response = client.get( + "/laps/2023/5?driver_number=0&driver_number=1&driver_number=13&driver_number=44&driver_number=83" + ) + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "Time": 3868310, + "Driver": "VER", + "DriverNumber": "1", + "LapTime": 101724, + "LapNumber": 1.0, + "Stint": 1.0, + "PitOutTime": None, + "PitInTime": None, + "Sector1Time": None, + "Sector2Time": 36216, + "Sector3Time": 26263, + "Sector1SessionTime": None, + "Sector2SessionTime": 3842065, + "Sector3SessionTime": 3868409, + "SpeedI1": 212.0, + "SpeedI2": 186.0, + "SpeedFL": 274.0, + "SpeedST": 306.0, + "IsPersonalBest": False, + "Compound": "HARD", + "TyreLife": 1.0, + "FreshTyre": True, + "Team": "Red Bull Racing", + "LapStartTime": 3766300, + "LapStartDate": None, + "TrackStatus": "1", + "Position": 9.0, + "Deleted": False, + "DeletedReason": "", + "FastF1Generated": False, + "IsAccurate": False, + } + + +def test_get_laps_bad_driver_numbers(): + response = client.get( + "/laps/2023/5?driver_number=0&driver_number=99&driver_number=13&driver_number=45&driver_number=83" + ) + assert response.status_code == status.HTTP_200_OK + assert response.json() == [] + + +# endregion laps - bad inputs diff --git a/tests/test_next_event.py b/tests/test_next_event.py new file mode 100644 index 0000000..d56e48f --- /dev/null +++ b/tests/test_next_event.py @@ -0,0 +1,39 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +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", + "EventFormat": "conventional", + "Session1": "Practice 1", + "Session1Date": "2024-02-29 14:30:00+03:00", + "Session1DateUtc": "2024-02-29 11:30:00", + "Session2": "Practice 2", + "Session2Date": "2024-02-29 18:00:00+03:00", + "Session2DateUtc": "2024-02-29 15:00:00", + "Session3": "Practice 3", + "Session3Date": "2024-03-01 15:30:00+03:00", + "Session3DateUtc": "2024-03-01 12:30:00", + "Session4": "Qualifying", + "Session4Date": "2024-03-01 19:00:00+03:00", + "Session4DateUtc": "2024-03-01 16:00:00", + "Session5": "Race", + "Session5Date": "2024-03-02 18:00:00+03:00", + "Session5DateUtc": "2024-03-02 15:00:00", + "F1ApiSupport": True, + } diff --git a/tests/test_results.py b/tests/test_results.py new file mode 100644 index 0000000..ad990a1 --- /dev/null +++ b/tests/test_results.py @@ -0,0 +1,82 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +# region results - good inputs + + +def test_get_results(): + response = client.get("/results/2023/5") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "DriverNumber": "1", + "BroadcastName": "M VERSTAPPEN", + "Abbreviation": "VER", + "DriverId": "max_verstappen", + "TeamName": "Red Bull Racing", + "TeamColor": "3671C6", + "TeamId": "red_bull", + "FirstName": "Max", + "LastName": "Verstappen", + "FullName": "Max Verstappen", + "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/M/MAXVER01_Max_Verstappen/maxver01.png.transform/1col/image.png", + "CountryCode": "NED", + "Position": 1, + "ClassifiedPosition": "1", + "GridPosition": 9, + "Q1": None, + "Q2": None, + "Q3": None, + "Time": 5258241, + "Status": "Finished", + "Points": 26, + } + + +def test_get_results_with_session(): + response = client.get("/results/2023/5?session=4") + assert response.status_code == status.HTTP_200_OK + assert response.json()[0] == { + "DriverNumber": "11", + "BroadcastName": "S PEREZ", + "Abbreviation": "PER", + "DriverId": "perez", + "TeamName": "Red Bull Racing", + "TeamColor": "3671C6", + "TeamId": "red_bull", + "FirstName": "Sergio", + "LastName": "Perez", + "FullName": "Sergio Perez", + "HeadshotUrl": "https://www.formula1.com/content/dam/fom-website/drivers/S/SERPER01_Sergio_Perez/serper01.png.transform/1col/image.png", + "CountryCode": "MEX", + "Position": 1, + "ClassifiedPosition": "", + "GridPosition": None, + "Q1": 87713, + "Q2": 87328, + "Q3": 86841, + "Time": None, + "Status": "", + "Points": None, + } + + +# endregion results - good inputs + +# region results - bad inputs + + +def test_get_results_bad_round_invalid(): + response = client.get("/results/2023/25?session=2") + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json() == {"detail": "Bad Request. Invalid round: 25"} + + +# endregion results - bad inputs diff --git a/tests/test_root.py b/tests/test_root.py new file mode 100644 index 0000000..e792da5 --- /dev/null +++ b/tests/test_root.py @@ -0,0 +1,15 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +def test_read_root(): + response = client.get("/") + assert response.status_code == status.HTTP_200_OK + assert response.json() == {"we_are": "SlickTelemetry"} diff --git a/tests/test_schedule.py b/tests/test_schedule.py new file mode 100644 index 0000000..298d907 --- /dev/null +++ b/tests/test_schedule.py @@ -0,0 +1,71 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +def test_get_schedule(): + response = client.get("/schedule") + assert response.status_code == status.HTTP_200_OK + assert response.json()["year"] == 2023 + assert response.json()["EventSchedule"][0] == { + "RoundNumber": 1, + "Country": "Bahrain", + "Location": "Sakhir", + "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2023", + "EventDate": "2023-03-05", + "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", + "Session2": "Practice 2", + "Session2Date": "2023-03-03 18:00:00+03:00", + "Session2DateUtc": "2023-03-03 15:00:00", + "Session3": "Practice 3", + "Session3Date": "2023-03-04 14:30:00+03:00", + "Session3DateUtc": "2023-03-04 11:30:00", + "Session4": "Qualifying", + "Session4Date": "2023-03-04 18:00:00+03:00", + "Session4DateUtc": "2023-03-04 15:00:00", + "Session5": "Race", + "Session5Date": "2023-03-05 18:00:00+03:00", + "Session5DateUtc": "2023-03-05 15:00:00", + "F1ApiSupport": True, + } + + +def test_get_schedule_good_year(): + response = client.get("/schedule?year=2023") + assert response.status_code == status.HTTP_200_OK + assert response.json()["year"] == 2023 + assert response.json()["EventSchedule"][0] == { + "RoundNumber": 1, + "Country": "Bahrain", + "Location": "Sakhir", + "OfficialEventName": "FORMULA 1 GULF AIR BAHRAIN GRAND PRIX 2023", + "EventDate": "2023-03-05", + "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", + "Session2": "Practice 2", + "Session2Date": "2023-03-03 18:00:00+03:00", + "Session2DateUtc": "2023-03-03 15:00:00", + "Session3": "Practice 3", + "Session3Date": "2023-03-04 14:30:00+03:00", + "Session3DateUtc": "2023-03-04 11:30:00", + "Session4": "Qualifying", + "Session4Date": "2023-03-04 18:00:00+03:00", + "Session4DateUtc": "2023-03-04 15:00:00", + "Session5": "Race", + "Session5Date": "2023-03-05 18:00:00+03:00", + "Session5DateUtc": "2023-03-05 15:00:00", + "F1ApiSupport": True, + } diff --git a/tests/test_standings.py b/tests/test_standings.py new file mode 100644 index 0000000..937791f --- /dev/null +++ b/tests/test_standings.py @@ -0,0 +1,155 @@ +# External +from fastapi import status +from fastapi.testclient import TestClient + +# Project +from app.main import app + + +client = TestClient(app) + + +# region standings - 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()["DriverStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "575", + "wins": "19", + "Driver": { + "driverId": "max_verstappen", + "permanentNumber": "33", + "code": "VER", + "url": "http://en.wikipedia.org/wiki/Max_Verstappen", + "givenName": "Max", + "familyName": "Verstappen", + "dateOfBirth": "1997-09-30", + "nationality": "Dutch", + }, + "Constructors": [ + { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + } + ], + } + assert response.json()["ConstructorStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "860", + "wins": "21", + "Constructor": { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + }, + } + + +def test_get_standings_good_year_only(): + response = client.get("/standings?year=2023") + assert response.status_code == status.HTTP_200_OK + assert response.json()["season"] == 2023 + assert response.json()["round"] == 22 + assert response.json()["DriverStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "575", + "wins": "19", + "Driver": { + "driverId": "max_verstappen", + "permanentNumber": "33", + "code": "VER", + "url": "http://en.wikipedia.org/wiki/Max_Verstappen", + "givenName": "Max", + "familyName": "Verstappen", + "dateOfBirth": "1997-09-30", + "nationality": "Dutch", + }, + "Constructors": [ + { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + } + ], + } + assert response.json()["ConstructorStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "860", + "wins": "21", + "Constructor": { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + }, + } + + +def test_get_standings_good_year_and_round(): + response = client.get("/standings?year=2023&round=5") + assert response.status_code == status.HTTP_200_OK + assert response.json()["season"] == 2023 + assert response.json()["round"] == 5 + assert response.json()["DriverStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "119", + "wins": "3", + "Driver": { + "driverId": "max_verstappen", + "permanentNumber": "33", + "code": "VER", + "url": "http://en.wikipedia.org/wiki/Max_Verstappen", + "givenName": "Max", + "familyName": "Verstappen", + "dateOfBirth": "1997-09-30", + "nationality": "Dutch", + }, + "Constructors": [ + { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + } + ], + } + assert response.json()["ConstructorStandings"][0] == { + "position": "1", + "positionText": "1", + "points": "224", + "wins": "5", + "Constructor": { + "constructorId": "red_bull", + "url": "http://en.wikipedia.org/wiki/Red_Bull_Racing", + "name": "Red Bull", + "nationality": "Austrian", + }, + } + + +# endregion standings - good inputs + +# region standings - no inputs + + +def test_get_standings_good_round_bad_year_no_input(): + response = client.get("/standings?round=3") + assert response.status_code == status.HTTP_400_BAD_REQUEST + assert response.json() == {"detail": 'Bad request. Must provide the "year" parameter.'} + + +# endregion standings - no inputs diff --git a/useful_commands.md b/useful_commands.md index a9dccc3..03f3ae8 100644 --- a/useful_commands.md +++ b/useful_commands.md @@ -37,7 +37,8 @@ poetry show --outdated ### Run tests using pytest ```sh -poetry run pytest -rpP + # pytest -rpP + poetry poe tests ``` ## Git hooks @@ -45,13 +46,15 @@ poetry run pytest -rpP ### Install git hooks ```sh -pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-commit +# pre-commit install --hook-type commit-msg --hook-type pre-push --hook-type pre-commit +poetry poe git-hooks-setup ``` ### Updating hooks automatically ```sh -pre-commit autoupdate +# pre-commit autoupdate +poetry poe git-hooks-update ``` ## Docker