diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 187d6b6..812f830 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,30 +9,31 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] operating-system: [ubuntu-20.04, windows-latest, macos-latest] steps: - uses: actions/checkout@v3 + - name: Install uv + uses: astral-sh/setup-uv@v3 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v3 with: python-version: ${{ matrix.python-version }} - name: Install dependencies + run: uv sync --group dev + - name: Check format run: | - python -m pip install --upgrade pip - pip install -e . - pip install -r requirements.testing.txt - - name: Lint with flake8 + uv run nox -s check_format + - name: Check lint run: | - pip install flake8 - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + uv run nox -s check_lint + - name: Check types + run: | + uv run nox -s check_types - name: Test with pytest run: | - py.test -s -v --cov-report xml --cov=herepy tests/ + uv run nox -s run_tests - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 with: diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 78a38b7..3f313ca 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -8,19 +8,16 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: "3.9" - - name: Install Module - run: pip install -e . - name: Install Dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.docs.txt - pip install livereload + run: uv sync --group docs - name: Build Docs - run: mkdocs build + run: uv run mkdocs build - name: Deploy to Netlify uses: nwtgck/actions-netlify@v3.0 with: diff --git a/README.rst b/README.rst index 4b7ec57..9435240 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ HerePy Introduction ============ -This library provides a pure Python interface for the `HERE API `_. It works with Python versions 3.x. +This library provides a pure Python interface for the `HERE API `_. It works with Python versions 3.10 and over. `HERE `_ provides location based services. HERE exposes a `rest APIs `_ and this library is intended to make it even easier for Python programmers to use. @@ -38,6 +38,7 @@ Installing You can install herepy using Python Package Index:: $ pip install herepy + $ uv pip install herepy Install with conda from the Anaconda conda-forge channel:: @@ -57,28 +58,27 @@ Check out the latest development version anonymously with:: $ git clone git://github.com/abdullahselek/HerePy.git $ cd HerePy -To install dependencies, run either:: +To install dependencies for development, use uv:: - $ pip install -r requirements.testing.txt - $ pip install -r requirements.txt + $ uv sync To install the minimal dependencies for production use (i.e., what is installed with ``pip install herepy``) run:: - $ pip install -r requirements.txt + $ uv sync --no-dev Running Tests ============= -The test suite can be run against a single Python version which requires ``pip install pytest`` and optionally ``pip install pytest-cov`` (these are included if you have installed dependencies from ``requirements.testing.txt``) +The test suite can be run against a single Python version using uv:: To run the unit tests with a single Python version:: - $ py.test -v + $ uv run pytest -v to also run code coverage:: - $ py.test --cov=herepy + $ uv run pytest --cov=herepy To run the unit tests against a set of Python versions:: @@ -138,6 +138,14 @@ Using The library provides a Python wrapper around the HERE APIs with different data models. To get started, check out the examples in the ``examples/`` folder or read the documentation at `https://herepy.abdullahselek.com/ `_. All API clients need an API key which you can get from `HERE Developer Portal `_. +Publishing +============ + +Maintainers can publish the package to PyPI using uv:: + + $ uv build + $ uv publish + License ------- diff --git a/docs/installation.md b/docs/installation.md index 1b25e80..8b1ec82 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -5,38 +5,38 @@ **From PyPI** $ pip install herepy + $ uv pip install herepy **From source** -Install dependencies using `pip` +Install dependencies using `uv` ```console -$ pip install -r requirements.txt +$ uv sync ``` Download the latest `herepy` library from: https://github.com/abdullahselek/HerePy -Extract the source distribution and run +To install the project in editable mode for development: ```console -$ python setup.py build -$ python setup.py install +$ uv sync ``` ## Running Tests -The test suite can be run against a single Python version which requires `pip install pytest` and optionally `pip install pytest-cov` (these are included if you have installed dependencies from `requirements.testing.txt`) +The test suite can be run against a single Python version using `uv` To run the unit tests with a single Python version ```console -$ py.test -v +$ uv run pytest -v ``` to also run code coverage ```console -$ py.test -v --cov-report html --cov=herepy +$ uv run pytest -v --cov-report html --cov=herepy ``` To run the unit tests against a set of Python versions:: diff --git a/examples/destination_weather_api.py b/examples/destination_weather_api.py index c9fae48..69dae04 100644 --- a/examples/destination_weather_api.py +++ b/examples/destination_weather_api.py @@ -1,3 +1,4 @@ +"""Example usage of destination_weather_api.""" #!/usr/bin/env python from herepy import DestinationWeatherApi, WeatherProductType @@ -5,9 +6,7 @@ destination_weather_api = DestinationWeatherApi("api_key") # weather conditions with given location name -response = destination_weather_api.weather_for_location_name( - location_name="Berlin", product=WeatherProductType.forecast_7days -) +response = destination_weather_api.weather_for_location_name(location_name="Berlin", product=WeatherProductType.forecast_7days) print(response.as_dict()) # weather conditions within given coordinates @@ -19,7 +18,5 @@ print(response.as_dict()) # weather conditions within given zipcode -response = destination_weather_api.weather_for_zip_code( - zip_code="10025", product=WeatherProductType.forecast_7days -) +response = destination_weather_api.weather_for_zip_code(zip_code="10025", product=WeatherProductType.forecast_7days) print(response.as_dict()) diff --git a/examples/ev_charging_stations_api.py b/examples/ev_charging_stations_api.py index 1aa3f6f..f367076 100644 --- a/examples/ev_charging_stations_api.py +++ b/examples/ev_charging_stations_api.py @@ -1,3 +1,4 @@ +"""Example usage of ev_charging_stations_api.""" #!/usr/bin/env python from herepy import EVChargingStationsApi, EVStationConnectorTypes diff --git a/examples/fleet_telematics_api.py b/examples/fleet_telematics_api.py index 0b8b808..aa98aed 100644 --- a/examples/fleet_telematics_api.py +++ b/examples/fleet_telematics_api.py @@ -1,6 +1,7 @@ +"""Example usage of fleet_telematics_api.""" #!/usr/bin/env python -from herepy import FleetTelematicsApi, RouteMode, MultiplePickupOfferType +from herepy import FleetTelematicsApi, MultiplePickupOfferType, RouteMode fleet_telematics_api = FleetTelematicsApi(api_key="api_key") diff --git a/examples/geocoder_api.py b/examples/geocoder_api.py index 4f0463c..8ec60bf 100644 --- a/examples/geocoder_api.py +++ b/examples/geocoder_api.py @@ -1,3 +1,4 @@ +"""Example usage of geocoder_api.""" #!/usr/bin/env python from herepy import GeocoderApi @@ -17,9 +18,7 @@ print(response.as_dict()) # geocodes with given address details -response = geocoder_api.address_with_details( - house_number=34, street="Barbaros", city="Istanbul", country="Turkey" -) +response = geocoder_api.address_with_details(house_number=34, street="Barbaros", city="Istanbul", country="Turkey") print(response.as_dict()) # geocodes with given street and city diff --git a/examples/geocoder_autocomplete_api.py b/examples/geocoder_autocomplete_api.py index 136bc03..3aec897 100644 --- a/examples/geocoder_autocomplete_api.py +++ b/examples/geocoder_autocomplete_api.py @@ -1,3 +1,4 @@ +"""Example usage of geocoder_autocomplete_api.""" #!/usr/bin/env python from herepy import GeocoderAutoCompleteApi @@ -5,13 +6,9 @@ geocoder_autocomplete_api = GeocoderAutoCompleteApi(api_key="api_key") # ask for a list of suggested addresses found within a specified area -response = geocoder_autocomplete_api.address_suggestion( - query="High", prox=[51.5035, -0.1616], radius=100 -) +response = geocoder_autocomplete_api.address_suggestion(query="High", prox=[51.5035, -0.1616], radius=100) print(response.as_dict()) # ask for a list of suggested addresses within a single country -response = geocoder_autocomplete_api.limit_results_byaddress( - query="Nis", country_code="USA" -) +response = geocoder_autocomplete_api.limit_results_byaddress(query="Nis", country_code="USA") print(response.as_dict()) diff --git a/examples/geocoder_reverse_api.py b/examples/geocoder_reverse_api.py index 85c9fc3..03d0e86 100644 --- a/examples/geocoder_reverse_api.py +++ b/examples/geocoder_reverse_api.py @@ -1,3 +1,4 @@ +"""Example usage of geocoder_reverse_api.""" #!/usr/bin/env python from herepy import GeocoderReverseApi diff --git a/examples/isoline_routing_api.py b/examples/isoline_routing_api.py index 6163f26..06a8433 100644 --- a/examples/isoline_routing_api.py +++ b/examples/isoline_routing_api.py @@ -1,9 +1,10 @@ +"""Example usage of isoline_routing_api.""" #!/usr/bin/env python from herepy import ( IsolineRoutingApi, - IsolineRoutingTransportMode, IsolineRoutingMode, + IsolineRoutingTransportMode, ) isoline_routing_api = IsolineRoutingApi(api_key="api_key") diff --git a/examples/map_image_api.py b/examples/map_image_api.py index 66f7602..934b23a 100644 --- a/examples/map_image_api.py +++ b/examples/map_image_api.py @@ -1,3 +1,4 @@ +"""Example usage of map_image_api.""" #!/usr/bin/env python from herepy import MapImageApi @@ -20,15 +21,11 @@ print(map_image) # Get map image for given coordinates, uncertainty and map scheme -map_image = map_image_api.get_mapimage( - coordinates=[28.371425, 77.387695], uncertainty="5m", map_scheme=3 -) +map_image = map_image_api.get_mapimage(coordinates=[28.371425, 77.387695], uncertainty="5m", map_scheme=3) print(map_image) # Get a dotless map image for given coordinates and uncertainty -map_image = map_image_api.get_mapimage( - coordinates=[28.371425, 77.387695], uncertainty="5m", nodot=True -) +map_image = map_image_api.get_mapimage(coordinates=[28.371425, 77.387695], uncertainty="5m", nodot=True) print(map_image) # Get an image showing position with coordinates, city name, image height @@ -42,9 +39,7 @@ print(map_image) # Get an image showing with coordinates and country name -map_image = map_image_api.get_mapimage( - coordinates=[60.17675, 24.929974], country_name="Finland", zoom=15 -) +map_image = map_image_api.get_mapimage(coordinates=[60.17675, 24.929974], country_name="Finland", zoom=15) print(map_image) # Get an image showing with coordinates, country name and center diff --git a/examples/map_tile_api.py b/examples/map_tile_api.py index ff2a842..3f33d12 100644 --- a/examples/map_tile_api.py +++ b/examples/map_tile_api.py @@ -1,9 +1,10 @@ +"""Example usage of map_tile_api.""" #!/usr/bin/env python from herepy import ( + BaseMapTileResourceType, MapTileApi, MapTileApiType, - BaseMapTileResourceType, TrafficMapTileResourceType, ) diff --git a/examples/places_api.py b/examples/places_api.py index 2f6ede2..9b6f75b 100644 --- a/examples/places_api.py +++ b/examples/places_api.py @@ -1,3 +1,4 @@ +"""Example usage of places_api.""" #!/usr/bin/env python from herepy import PlacesApi @@ -5,19 +6,13 @@ places_api = PlacesApi(api_key="api_key") # fetches a list of places based on a query string -response = places_api.onebox_search( - coordinates=[37.7905, -122.4107], query="restaurant" -) +response = places_api.onebox_search(coordinates=[37.7905, -122.4107], query="restaurant") print(response.as_dict()) # fetches a list of places based on a query string and country code -response = places_api.search_in_country( - coordinates=[37.7905, -122.4107], query="cafe", country_code="USA" -) +response = places_api.search_in_country(coordinates=[37.7905, -122.4107], query="cafe", country_code="USA") print(response.as_dict()) # a list of popular places around a location -response = places_api.places_in_circle( - coordinates=[37.7905, -122.4107], radius=1000, query="cafe", limit=40 -) +response = places_api.places_in_circle(coordinates=[37.7905, -122.4107], radius=1000, query="cafe", limit=40) print(response.as_dict()) diff --git a/examples/public_transit_api.py b/examples/public_transit_api.py index 4ef046d..bf2e56d 100644 --- a/examples/public_transit_api.py +++ b/examples/public_transit_api.py @@ -1,3 +1,4 @@ +"""Example usage of public_transit_api.""" #!/usr/bin/env python from herepy import PublicTransitApi, PublicTransitSearchMethod diff --git a/examples/rme_api.py b/examples/rme_api.py index 6aaeba5..b366db3 100644 --- a/examples/rme_api.py +++ b/examples/rme_api.py @@ -1,13 +1,13 @@ +"""Example usage of rme_api.""" #!/usr/bin/env python -import io from herepy import RmeApi rme_api = RmeApi(api_key="api_key") # retrieves misc information about the route given in gpx file -with io.open("testdata/routes/sample.gpx", encoding="utf-8") as gpx_file: +with open("testdata/routes/sample.gpx", encoding="utf-8") as gpx_file: gpx_content = gpx_file.read() response = rme_api.match_route(gpx_content, ["ADAS_ATTRIB_FCn(SLOPES)"]) print(response.as_dict()) diff --git a/examples/routing_api.py b/examples/routing_api.py index 4fbcba0..67b4fcb 100644 --- a/examples/routing_api.py +++ b/examples/routing_api.py @@ -1,30 +1,29 @@ +"""Example usage of routing_api.""" #!/usr/bin/env python from herepy import ( - RoutingApi, - RouteMode, + Avoid, + AvoidArea, + AvoidFeature, MatrixRoutingType, MatrixSummaryAttribute, - RoutingTransportMode, - RoutingMode, + RouteMode, + RoutingApi, RoutingApiReturnField, - RoutingMetric, RoutingApiSpanField, - AvoidArea, - AvoidFeature, - Avoid, - Truck, + RoutingMetric, + RoutingMode, + RoutingTransportMode, ShippedHazardousGood, - TunnelCategory, + Truck, TruckType, + TunnelCategory, ) routing_api = RoutingApi(api_key="api_key") # fetches a bicycle route between two points -response = routing_api.bicycle_route( - waypoint_a=[41.9798, -87.8801], waypoint_b=[41.9043, -87.9216] -) +response = routing_api.bicycle_route(waypoint_a=[41.9798, -87.8801], waypoint_b=[41.9043, -87.9216]) print(response.as_dict()) # fetches a driving route between two points diff --git a/examples/traffic_api.py b/examples/traffic_api.py index 27d9532..8aec681 100644 --- a/examples/traffic_api.py +++ b/examples/traffic_api.py @@ -1,10 +1,11 @@ +"""Example usage of traffic_api.""" #!/usr/bin/env python from herepy import ( - TrafficApi, - IncidentsCriticalityStr, - IncidentsCriticalityInt, FlowProximityAdditionalAttributes, + IncidentsCriticalityInt, + IncidentsCriticalityStr, + TrafficApi, ) traffic_api = TrafficApi(api_key="api_key") @@ -45,15 +46,11 @@ print(response.as_dict()) # traffic flow information within specified area -response = traffic_api.flow_within_boundingbox( - top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035] -) +response = traffic_api.flow_within_boundingbox(top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035]) print(response.as_dict()) # traffic flow for a circle around a defined point -response = traffic_api.flow_using_proximity( - latitude=51.5072, longitude=-0.1275, distance=100 -) +response = traffic_api.flow_using_proximity(latitude=51.5072, longitude=-0.1275, distance=100) print(response.as_dict()) # traffic flow information using proximity, returning shape and functional class diff --git a/examples/vector_tile_api.py b/examples/vector_tile_api.py index 7d0bce3..a19524a 100644 --- a/examples/vector_tile_api.py +++ b/examples/vector_tile_api.py @@ -1,17 +1,14 @@ +"""Example usage of vector_tile_api.""" #!/usr/bin/env python -from herepy import VectorTileApi, VectorMapTileLayer +from herepy import VectorMapTileLayer, VectorTileApi vector_tile_api = VectorTileApi(api_key="api_key") # Returns a tile using base layer and other default parameters -vector_tile = vector_tile_api.get_vectortile( - latitude=52.525439, longitude=13.38727, zoom=12 -) +vector_tile = vector_tile_api.get_vectortile(latitude=52.525439, longitude=13.38727, zoom=12) print(vector_tile) # Returns tile using core layer with other default parameters -vector_tile = vector_tile_api.get_vectortile( - latitude=52.525439, longitude=13.38727, zoom=12, layer=VectorMapTileLayer.core -) +vector_tile = vector_tile_api.get_vectortile(latitude=52.525439, longitude=13.38727, zoom=12, layer=VectorMapTileLayer.core) print(vector_tile) diff --git a/herepy/__init__.py b/herepy/__init__.py deleted file mode 100644 index 75ffd5c..0000000 --- a/herepy/__init__.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python - -"""A library that provides a Python interface to the HERE APIs""" - -__author__ = "Abdullah Selek" -__email__ = "abdullahselek.os@gmail.com" -__copyright__ = "Copyright (c) 2017 Abdullah Selek" -__license__ = "MIT License" -__version__ = "3.6.5" -__url__ = "https://github.com/abdullahselek/HerePy" -__download_url__ = "https://pypi.org/pypi/herepy" -__description__ = "A library that provides a Python interface to the HERE APIs" - - -import json - -from .destination_weather_api import DestinationWeatherApi -from .error import (AccessDeniedError, HEREError, InvalidRequestError, - UnauthorizedError) -from .ev_charging_stations_api import EVChargingStationsApi -from .fleet_telematics_api import FleetTelematicsApi -from .geocoder_api import GeocoderApi -from .geocoder_autocomplete_api import GeocoderAutoCompleteApi -from .geocoder_reverse_api import GeocoderReverseApi -from .here_enum import (AerialMapTileResourceType, AvoidFeature, - BaseMapTileResourceType, EVStationConnectorTypes, - FlowProximityAdditionalAttributes, - IncidentsCriticalityInt, IncidentsCriticalityStr, - IsolineRoutingMode, IsolineRoutingOptimizationMode, - IsolineRoutingRangeType, IsolineRoutingTransportMode, - MapImageFormatType, MapImageResourceType, - MapTileApiType, MapTileResourceType, MatrixRoutingMode, - MatrixRoutingProfile, MatrixRoutingTransportMode, - MatrixRoutingType, MatrixSummaryAttribute, - MultiplePickupOfferType, PlacesCategory, - PublicTransitModeType, PublicTransitRoutingMode, - PublicTransitSearchMethod, RouteMode, - RoutingApiReturnField, RoutingApiSpanField, - RoutingMetric, RoutingMode, RoutingTransportMode, - ShippedHazardousGood, TrafficMapTileResourceType, - TruckType, TunnelCategory, VectorMapTileLayer, - WeatherProductType) -from .isoline_routing_api import IsolineRoutingApi -from .map_image_api import MapImageApi -from .map_tile_api import MapTileApi -from .mercator_projection import MercatorProjection -from .models import (DestinationWeatherResponse, EVChargingStationsResponse, - GeocoderAutoCompleteResponse, GeocoderResponse, - GeocoderReverseResponse, IsolineRoutingResponse, - PlacesResponse, PublicTransitResponse, RmeResponse, - RoutingMatrixResponse, RoutingResponse, RoutingResponseV8, - TrafficFlowAvailabilityResponse, TrafficFlowResponse, - TrafficIncidentResponse, WaypointSequenceResponse) -from .objects import Avoid, AvoidArea, AvoidFeature, Truck -from .places_api import PlacesApi -from .platform.tour_planning_api import TourPlanningApi -from .public_transit_api import PublicTransitApi -from .rme_api import RmeApi -from .routing_api import (InvalidCredentialsError, InvalidInputDataError, - LinkIdNotFoundError, NoRouteFoundError, - RouteNotReconstructedError, RoutingApi, - WaypointNotFoundError) -from .traffic_api import TrafficApi -from .utils import Utils -from .vector_tile_api import VectorTileApi diff --git a/junit.xml b/junit.xml new file mode 100644 index 0000000..80be3e0 --- /dev/null +++ b/junit.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 0000000..fa669ad --- /dev/null +++ b/noxfile.py @@ -0,0 +1,68 @@ +"""Developer task automation.""" + +import nox + +nox.options.default_venv_backend = "uv" +nox.options.sessions = [ + "check_format", + "check_lint", + "check_types", + "run_tests", +] + +PYTHON = ["3.13"] +CODE_TO_TEST = ["src", "tests", "noxfile.py"] + + +@nox.session(python=PYTHON) +def run_tests(session: nox.Session): + """Run unit tests.""" + session.run_install( + "uv", + "sync", + env={"UV_PROJECT_ENVIRONMENT": session.virtualenv.location}, + silent=True, + ) + pytest_args = session.posargs if session.posargs else [] + + session.run( + "pytest", + "--cache-clear", + "--junitxml=junit.xml", + "--cov-fail-under=90", + "--cov=src", + "--cov-branch", + "--cov-report=term", + "--cov-report=xml", + *pytest_args, + ) + + +@nox.session(python=False) +def check_format(session: nox.Session): + """Check code formatting.""" + session.run("ruff", "format", *CODE_TO_TEST, "--check") + + +@nox.session(python=False) +def format(session: nox.Session): + """Check code formatting and auto fix the errors if possible.""" + session.run("ruff", "format", *CODE_TO_TEST) + + +@nox.session(python=False) +def check_lint(session: nox.Session): + """Check code linting.""" + session.run("ruff", "check", *CODE_TO_TEST) + + +@nox.session(python=False) +def lint(session: nox.Session): + """Check code linting and auto fix the erros if possible.""" + session.run("ruff", "check", *CODE_TO_TEST, "--fix") + + +@nox.session(python=False) +def check_types(session: nox.Session): + """Run static type checking.""" + session.run("mypy", *CODE_TO_TEST) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9610a32 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,94 @@ +[project] +name = "herepy" +version = "3.6.5" +description = "A library that provides a Python interface to the HERE APIs" +readme = "README.rst" +requires-python = ">=3.10" +license = { text = "MIT License" } +authors = [{ name = "Abdullah Selek", email = "abdullahselek.os@gmail.com" }] +keywords = [ + "here api", + "here technologies", + "here python api clients", + "rest api clients", +] +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Topic :: Software Development :: Libraries :: Python Modules", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", +] +dependencies = ["Requests>=2.25.1,<3"] + +[project.urls] +Repository = "https://github.com/abdullahselek/HerePy" +Download = "https://pypi.org/pypi/herepy" +Documentation = "https://herepy.abdullahselek.com/" + +[dependency-groups] +dev = [ + "pytest==8.1.1", + "pytest-cov==5.0.0", + "pytest-runner==6.0.1", + "codecov==2.1.13", + "responses==0.25.0", + "tox==4.14.2", + "tox-pyenv==1.1.0", + "flake8", + "nox>=2026.4.10", + "ruff>=0.15.16", + "mypy>=2.1.0", +] +docs = [ + "mkdocs==1.6.1", + "mkdocstrings==0.26.2", + "mkdocs-material==9.5.42", + "markdown-include==0.8.1", + "mkdocstrings-python==1.12.2", + "livereload", +] + +[tool.setuptools] +packages = { find = { exclude = ["tests*", "docs*"] } } +package-data = { herepy = ["py.typed"] } + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.ruff] +src = ["src"] +target-version = "py310" +line-length = 140 + +[tool.ruff.lint] +select = [ + "D", # pydocstyle + "E", # pycodestyle errors + "F", # pyflakes + "I", # isort + "UP", # pyupgrade + "W", # pycodestyle warnings +] +ignore = [ + "D203", # 1 blank line required before class docstring (incompatible with D211) + "D212", # Multi-line summary should start on the same line as the opening quotes (incompatible with D213) +] + +[tool.ruff.lint.per-file-ignores] +# Ignore all directories named `tests`. +"tests/**" = ["D", "E", "F"] + + +[tool.pytest.ini_options] +testpaths = ["tests"] + +[tool.mypy] +python_version = "3.10" diff --git a/requirements.docs.txt b/requirements.docs.txt deleted file mode 100644 index f9be00f..0000000 --- a/requirements.docs.txt +++ /dev/null @@ -1,5 +0,0 @@ -mkdocs==1.6.1 -mkdocstrings==0.26.2 -mkdocs-material==9.5.42 -markdown-include==0.8.1 -mkdocstrings-python==1.12.2 diff --git a/requirements.testing.txt b/requirements.testing.txt deleted file mode 100644 index dbe6a48..0000000 --- a/requirements.testing.txt +++ /dev/null @@ -1,7 +0,0 @@ -pytest==8.1.1 -pytest-cov==5.0.0 -pytest-runner==6.0.1 -codecov==2.1.13 -responses==0.25.0 -tox==4.14.2 -tox-pyenv==1.1.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bd563a2..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -Requests>=2.25.1,<3 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 4b8715d..0000000 --- a/setup.cfg +++ /dev/null @@ -1,14 +0,0 @@ -[aliases] -test = pytest - -[check-manifest] -ignore = - .travis.yml - violations.flake8.txt - -[flake8] -ignore = E111,E124,E126,E221,E501 - -[pep8] -ignore = E111,E124,E126,E221,E501 -max-line-length = 100 diff --git a/setup.py b/setup.py deleted file mode 100755 index b8dd958..0000000 --- a/setup.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - -import codecs -import os -import re - -from setuptools import find_packages, setup - -cwd = os.path.abspath(os.path.dirname(__file__)) - - -def read(filename): - with codecs.open(os.path.join(cwd, filename), "rb", "utf-8") as h: - return h.read() - - -metadata = read(os.path.join(cwd, "herepy", "__init__.py")) - - -def extract_metaitem(meta): - meta_match = re.search( - r"""^__{meta}__\s+=\s+['\"]([^'\"]*)['\"]""".format(meta=meta), - metadata, - re.MULTILINE, - ) - if meta_match: - return meta_match.group(1) - raise RuntimeError("Unable to find __{meta}__ string.".format(meta=meta)) - - -with open("requirements.txt") as f: - requirements = f.read().splitlines() - -setup( - name="herepy", - version=extract_metaitem("version"), - license=extract_metaitem("license"), - description=extract_metaitem("description"), - long_description=(read("README.rst")), - long_description_content_type="text/x-rst", - author=extract_metaitem("author"), - author_email=extract_metaitem("email"), - maintainer=extract_metaitem("author"), - maintainer_email=extract_metaitem("email"), - url=extract_metaitem("url"), - download_url=extract_metaitem("download_url"), - packages=find_packages(exclude=("tests", "docs")), - package_data={"herepy": ["py.typed"]}, - platforms=["Any"], - python_requires=">=3.8", - install_requires=requirements, - keywords="here api, here technologies, here python api clients, rest api clients", - classifiers=[ - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Topic :: Software Development :: Libraries :: Python Modules", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - ], -) diff --git a/src/herepy/__init__.py b/src/herepy/__init__.py new file mode 100644 index 0000000..a6d33e0 --- /dev/null +++ b/src/herepy/__init__.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python + +"""A library that provides a Python interface to the HERE APIs.""" + +__author__ = "Abdullah Selek" +__email__ = "abdullahselek.os@gmail.com" +__copyright__ = "Copyright (c) 2017 Abdullah Selek" +__license__ = "MIT License" +__version__ = "3.6.5" +__url__ = "https://github.com/abdullahselek/HerePy" +__download_url__ = "https://pypi.org/pypi/herepy" +__description__ = "A library that provides a Python interface to the HERE APIs" + +from .destination_weather_api import DestinationWeatherApi +from .error import AccessDeniedError, HEREError, InvalidRequestError, UnauthorizedError +from .ev_charging_stations_api import EVChargingStationsApi +from .fleet_telematics_api import FleetTelematicsApi +from .geocoder_api import GeocoderApi +from .geocoder_autocomplete_api import GeocoderAutoCompleteApi +from .geocoder_reverse_api import GeocoderReverseApi +from .here_enum import ( + AerialMapTileResourceType, + AvoidFeature, + BaseMapTileResourceType, + EVStationConnectorTypes, + FlowProximityAdditionalAttributes, + IncidentsCriticalityInt, + IncidentsCriticalityStr, + IsolineRoutingMode, + IsolineRoutingOptimizationMode, + IsolineRoutingRangeType, + IsolineRoutingTransportMode, + MapImageFormatType, + MapImageResourceType, + MapTileApiType, + MapTileResourceType, + MatrixRoutingMode, + MatrixRoutingProfile, + MatrixRoutingTransportMode, + MatrixRoutingType, + MatrixSummaryAttribute, + MultiplePickupOfferType, + PlacesCategory, + PublicTransitModeType, + PublicTransitRoutingMode, + PublicTransitSearchMethod, + RouteMode, + RoutingApiReturnField, + RoutingApiSpanField, + RoutingMetric, + RoutingMode, + RoutingTransportMode, + ShippedHazardousGood, + TrafficMapTileResourceType, + TruckType, + TunnelCategory, + VectorMapTileLayer, + WeatherProductType, +) +from .isoline_routing_api import IsolineRoutingApi +from .map_image_api import MapImageApi +from .map_tile_api import MapTileApi +from .mercator_projection import MercatorProjection +from .models import ( + DestinationWeatherResponse, + EVChargingStationsResponse, + GeocoderAutoCompleteResponse, + GeocoderResponse, + GeocoderReverseResponse, + IsolineRoutingResponse, + PlacesResponse, + PublicTransitResponse, + RmeResponse, + RoutingMatrixResponse, + RoutingResponse, + RoutingResponseV8, + TrafficFlowAvailabilityResponse, + TrafficFlowResponse, + TrafficIncidentResponse, + WaypointSequenceResponse, +) +from .objects import Avoid, AvoidArea, Truck +from .places_api import PlacesApi +from .platform.tour_planning_api import TourPlanningApi +from .public_transit_api import PublicTransitApi +from .rme_api import RmeApi +from .routing_api import ( + InvalidCredentialsError, + InvalidInputDataError, + LinkIdNotFoundError, + NoRouteFoundError, + RouteNotReconstructedError, + RoutingApi, + WaypointNotFoundError, +) +from .traffic_api import TrafficApi +from .utils import Utils +from .vector_tile_api import VectorTileApi + +__all__ = [ + "DestinationWeatherApi", + "AccessDeniedError", + "HEREError", + "InvalidRequestError", + "UnauthorizedError", + "EVChargingStationsApi", + "FleetTelematicsApi", + "GeocoderApi", + "GeocoderAutoCompleteApi", + "GeocoderReverseApi", + "AerialMapTileResourceType", + "AvoidFeature", + "BaseMapTileResourceType", + "EVStationConnectorTypes", + "FlowProximityAdditionalAttributes", + "IncidentsCriticalityInt", + "IncidentsCriticalityStr", + "IsolineRoutingMode", + "IsolineRoutingOptimizationMode", + "IsolineRoutingRangeType", + "IsolineRoutingTransportMode", + "MapImageFormatType", + "MapImageResourceType", + "MapTileApiType", + "MapTileResourceType", + "MatrixRoutingMode", + "MatrixRoutingProfile", + "MatrixRoutingTransportMode", + "MatrixRoutingType", + "MatrixSummaryAttribute", + "MultiplePickupOfferType", + "PlacesCategory", + "PublicTransitModeType", + "PublicTransitRoutingMode", + "PublicTransitSearchMethod", + "RouteMode", + "RoutingApiReturnField", + "RoutingApiSpanField", + "RoutingMetric", + "RoutingMode", + "RoutingTransportMode", + "ShippedHazardousGood", + "TrafficMapTileResourceType", + "TruckType", + "TunnelCategory", + "VectorMapTileLayer", + "WeatherProductType", + "IsolineRoutingApi", + "MapImageApi", + "MapTileApi", + "MercatorProjection", + "DestinationWeatherResponse", + "EVChargingStationsResponse", + "GeocoderAutoCompleteResponse", + "GeocoderResponse", + "GeocoderReverseResponse", + "IsolineRoutingResponse", + "PlacesResponse", + "PublicTransitResponse", + "RmeResponse", + "RoutingMatrixResponse", + "RoutingResponse", + "RoutingResponseV8", + "TrafficFlowAvailabilityResponse", + "TrafficFlowResponse", + "TrafficIncidentResponse", + "WaypointSequenceResponse", + "Avoid", + "AvoidArea", + "Truck", + "PlacesApi", + "TourPlanningApi", + "PublicTransitApi", + "RmeApi", + "InvalidCredentialsError", + "InvalidInputDataError", + "LinkIdNotFoundError", + "NoRouteFoundError", + "RouteNotReconstructedError", + "RoutingApi", + "WaypointNotFoundError", + "TrafficApi", + "Utils", + "VectorTileApi", +] diff --git a/herepy/destination_weather_api.py b/src/herepy/destination_weather_api.py similarity index 79% rename from herepy/destination_weather_api.py rename to src/herepy/destination_weather_api.py index 40faaef..5d62471 100644 --- a/herepy/destination_weather_api.py +++ b/src/herepy/destination_weather_api.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +"""Module for the HERE Destination Weather API.""" + import json import sys -from typing import Optional import requests @@ -14,28 +15,28 @@ class DestinationWeatherApi(HEREApi): - """A python interface into the HERE Destination Weather API""" + """A python interface into the HERE Destination Weather API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a DestinationWeatherApi instance. + """ + Initialize a DestinationWeatherApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(DestinationWeatherApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://weather.cc.api.here.com/weather/1.0/report.json" def _get(self, data, product): url = Utils.build_url(self._base_url, extra_params=data) response = requests.get(url, timeout=self._timeout) json_data = json.loads(response.content.decode("utf8")) - if json_data.get(self._product_node(product)) != None: - return DestinationWeatherResponse.new_from_jsondict( - json_data, param_defaults={self._product_node(product): None} - ) + if json_data.get(self._product_node(product)) is not None: + return DestinationWeatherResponse.new_from_jsondict(json_data, param_defaults={self._product_node(product): None}) else: error = self._get_error_from_response(json_data) raise error @@ -45,9 +46,7 @@ def _get_error_from_response(self, json_data): if json_data["error"] == "Unauthorized": return UnauthorizedError(json_data["error_description"]) error_type = json_data.get("Type") - error_message = json_data.get( - "Message", "Error occurred on " + sys._getframe(1).f_code.co_name - ) + error_message = json_data.get("Message", "Error occurred on " + sys._getframe(1).f_code.co_name) if error_type == "Invalid Request": return InvalidRequestError(error_message) else: @@ -75,8 +74,10 @@ def weather_for_location_name( product: WeatherProductType, one_observation: bool = True, metric: bool = True, - ) -> Optional[DestinationWeatherResponse]: - """Request the product for given location name. + ) -> DestinationWeatherResponse | None: + """ + Request the product for given location name. + Args: location_name (str): Location name. @@ -86,17 +87,18 @@ def weather_for_location_name( Limit the result to the best mapped weather station. metric (bool): Use the metric system. + Returns: DestinationWeatherResponse Raises: HEREError - """ + """ data = { "apiKey": self._api_key, "product": product.__str__(), - "oneobservation": "true" if one_observation == True else "false", - "metric": "true" if metric == True else "false", + "oneobservation": "true" if one_observation else "false", + "metric": "true" if metric else "false", "name": location_name, } return self._get(data, product) @@ -107,8 +109,10 @@ def weather_for_zip_code( product: WeatherProductType, one_observation: bool = True, metric: bool = True, - ) -> Optional[DestinationWeatherResponse]: - """Request the product for given location name. + ) -> DestinationWeatherResponse | None: + """ + Request the product for given zip code. + Args: zip_code (int): U.S. zip code. @@ -118,17 +122,18 @@ def weather_for_zip_code( Limit the result to the best mapped weather station. metric (bool): Use the metric system. + Returns: DestinationWeatherResponse Raises: HEREError - """ + """ data = { "apiKey": self._api_key, "product": product.__str__(), - "oneobservation": "true" if one_observation == True else "false", - "metric": "true" if metric == True else "false", + "oneobservation": "true" if one_observation else "false", + "metric": "true" if metric else "false", "zipcode": zip_code, } return self._get(data, product) @@ -140,8 +145,10 @@ def weather_for_coordinates( product: WeatherProductType, one_observation: bool = True, metric: bool = True, - ) -> Optional[DestinationWeatherResponse]: - """Request the product for given location name. + ) -> DestinationWeatherResponse | None: + """ + Request the product for given coordinates. + Args: latitude (float): Latitude. @@ -153,17 +160,18 @@ def weather_for_coordinates( Limit the result to the best mapped weather station. metric (bool): Use the metric system. + Returns: DestinationWeatherResponse Raises: HEREError - """ + """ data = { "apiKey": self._api_key, "product": product.__str__(), - "oneobservation": "true" if one_observation == True else "false", - "metric": "true" if metric == True else "false", + "oneobservation": "true" if one_observation else "false", + "metric": "true" if metric else "false", "latitude": latitude, "longitude": longitude, } diff --git a/herepy/error.py b/src/herepy/error.py similarity index 75% rename from herepy/error.py rename to src/herepy/error.py index 199bc03..32319f3 100644 --- a/herepy/error.py +++ b/src/herepy/error.py @@ -1,9 +1,10 @@ #!/usr/bin/env python +"""Base error classes for the HERE API.""" -class HEREError(Exception): - """Base class for HERE errors""" +class HEREError(Exception): + """Base class for HERE errors.""" @property def message(self): @@ -12,24 +13,24 @@ def message(self): class UnauthorizedError(HEREError): - - """Unauthorized Error Type. + """ + Unauthorized Error Type. Indicates authentication failure, invalid credentials were supplied. """ class AccessDeniedError(HEREError): - - """Access Denied Error Type. + """ + Access Denied Error Type. Indicates the request is not permitted with the credentials provided. """ class InvalidRequestError(HEREError): - - """Invalid Request Error Type. + """ + Invalid Request Error Type. Indicates an invalid or missing parameter value in the request, for example value given for the product parameter does not exist. """ diff --git a/herepy/ev_charging_stations_api.py b/src/herepy/ev_charging_stations_api.py similarity index 77% rename from herepy/ev_charging_stations_api.py rename to src/herepy/ev_charging_stations_api.py index 8d390fd..62f6ad3 100644 --- a/herepy/ev_charging_stations_api.py +++ b/src/herepy/ev_charging_stations_api.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +"""Module for the HERE EV Charging Stations API.""" + import json import sys -from typing import List, Optional import requests @@ -13,17 +14,19 @@ class EVChargingStationsApi: - """A python interface into the HERE EV Charging Stations API""" + """A python interface into the HERE EV Charging Stations API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a EVChargingStationsApi instance. + """ + Initialize a EVChargingStationsApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ + """ self._api_key = api_key if timeout: self._timeout = timeout @@ -40,14 +43,14 @@ def __get(self, base_url, data, response_cls): else: raise error_from_ev_charging_service_error(json_data) - def __connector_types_str(self, connector_types: List[EVStationConnectorTypes]): + def __connector_types_str(self, connector_types: list[EVStationConnectorTypes]): connector_types_str = "" for connector_type in connector_types: connector_types_str += str.format("{0},", connector_type._value_) connector_types_str = connector_types_str[:-1] return connector_types_str - def __corridor_str(self, points: List[float]): + def __corridor_str(self, points: list[float]): if len(points) % 2 != 0: points = points[:-1] corridor_str = "" @@ -61,14 +64,17 @@ def get_stations_circular_search( latitude: float, longitude: float, radius: int, - connectortypes: List[EVStationConnectorTypes] = None, + connectortypes: list[EVStationConnectorTypes] = None, maxresults: int = 50, offset: int = 0, - ) -> Optional[EVChargingStationsResponse]: - """Makes a search request for charging stations. - A circular search area defined by the latitude and longitude of its center - (compliant with WGS 84) and an integer representing the radius of the area - in meters, all separated by commas. + ) -> EVChargingStationsResponse | None: + """ + Make a search request for charging stations. + + A circular search area defined by the latitude and longitude of its center + (compliant with WGS 84) and an integer representing the radius of the area + in meters, all separated by commas. + Args: latitude (float): latitude. @@ -82,14 +88,16 @@ def get_stations_circular_search( The maximum number of results a response can contain. This parameter can be used with the offset parameter in the query and HasMore in the response for pagination. offset (int): - A value specifying the index of the first result. The offset together with the "maxresults" value can be used to support a paging mechanism on search results. + A value specifying the index of the first result. The offset together with the + "maxresults" value can be used to support a paging mechanism on search results. This parameter can be used with the maxresults parameter in the query and HasMore in the response for pagination. + Returns: EVChargingStationsResponse Raises: HEREError - """ + """ if connectortypes: connector_types_str = self.__connector_types_str(connectortypes) data = { @@ -106,21 +114,21 @@ def get_stations_circular_search( "maxresults": maxresults, "offset": offset, } - response = self.__get( - self._base_url + "stations.json", data, EVChargingStationsResponse - ) + response = self.__get(self._base_url + "stations.json", data, EVChargingStationsResponse) return response def get_stations_bounding_box( self, - top_left: List[float], - bottom_right: List[float], - connectortypes: List[EVStationConnectorTypes] = None, + top_left: list[float], + bottom_right: list[float], + connectortypes: list[EVStationConnectorTypes] = None, maxresults: int = 50, offset: int = 0, - ) -> Optional[EVChargingStationsResponse]: - """Makes a search request for charging stations with in given - bounding box. The bounding box can have a maximum height / width of 400km. + ) -> EVChargingStationsResponse | None: + """ + Make a search request for charging stations with in given + bounding box. The bounding box can have a maximum height / width of 400km. + Args: top_left (List): List contains latitude and longitude in order. @@ -132,14 +140,16 @@ def get_stations_bounding_box( The maximum number of results a response can contain. This parameter can be used with the offset parameter in the query and HasMore in the response for pagination. offset (int): - A value specifying the index of the first result. The offset together with the "maxresults" value can be used to support a paging mechanism on search results. + A value specifying the index of the first result. The offset together with the + "maxresults" value can be used to support a paging mechanism on search results. This parameter can be used with the maxresults parameter in the query and HasMore in the response for pagination. + Returns: EVChargingStationsResponse Raises: HEREError - """ + """ if connectortypes: connector_types_str = self.__connector_types_str(connectortypes) data = { @@ -168,20 +178,20 @@ def get_stations_bounding_box( "maxresults": maxresults, "offset": offset, } - response = self.__get( - self._base_url + "stations.json", data, EVChargingStationsResponse - ) + response = self.__get(self._base_url + "stations.json", data, EVChargingStationsResponse) return response def get_stations_corridor( self, - points: List[float], - connectortypes: List[EVStationConnectorTypes] = None, + points: list[float], + connectortypes: list[EVStationConnectorTypes] = None, maxresults: int = 50, offset: int = 0, - ) -> Optional[EVChargingStationsResponse]: - """Makes a search request for charging stations with in given corridor. - Maximum corridor area is 5000 km2. + ) -> EVChargingStationsResponse | None: + """ + Makes a search request for charging stations with in given corridor. + Maximum corridor area is 5000 km2. + Args: points (List): List contains latitude and longitude pairs in order. @@ -191,14 +201,16 @@ def get_stations_corridor( The maximum number of results a response can contain. This parameter can be used with the offset parameter in the query and HasMore in the response for pagination. offset (int): - A value specifying the index of the first result. The offset together with the "maxresults" value can be used to support a paging mechanism on search results. + A value specifying the index of the first result. The offset together with the + "maxresults" value can be used to support a paging mechanism on search results. This parameter can be used with the maxresults parameter in the query and HasMore in the response for pagination. + Returns: EVChargingStationsResponse Raises: HEREError - """ + """ if connectortypes: connector_types_str = self.__connector_types_str(connectortypes) data = { @@ -215,16 +227,16 @@ def get_stations_corridor( "maxresults": maxresults, "offset": offset, } - response = self.__get( - self._base_url + "stations.json", data, EVChargingStationsResponse - ) + response = self.__get(self._base_url + "stations.json", data, EVChargingStationsResponse) return response - def get_station_details( - self, station_id: str, maxresults: int = 50, offset: int = 0 - ) -> Optional[EVChargingStationsResponse]: - """Based on the results of a search for charging stations, this method + def get_station_details(self, station_id: str, maxresults: int = 50, offset: int = 0) -> EVChargingStationsResponse | None: + """ + Retrieve the full/updated information about a single charging station only. + + Based on the results of a search for charging stations, this method retrieves the full/updated information about a single charging station only. + Args: station_id (str): station_id is an attribute of the evStation element with a unique value. @@ -232,14 +244,16 @@ def get_station_details( The maximum number of results a response can contain. This parameter can be used with the offset parameter in the query and HasMore in the response for pagination. offset (int): - A value specifying the index of the first result. The offset together with the "maxresults" value can be used to support a paging mechanism on search results. + A value specifying the index of the first result. The offset together with the + "maxresults" value can be used to support a paging mechanism on search results. This parameter can be used with the maxresults parameter in the query and HasMore in the response for pagination. + Returns: EVChargingStationsResponse Raises: HEREError - """ + """ data = {"apiKey": self._api_key, "maxresults": maxresults, "offset": offset} url = self._base_url + "stations/" + station_id + ".json" response = self.__get(url, data, EVChargingStationsResponse) @@ -247,8 +261,8 @@ def get_station_details( class UnauthorizedError(HEREError): - - """Unauthorized Error Type. + """ + Unauthorized Error Type. This error is returned if the specified token was invalid or no contract could be found for this token. @@ -257,8 +271,7 @@ class UnauthorizedError(HEREError): # pylint: disable=R0911 def error_from_ev_charging_service_error(json_data: dict): - """Return the correct subclass for ev charging errors""" - + """Return the correct subclass for ev charging errors.""" if "Type" in json_data: error_type = json_data["Type"] message = json_data["Message"] @@ -266,11 +279,6 @@ def error_from_ev_charging_service_error(json_data: dict): if error_type == "Unauthorized": return UnauthorizedError(message) elif "error" in json_data and "error_description" in json_data: - return HEREError( - "Error occurred: " - + json_data["error"] - + ", description: " - + json_data["error_description"] - ) + return HEREError("Error occurred: " + json_data["error"] + ", description: " + json_data["error_description"]) # pylint: disable=W0212 return HEREError("Error occurred on " + sys._getframe(1).f_code.co_name) diff --git a/herepy/fleet_telematics_api.py b/src/herepy/fleet_telematics_api.py similarity index 83% rename from herepy/fleet_telematics_api.py rename to src/herepy/fleet_telematics_api.py index 232952a..2bb9079 100644 --- a/herepy/fleet_telematics_api.py +++ b/src/herepy/fleet_telematics_api.py @@ -1,42 +1,46 @@ #!/usr/bin/env python +"""A python interface into the HERE Fleet Telematics API.""" + import json import sys -from typing import List, Optional import requests from herepy.error import HEREError from herepy.here_api import HEREApi -from herepy.here_enum import MultiplePickupOfferType, RouteMode +from herepy.here_enum import RouteMode from herepy.models import WaypointSequenceResponse from herepy.utils import Utils class FleetTelematicsApi(HEREApi): - """A python interface into the HERE Fleet Telematics API""" + """A python interface into the HERE Fleet Telematics API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a FleetTelematicsApi instance. + """ + Initialize a FleetTelematicsApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. + Returns: FleetTelematicsApi instance. - """ - super(FleetTelematicsApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://wse.ls.hereapi.com/2/" def __create_find_sequence_parameters( self, start: str, departure: str, - intermediate_destinations: List[str], + intermediate_destinations: list[str], end: str, - modes: List[RouteMode], + modes: list[RouteMode], ): data = { "apiKey": self._api_key, @@ -62,7 +66,7 @@ def __create_find_sequence_parameters( def __create_find_pickup_parameters( self, - modes: List[RouteMode], + modes: list[RouteMode], start: str, departure: str, capacity: int, @@ -71,7 +75,7 @@ def __create_find_pickup_parameters( max_detour: int, rest_times: str, end: str, - intermediate_destinations: List[str], + intermediate_destinations: list[str], ): data = {} @@ -90,9 +94,7 @@ def __create_find_pickup_parameters( count = 0 for destination_pickup_param in intermediate_destinations: - data[str.format("destination{0}", count)] = ( - str.format("waypoint{0};", count + 1) + destination_pickup_param - ) + data[str.format("destination{0}", count)] = str.format("waypoint{0};", count + 1) + destination_pickup_param count += 1 data["end"] = str.format("waypoint{0};{1}", count + 1, end) @@ -111,11 +113,13 @@ def find_sequence( self, start: str, departure: str, - intermediate_destinations: List[str], + intermediate_destinations: list[str], end: str, - modes: List[RouteMode], - ) -> Optional[WaypointSequenceResponse]: - """Finds time-optimized waypoint sequence route. + modes: list[RouteMode], + ) -> WaypointSequenceResponse | None: + """ + Find time-optimized waypoint sequence route. + Args: start (str): Starting point. `str.format('{0};{1},{2}', text, latitude, longitude)` @@ -127,12 +131,13 @@ def find_sequence( End point. `str.format('{0};{1},{2}', text, latitude, longitude)` modes (List[RouteMode]): Route modes. + Returns: WaypointSequenceResponse Raises: HEREError - """ + """ data = self.__create_find_sequence_parameters( start=start, departure=departure, @@ -140,14 +145,12 @@ def find_sequence( end=end, modes=modes, ) - response = self.__get( - self._base_url + "findsequence.json", data, WaypointSequenceResponse - ) + response = self.__get(self._base_url + "findsequence.json", data, WaypointSequenceResponse) return response def find_pickups( self, - modes: List[RouteMode], + modes: list[RouteMode], start: str, departure: str, capacity: int, @@ -155,10 +158,12 @@ def find_pickups( driver_cost: int, max_detour: int, rest_times: str, - intermediate_destinations: List[str], + intermediate_destinations: list[str], end: str, - ) -> Optional[WaypointSequenceResponse]: - """Finds cheaper route by picking up some additional goods along the route. + ) -> WaypointSequenceResponse | None: + """ + Find cheaper route by picking up some additional goods along the route. + Args: modes (List[RouteMode]): Route modes. @@ -185,7 +190,8 @@ def find_pickups( `default` Use internal default. The default are simplified European rules: After 4.5h driving 45min rest and after 9h driving 11h rest. `durations:...` and `serviceTimes:...` - You can provide values for driving and rest periods and define if service times at waypoints can be used for resting. You must provide both parameters. + You can provide values for driving and rest periods and define if service times at waypoints + can be used for resting. You must provide both parameters. intermediate_destinations (List[DestinationPickupParam]): Intermediate destinations, at least one. If no end parameter is provided, one of these values is selected as end of the sequence. @@ -197,12 +203,13 @@ def find_pickups( param_type, item)` end (str): End of the journey. `str.format('{0};{1},{2}', text, latitude, longitude)` + Returns: WaypointSequenceResponse Raises: HEREError - """ + """ data = self.__create_find_pickup_parameters( modes=modes, start=start, @@ -215,23 +222,21 @@ def find_pickups( intermediate_destinations=intermediate_destinations, end=end, ) - response = self.__get( - self._base_url + "findpickups.json", data, WaypointSequenceResponse - ) + response = self.__get(self._base_url + "findpickups.json", data, WaypointSequenceResponse) return response class UnauthorizedError(HEREError): + """ + Unauthorized Error Type. - """Unauthorized Error Type. This error is returned if the specified token was invalid or no contract could be found for this token. """ def error_from_fleet_telematics_service_error(json_data: dict): - """Return the correct subclass for sequence errors""" - + """Return the correct subclass for sequence errors.""" if "error" in json_data: error_type = json_data["error"] message = json_data["error_description"] diff --git a/herepy/geocoder_api.py b/src/herepy/geocoder_api.py similarity index 75% rename from herepy/geocoder_api.py rename to src/herepy/geocoder_api.py index e84d400..468b023 100644 --- a/herepy/geocoder_api.py +++ b/src/herepy/geocoder_api.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +"""Module for the HERE Geocoder API.""" + import json import sys -from typing import List, Optional import requests @@ -13,18 +14,20 @@ class GeocoderApi(HEREApi): - """A python interface into the HERE Geocoder API""" + """A python interface into the HERE Geocoder API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a GeocoderApi instance. + """ + Initialize a GeocoderApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(GeocoderApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://geocode.search.hereapi.com/v1/geocode" def __get(self, data): @@ -32,7 +35,7 @@ def __get(self, data): response = requests.get(url, timeout=self._timeout) try: json_data = json.loads(response.content.decode("utf8")) - if json_data.get("items") != None: + if json_data.get("items") is not None: return GeocoderResponse.new_from_jsondict(json_data) elif json_data["error"] == "Unauthorized": raise UnauthorizedError(json_data["error_description"]) @@ -44,38 +47,37 @@ def __get(self, data): ) ) except ValueError as err: - raise HEREError( - "Error occurred on function " - + sys._getframe(1).f_code.co_name - + " " - + str(err) - ) - - def free_form( - self, searchtext: str, lang: str = "en-US" - ) -> Optional[GeocoderResponse]: - """Geocodes given search text + raise HEREError("Error occurred on function " + sys._getframe(1).f_code.co_name + " " + str(err)) + + def free_form(self, searchtext: str, lang: str = "en-US") -> GeocoderResponse | None: + """ + Geocodes given search text. + Args: searchtext (str): possible address text. lang (str): BCP47 compliant Language Code. + Returns: GeocoderResponse Raises: - HEREError""" + HEREError + """ data = {"q": searchtext, "apiKey": self._api_key, "lang": lang} return self.__get(data) def address_with_boundingbox( self, searchtext: str, - top_left: List[float], - bottom_right: List[float], + top_left: list[float], + bottom_right: list[float], lang: str = "en-US", - ) -> Optional[GeocoderResponse]: - """Geocodes given search text with in given boundingbox + ) -> GeocoderResponse | None: + """ + Geocodes given search text with in given boundingbox. + Args: searchtext (str): possible address text. @@ -85,11 +87,13 @@ def address_with_boundingbox( List contains latitude and longitude in order. lang (str): BCP47 compliant Language Code. + Returns: GeocoderResponse Raises: - HEREError""" + HEREError + """ data = { "q": searchtext, "mapView": str.format( @@ -106,14 +110,16 @@ def address_with_boundingbox( def address_with_details( self, - house_number: Optional[int] = None, - street: Optional[str] = None, - city: Optional[str] = None, - postal_code: Optional[str] = None, - country: Optional[str] = None, + house_number: int | None = None, + street: str | None = None, + city: str | None = None, + postal_code: str | None = None, + country: str | None = None, lang: str = "en-US", - ) -> Optional[GeocoderResponse]: - """Geocodes with given address details + ) -> GeocoderResponse | None: + """ + Geocodes with given address details. + Args: house_number (int): house number. @@ -127,11 +133,13 @@ def address_with_details( postal code. lang (str): BCP47 compliant Language Code. + Returns: GeocoderResponse Raises: - HEREError""" + HEREError + """ qq_params = [] if house_number is not None: qq_params.append(f"houseNumber={house_number}") @@ -154,10 +162,10 @@ def address_with_details( } return self.__get(data) - def street_intersection( - self, street: str, city: str, lang: str = "en-US" - ) -> Optional[GeocoderResponse]: - """Geocodes with given street and city + def street_intersection(self, street: str, city: str, lang: str = "en-US") -> GeocoderResponse | None: + """ + Geocodes with given street and city. + Args: street (str): street name. @@ -165,11 +173,13 @@ def street_intersection( city name. lang (str): BCP47 compliant Language Code. + Returns: GeocoderResponse Raises: - HEREError""" + HEREError + """ data = { "qq": str.format("street={0};", street) + str.format("city={0}", city), "apiKey": self._api_key, diff --git a/herepy/geocoder_autocomplete_api.py b/src/herepy/geocoder_autocomplete_api.py similarity index 75% rename from herepy/geocoder_autocomplete_api.py rename to src/herepy/geocoder_autocomplete_api.py index 0ca68bd..90e4ed3 100644 --- a/herepy/geocoder_autocomplete_api.py +++ b/src/herepy/geocoder_autocomplete_api.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +"""Module for the HERE Geocoder Auto Complete API.""" + import json import sys -from typing import List, Optional import requests @@ -13,25 +14,27 @@ class GeocoderAutoCompleteApi(HEREApi): - """A python interface into the HERE Geocoder Auto Complete API""" + """A python interface into the HERE Geocoder Auto Complete API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a GeocoderAutoCompleteApi instance. + """ + Initialize a GeocoderAutoCompleteApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(GeocoderAutoCompleteApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://autocomplete.search.hereapi.com/v1/autocomplete" def __get(self, data): url = Utils.build_url(self._base_url, extra_params=data) response = requests.get(url, timeout=self._timeout) json_data = json.loads(response.content.decode("utf8")) - if json_data.get("items") != None: + if json_data.get("items") is not None: return GeocoderAutoCompleteResponse.new_from_jsondict(json_data) else: raise HEREError( @@ -41,10 +44,10 @@ def __get(self, data): ) ) - def address_suggestion( - self, query: str, prox: List[float], radius: int, lang: str = "en-US" - ) -> Optional[GeocoderAutoCompleteResponse]: - """Request a list of suggested addresses found within a specified area + def address_suggestion(self, query: str, prox: list[float], radius: int, lang: str = "en-US") -> GeocoderAutoCompleteResponse | None: + """ + Request a list of suggested addresses found within a specified area. + Args: query (str): Query search string @@ -54,11 +57,13 @@ def address_suggestion( Radius in meters lang (str): BCP47 compliant Language Code. + Returns: GeocoderAutoCompleteResponse Raises: - HEREError""" + HEREError + """ data = { "q": query, "prox": str.format("{0},{1},{2}", prox[0], prox[1], radius), @@ -67,10 +72,10 @@ def address_suggestion( } return self.__get(data) - def limit_results_byaddress( - self, query: str, country_code: str, lang: str = "en-US" - ) -> Optional[GeocoderAutoCompleteResponse]: - """Request a list of suggested addresses within a single country + def limit_results_byaddress(self, query: str, country_code: str, lang: str = "en-US") -> GeocoderAutoCompleteResponse | None: + """ + Request a list of suggested addresses within a single country. + Args: query (str): Query search string @@ -78,11 +83,13 @@ def limit_results_byaddress( Country code (USA etc.) lang (str): BCP47 compliant Language Code. + Returns: GeocoderAutoCompleteResponse Raises: - HEREError""" + HEREError + """ data = { "q": query, "in": "countryCode:" + country_code, diff --git a/herepy/geocoder_reverse_api.py b/src/herepy/geocoder_reverse_api.py similarity index 74% rename from herepy/geocoder_reverse_api.py rename to src/herepy/geocoder_reverse_api.py index b678a24..66ae422 100644 --- a/herepy/geocoder_reverse_api.py +++ b/src/herepy/geocoder_reverse_api.py @@ -1,8 +1,9 @@ #!/usr/bin/env python +"""Module for the HERE Geocoder Reverse API.""" + import json import sys -from typing import List, Optional import requests @@ -13,18 +14,20 @@ class GeocoderReverseApi(HEREApi): - """A python interface into the HERE Geocoder Reverse API""" + """A python interface into the HERE Geocoder Reverse API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a GeocoderApi instance. + """ + Initialize a GeocoderReverseApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(GeocoderReverseApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://revgeocode.search.hereapi.com/v1/revgeocode" def __get(self, data): @@ -32,7 +35,7 @@ def __get(self, data): response = requests.get(url, timeout=self._timeout) try: json_data = json.loads(response.content.decode("utf8")) - if json_data.get("items") != None: + if json_data.get("items") is not None: return GeocoderReverseResponse.new_from_jsondict(json_data) elif "error" in json_data: if json_data["error"] == "Unauthorized": @@ -45,17 +48,12 @@ def __get(self, data): ) ) except ValueError as err: - raise HEREError( - "Error occurred on function " - + sys._getframe(1).f_code.co_name - + " " - + str(err) - ) + raise HEREError("Error occurred on function " + sys._getframe(1).f_code.co_name + " " + str(err)) + + def retrieve_addresses(self, prox: list[float], limit: int = 1, lang: str = "en-US") -> GeocoderReverseResponse | None: + """ + Gets the address information of a point. - def retrieve_addresses( - self, prox: List[float], limit: int = 1, lang: str = "en-US" - ) -> Optional[GeocoderReverseResponse]: - """Gets the address information of a point. Args: prox (lat/lon): latitude longitude of the point @@ -63,11 +61,13 @@ def retrieve_addresses( Limits items to return, with default value 1. Max value 100. lang (str): BCP47 compliant Language Code. + Returns: GeocoderReverseResponse Raises: - HEREError""" + HEREError + """ data = { "at": str.format("{0},{1}", prox[0], prox[1]), "limit": limit, diff --git a/herepy/here_api.py b/src/herepy/here_api.py similarity index 85% rename from herepy/here_api.py rename to src/herepy/here_api.py index e36dcd3..f026ea0 100644 --- a/herepy/here_api.py +++ b/src/herepy/here_api.py @@ -1,18 +1,20 @@ #!/usr/bin/env python -class HEREApi(object): +class HEREApi: """Base class from which all wrappers inherit.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a Api instance. + """ + Returns a Api instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ + """ self.__set_credentials(api_key) if timeout: self._timeout = timeout @@ -20,9 +22,12 @@ def __init__(self, api_key: str = None, timeout: int = None): self._timeout = 20 def __set_credentials(self, api_key): - """Setter for credentials. + """ + Setter for credentials. + Args: api_key (str): API key taken from HERE Developer Portal. + """ self._api_key = api_key diff --git a/herepy/here_enum.py b/src/herepy/here_enum.py similarity index 67% rename from herepy/here_enum.py rename to src/herepy/here_enum.py index 58dbc9b..f44536c 100644 --- a/herepy/here_enum.py +++ b/src/herepy/here_enum.py @@ -21,8 +21,9 @@ class RouteMode(Enum): publicTransportTimeTable = "publicTransportTimeTable" truck = "truck" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the route mode.""" + return f"{self._value_}" class RoutingMode(Enum): @@ -31,8 +32,9 @@ class RoutingMode(Enum): fast = "fast" short = "short" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing mode.""" + return f"{self._value_}" class RoutingMetric(Enum): @@ -41,12 +43,13 @@ class RoutingMetric(Enum): metric = "metric" imperial = "imperial" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing metric.""" + return f"{self._value_}" class RoutingApiReturnField(Enum): - """Attributes are included in the response as part of data representation of a Route or Section..""" + """Attributes are included in the response as part of data representation of a Route or Section.""" polyline = "polyline" actions = "actions" @@ -61,8 +64,9 @@ class RoutingApiReturnField(Enum): incidents = "incidents" routingZones = "routingZones" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the return field.""" + return f"{self._value_}" class RoutingApiSpanField(Enum): @@ -89,8 +93,9 @@ class RoutingApiSpanField(Enum): routingZones = "routingZones" notices = "notices" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the span field.""" + return f"{self._value_}" class MatrixSummaryAttribute(Enum): @@ -99,8 +104,9 @@ class MatrixSummaryAttribute(Enum): travel_times = "travelTimes" distances = "distances" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the summary attribute.""" + return f"{self._value_}" class MatrixRoutingType(Enum): @@ -112,8 +118,9 @@ class MatrixRoutingType(Enum): polygon = "polygon" auto_circle = "autoCircle" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing type.""" + return f"{self._value_}" class MatrixRoutingProfile(Enum): @@ -125,8 +132,9 @@ class MatrixRoutingProfile(Enum): pedestrian = "pedestrian" bicycle = "bicycle" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing profile.""" + return f"{self._value_}" class MatrixRoutingMode(Enum): @@ -135,21 +143,25 @@ class MatrixRoutingMode(Enum): fast = "fast" short = "short" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing mode.""" + return f"{self._value_}" class MatrixRoutingTransportMode(Enum): - """Defines transport modes on Matrix Routing API. Depending on the transport mode special constraints, - speed attributes and weights are taken into account during route calculation.""" + """ + Defines transport modes on Matrix Routing API. Depending on the transport mode special constraints, + speed attributes and weights are taken into account during route calculation. + """ car = "car" truck = "truck" pedestrian = "pedestrian" bicycle = "bicycle" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the transport mode.""" + return f"{self._value_}" class PlacesCategory(Enum): @@ -173,32 +185,35 @@ class PlacesCategory(Enum): toilet_rest_area = "toilet-rest-area" transport = "transport" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the category.""" + return f"{self._value_}" class PublicTransitSearchMethod(Enum): - """Search methods used in public transit search function""" + """Search methods used in public transit search function.""" fuzzy = "fuzzy" strict = "strict" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the search method.""" + return f"{self._value_}" class PublicTransitRoutingMode(Enum): - """Routing types used in public transit api""" + """Routing types used in public transit api.""" schedule = "schedule" realtime = "realtime" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing mode.""" + return f"{self._value_}" class PublicTransitModeType(Enum): - """Mode types used in public transit api""" + """Mode types used in public transit api.""" high_speed_train = 0 intercity_train = 1 @@ -217,12 +232,13 @@ class PublicTransitModeType(Enum): flight = 14 walk = 20 - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the mode type.""" + return f"{self._value_}" class WeatherProductType(Enum): - """Identifis the type of report to obtain.""" + """Identifies the type of report to obtain.""" observation = "observation" forecast_7days = "forecast_7days" @@ -232,8 +248,9 @@ class WeatherProductType(Enum): alerts = "alerts" nws_alerts = "nws_alerts" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the product type.""" + return f"{self._value_}" class EVStationConnectorTypes(Enum): @@ -290,8 +307,9 @@ class EVStationConnectorTypes(Enum): domestic_plug_socket_type_a = 48 domestic_plug_socket_type_c = 49 - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the connector type.""" + return f"{self._value_}" class MultiplePickupOfferType(Enum): @@ -300,8 +318,9 @@ class MultiplePickupOfferType(Enum): pickup = "pickup" drop = "drop" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the offer type.""" + return f"{self._value_}" class IncidentsCriticalityStr(Enum): @@ -312,8 +331,9 @@ class IncidentsCriticalityStr(Enum): minor = "minor" lowImpact = "lowImpact" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the criticality level.""" + return f"{self._value_}" class IncidentsCriticalityInt(Enum): @@ -324,7 +344,8 @@ class IncidentsCriticalityInt(Enum): minor = 2 lowImpact = 3 - def __int__(self): + def __int__(self) -> int: + """Return the integer value of the criticality level.""" return self._value_ @@ -334,8 +355,9 @@ class FlowProximityAdditionalAttributes(Enum): functional_class = "fc" shape = "sh" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the attribute.""" + return f"{self._value_}" class IsolineRoutingMode(Enum): @@ -344,19 +366,21 @@ class IsolineRoutingMode(Enum): fast = "fast" short = "short" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the routing mode.""" + return f"{self._value_}" class IsolineRoutingTransportMode(Enum): - """Mode of transport to be used for the calculation of the isolines.""" + """Mode of transport to be used for the calculation of terms isolines.""" car = "car" truck = "truck" pedestrian = "pedestrian" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the transport mode.""" + return f"{self._value_}" class IsolineRoutingOptimizationMode(Enum): @@ -366,8 +390,9 @@ class IsolineRoutingOptimizationMode(Enum): performance = "performance" balanced = "balanced" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the optimization mode.""" + return f"{self._value_}" class IsolineRoutingRangeType(Enum): @@ -377,8 +402,9 @@ class IsolineRoutingRangeType(Enum): time = "time" consumption = "consumption" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the range type.""" + return f"{self._value_}" class MapTileApiType(Enum): @@ -388,13 +414,17 @@ class MapTileApiType(Enum): base = "base" traffic = "traffic" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the API type.""" + return f"{self._value_}" class MapTileResourceType(Enum): - def __str__(self): - return "%s" % self._value_ + """Base class for map tile resource types.""" + + def __str__(self) -> str: + """Return the string representation of the resource type.""" + return f"{self._value_}" class BaseMapTileResourceType(MapTileResourceType): @@ -443,17 +473,18 @@ class TrafficMapTileResourceType(MapTileResourceType): class VectorMapTileLayer(Enum): - """Type of Vector Map Tile Layer""" + """Type of Vector Map Tile Layer.""" base = "base" core = "core" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the layer.""" + return f"{self._value_}" class MapImageResourceType(Enum): - """Type of Map Image Resources""" + """Type of Map Image Resources.""" companylogo = "companylogo" heat = "heat" @@ -467,12 +498,13 @@ class MapImageResourceType(Enum): turnpoint = "turnpoint" version = "version" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the resource type.""" + return f"{self._value_}" class MapImageFormatType(Enum): - """Type of Map Image Formats""" + """Type of Map Image Formats.""" png = 0 jpeg = 1 @@ -483,7 +515,7 @@ class MapImageFormatType(Enum): class RoutingTransportMode(Enum): - """Transport modes of Routing API v8""" + """Transport modes of Routing API v8.""" car = "car" truck = "truck" @@ -493,8 +525,9 @@ class RoutingTransportMode(Enum): taxi = "taxi" bus = "bus" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the transport mode.""" + return f"{self._value_}" class AvoidFeature(Enum): @@ -506,8 +539,9 @@ class AvoidFeature(Enum): tunnel = "tunnel" dirt_road = "dirtRoad" - def __str__(self): - return "%s" % self._value_ + def __str__(self) -> str: + """Return the string representation of the avoid feature.""" + return f"{self._value_}" class ShippedHazardousGood(Enum): @@ -525,8 +559,9 @@ class ShippedHazardousGood(Enum): harmfulToWater = "harmfulToWater" other = "other" - def __str__(self): - return self._value_ + def __str__(self) -> str: + """Return the string representation of the hazardous good.""" + return f"{self._value_}" class TunnelCategory(Enum): @@ -537,8 +572,9 @@ class TunnelCategory(Enum): d = "D" e = "E" - def __str__(self): - return self._value_ + def __str__(self) -> str: + """Return the string representation of the category.""" + return f"{self._value_}" class TruckType(Enum): @@ -547,5 +583,6 @@ class TruckType(Enum): straight = "straight" tractor = "tractor" - def __str__(self): - return self._value_ + def __str__(self) -> str: + """Return the string representation of the truck type.""" + return f"{self._value_}" diff --git a/herepy/isoline_routing_api.py b/src/herepy/isoline_routing_api.py similarity index 80% rename from herepy/isoline_routing_api.py rename to src/herepy/isoline_routing_api.py index e891bb0..db92f16 100644 --- a/herepy/isoline_routing_api.py +++ b/src/herepy/isoline_routing_api.py @@ -1,32 +1,38 @@ #!/usr/bin/env python +"""Module for the HERE Isoline Routing API.""" + import json import sys -from typing import List, Optional import requests from herepy.error import HEREError, InvalidRequestError, UnauthorizedError from herepy.here_api import HEREApi -from herepy.here_enum import (IsolineRoutingMode, IsolineRoutingRangeType, - IsolineRoutingTransportMode) +from herepy.here_enum import ( + IsolineRoutingMode, + IsolineRoutingRangeType, + IsolineRoutingTransportMode, +) from herepy.models import IsolineRoutingResponse from herepy.utils import Utils class IsolineRoutingApi(HEREApi): - """A python interface into the HERE Isoline Routing API""" + """A python interface into the HERE Isoline Routing API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a IsolineRoutingApi instance. + """ + Initialize a IsolineRoutingApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(IsolineRoutingApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://isoline.router.hereapi.com/v8/isolines" def __get_error_from_response(self, json_data): @@ -34,9 +40,7 @@ def __get_error_from_response(self, json_data): if json_data["error"] == "Unauthorized": return UnauthorizedError(json_data["error_description"]) error_type = json_data.get("Type") - error_message = json_data.get( - "Message", "Error occurred on " + sys._getframe(1).f_code.co_name - ) + error_message = json_data.get("Message", "Error occurred on " + sys._getframe(1).f_code.co_name) if error_type == "Invalid Request": return InvalidRequestError(error_message) else: @@ -44,12 +48,7 @@ def __get_error_from_response(self, json_data): def __get_client_error_from_response(self, json_data): if "title" in json_data and "cause" in json_data: - return HEREError( - "Error on client: " - + json_data["title"] - + " cause: " - + json_data["cause"] - ) + return HEREError("Error on client: " + json_data["title"] + " cause: " + json_data["cause"]) else: return HEREError("herepy got a 400 from isoline router API") @@ -57,10 +56,8 @@ def __get(self, url, data, json_key): url = Utils.build_url(url, extra_params=data) response = requests.get(url, timeout=self._timeout) json_data = json.loads(response.content.decode("utf8")) - if json_data.get(json_key) != None and json_data.get("isolines") != None: - return IsolineRoutingResponse.new_from_jsondict( - json_data, param_defaults={json_key: None, "isolines": None} - ) + if json_data.get(json_key) is not None and json_data.get("isolines") is not None: + return IsolineRoutingResponse.new_from_jsondict(json_data, param_defaults={json_key: None, "isolines": None}) elif response.status_code == 400: error = self.__get_client_error_from_response(json_data=json_data) raise error @@ -71,12 +68,14 @@ def __get(self, url, data, json_key): def distance_based_isoline( self, transport_mode: IsolineRoutingTransportMode, - origin: List[float], - ranges: List[int], + origin: list[float], + ranges: list[int], routing_mode: IsolineRoutingMode, - ) -> Optional[IsolineRoutingResponse]: - """A distance-based isoline, also called an Isodistance, + ) -> IsolineRoutingResponse | None: + """ + A distance-based isoline, also called an Isodistance, can be requested using range[type]=distance and providing range[values] in meters. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -86,11 +85,13 @@ def distance_based_isoline( List of range values for isoline (in meters). routing_mode (IsolineRoutingMode): Isoline routing mode. + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] data = { "transportMode": transport_mode.__str__(), @@ -105,11 +106,13 @@ def distance_based_isoline( def time_isoline( self, transport_mode: IsolineRoutingTransportMode, - origin: List[float], - ranges: List[int], - ) -> Optional[IsolineRoutingResponse]: - """A time-based isoline, also called an Isochrone, + origin: list[float], + ranges: list[int], + ) -> IsolineRoutingResponse | None: + """ + A time-based isoline, also called an Isochrone, can be requested by using range[type]=time and providing range[values] in seconds. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -117,11 +120,13 @@ def time_isoline( List including latitude and longitude in order. ranges (List): List of range values for isoline (in meters). + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] data = { "transportMode": transport_mode.__str__(), @@ -134,19 +139,21 @@ def time_isoline( def isoline_based_on_consumption( self, - origin: List[float], - ranges: List[int], + origin: list[float], + ranges: list[int], transport_mode: IsolineRoutingTransportMode, - free_flow_speed_table: List[float], - traffic_speed_table: List[float], + free_flow_speed_table: list[float], + traffic_speed_table: list[float], ascent: int, descent: float, auxiliary_consumption: float, ): - """Electric vehicles have a limited reachable range based on their current battery + """ + Electric vehicles have a limited reachable range based on their current battery charge and factors affecting the rate of energy consumed, such as road slope or auxiliary power usage. Therefore, it is useful to visualize the appropriate range to avoid running out of energy before reaching a charging point. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -166,11 +173,13 @@ def isoline_based_on_consumption( Value of descent. auxiliary_consumption (float): Auxiliary consumption. + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] free_speed_table = [0] @@ -198,17 +207,19 @@ def isoline_based_on_consumption( def isoline_routing_at_specific_time( self, transport_mode: IsolineRoutingTransportMode, - ranges: List[int], - origin: Optional[List[float]] = None, - departure_time: Optional[str] = None, - destination: Optional[List[float]] = None, - arrival_time: Optional[str] = None, + ranges: list[int], + origin: list[float] | None = None, + departure_time: str | None = None, + destination: list[float] | None = None, + arrival_time: str | None = None, ): - """To calculate an isoline around an origin with a specific time, use departureTime. + """ + To calculate an isoline around an origin with a specific time, use departureTime. For a reverse isoline, that is, when using destination, you can use arrivalTime. If departureTime or arrivalTime are specified as "any", the isoline calculation will not take traffic flow and other time-dependent effects into account. This can be useful when it is not certain for what time of the day the isoline needs to be computed. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -222,11 +233,13 @@ def isoline_routing_at_specific_time( List including latitude and longitude in order. arrival_time (str): Arrival time of the planned routing in format yyyy-MM-ddThh:mm:ss. + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] if origin and departure_time: data = { @@ -249,19 +262,19 @@ def isoline_routing_at_specific_time( } return self.__get(self._base_url, data, "arrival") else: - raise HEREError( - "Please provide either origin & departure_time or destination & arrival_time." - ) + raise HEREError("Please provide either origin & departure_time or destination & arrival_time.") def multi_range_routing( self, transport_mode: IsolineRoutingTransportMode, - ranges: List[int], - origin: Optional[List[float]] = None, - destination: Optional[List[float]] = None, + ranges: list[int], + origin: list[float] | None = None, + destination: list[float] | None = None, ): - """Isoline routing can be requested with multiple ranges which allows for the calculation + """ + Isoline routing can be requested with multiple ranges which allows for the calculation of many isolines with the same start or destination. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -271,11 +284,13 @@ def multi_range_routing( List including latitude and longitude in order. destination (List): List including latitude and longitude in order. + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] if origin: data = { @@ -296,19 +311,19 @@ def multi_range_routing( } return self.__get(self._base_url, data, "arrival") else: - raise HEREError( - "Please provide values for origin or destination parameter." - ) + raise HEREError("Please provide values for origin or destination parameter.") def reverse_direction_isoline( self, transport_mode: IsolineRoutingTransportMode, - ranges: List[int], - origin: Optional[List[float]] = None, - destination: Optional[List[float]] = None, + ranges: list[int], + origin: list[float] | None = None, + destination: list[float] | None = None, ): - """Calculates an isoline in the reverse direction. To trigger calculation in reverse direction, + """ + Calculates an isoline in the reverse direction. To trigger calculation in reverse direction, use the destination parameter instead of origin. + Args: transport_mode (IsolineRoutingTransportMode): Transport mode of routing. @@ -318,11 +333,13 @@ def reverse_direction_isoline( List including latitude and longitude in order. destination (List): List including latitude and longitude in order. + Returns: IsolineRoutingResponse Raises: - HEREError""" + HEREError + """ string_ranges = [str(int) for int in ranges] if origin: data = { @@ -343,6 +360,4 @@ def reverse_direction_isoline( } return self.__get(self._base_url, data, "arrival") else: - raise HEREError( - "Please provide values for origin or destination parameter." - ) + raise HEREError("Please provide values for origin or destination parameter.") diff --git a/herepy/map_image_api.py b/src/herepy/map_image_api.py similarity index 88% rename from herepy/map_image_api.py rename to src/herepy/map_image_api.py index 4a291bc..4b5d855 100644 --- a/herepy/map_image_api.py +++ b/src/herepy/map_image_api.py @@ -1,30 +1,33 @@ #!/usr/bin/env python +"""Module for the HERE Map Image API.""" + import json import sys -from typing import List, Optional import requests -from herepy import MapImageFormatType, MapImageResourceType +from herepy import MapImageFormatType from herepy.error import HEREError, InvalidRequestError, UnauthorizedError from herepy.here_api import HEREApi from herepy.utils import Utils class MapImageApi(HEREApi): - """A python interface into the HERE Map Image API""" + """A python interface into the HERE Map Image API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a MapImageApi instance. + """ + Initialize a MapImageApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(MapImageApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://image.maps.ls.hereapi.com/mia/1.6/mapview" def __get_error_from_response(self, json_data): @@ -35,9 +38,7 @@ def __get_error_from_response(self, json_data): error_type = json_data.get("Type") error_message = json_data.get( "Message", - error_description - + ", error occurred on " - + sys._getframe(1).f_code.co_name, + error_description + ", error occurred on " + sys._getframe(1).f_code.co_name, ) if error_type == "Invalid Request": return InvalidRequestError(error_message) @@ -46,27 +47,29 @@ def __get_error_from_response(self, json_data): def get_mapimage( self, - top_left: List[float] = None, - bottom_right: List[float] = None, - coordinates: List[float] = None, - city_name: Optional[str] = None, - country_name: Optional[str] = None, - center: List[float] = None, + top_left: list[float] = None, + bottom_right: list[float] = None, + coordinates: list[float] = None, + city_name: str | None = None, + country_name: str | None = None, + center: list[float] = None, encoded_geo_coordinate: str = None, encoded_geo_center_coordinate: str = None, image_format: MapImageFormatType = MapImageFormatType.png, - image_height: Optional[int] = None, + image_height: int | None = None, show_position: bool = False, maxhits: int = 1, label_language: str = "eng", - second_label_language: Optional[str] = None, - house_number: Optional[str] = None, + second_label_language: str | None = None, + house_number: str | None = None, zoom: int = 8, - map_scheme: Optional[int] = None, - uncertainty: Optional[str] = None, - nodot: Optional[bool] = None, + map_scheme: int | None = None, + uncertainty: str | None = None, + nodot: bool | None = None, ): - """Retrieves the map image with given parameters. + """ + Retrieves the map image with given parameters. + Args: top_left (List[float]): List contains latitude and longitude in order for the bounding box parameter. @@ -128,12 +131,14 @@ def get_mapimage( which is 50000 meters. nodot (Optional[bool]): If provided map image will be without dots. + Returns: Map image as bytes. + Raises: HEREError - """ + """ data = { "z": zoom, "apiKey": self._api_key, @@ -182,6 +187,6 @@ def get_mapimage( if "error" in json_data: error = self.__get_error_from_response(json_data) raise error - except UnicodeDecodeError as err: + except UnicodeDecodeError: print("Map image downloaded") return response.content diff --git a/herepy/map_tile_api.py b/src/herepy/map_tile_api.py similarity index 86% rename from herepy/map_tile_api.py rename to src/herepy/map_tile_api.py index c117103..d9bc2c0 100644 --- a/herepy/map_tile_api.py +++ b/src/herepy/map_tile_api.py @@ -1,9 +1,10 @@ #!/usr/bin/env python +"""Module for the HERE Map Tile API.""" + import json import sys from random import randrange -from typing import Dict, Optional import requests @@ -16,18 +17,20 @@ class MapTileApi(HEREApi): - """A python interface into the HERE Map Tile API""" + """A python interface into the HERE Map Tile API.""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a MapTileApi instance. + """ + Initialize a MapTileApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(MapTileApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = None def __get_error_from_response(self, json_data): @@ -35,9 +38,7 @@ def __get_error_from_response(self, json_data): if json_data["error"] == "Unauthorized": return UnauthorizedError(json_data["error_description"]) error_type = json_data.get("Type") - error_message = json_data.get( - "Message", "Error occurred on " + sys._getframe(1).f_code.co_name - ) + error_message = json_data.get("Message", "Error occurred on " + sys._getframe(1).f_code.co_name) if error_type == "Invalid Request": return InvalidRequestError(error_message) else: @@ -54,9 +55,11 @@ def get_maptile( scheme: str = "normal.day", size: int = 256, tile_format: str = "png8", - query_parameters: Optional[Dict] = None, - ) -> Optional[bytes]: - """Returns optional bytes value of map tile with given parameters. + query_parameters: dict | None = None, + ) -> bytes | None: + """ + Returns optional bytes value of map tile with given parameters. + Args: latitude (float): Latitude value to be used to fetch map tile. @@ -89,18 +92,18 @@ def get_maptile( Please note that JPG is recommended for satellite and hybrid schemes only. query_parameters (Optional[Dict]): Optional Query Parameters. Refer to the API definition for values. + Returns: Map tile as bytes. + Raises: HEREError - """ + """ server = randrange(1, 4) - column, row = MercatorProjection.get_column_row( - latitude=latitude, longitude=longitude, zoom=zoom - ) + column, row = MercatorProjection.get_column_row(latitude=latitude, longitude=longitude, zoom=zoom) url = str.format( - "https://{}.{}.maps.ls.hereapi.com/maptile/2.1/{}/{}/{}/{}/{}/{}/{}/{}", + "https://{}.{}.maps.ls.hereapi.com/maptile/2.1/{}/{}/{}/{}/{}/{}/{}", server, api_type.__str__(), resource_type.__str__(), @@ -124,6 +127,6 @@ def get_maptile( if "error" in json_data: error = self.__get_error_from_response(json_data) raise error - except UnicodeDecodeError as err: + except UnicodeDecodeError: print("Map tile downloaded") return response.content diff --git a/herepy/mercator_projection.py b/src/herepy/mercator_projection.py similarity index 64% rename from herepy/mercator_projection.py rename to src/herepy/mercator_projection.py index a53c64f..3e20912 100644 --- a/herepy/mercator_projection.py +++ b/src/herepy/mercator_projection.py @@ -3,8 +3,9 @@ import math -class MercatorProjection(object): - """The Map and Vetor Tile API serves map tiles obtained by mapping points on the +class MercatorProjection: + """ + The Map and Vetor Tile API serves map tiles obtained by mapping points on the surface of a sphere (the globe) to points on a plane, using the normalized Mercator projection. This class helps to create column and row values to be used in requests. @@ -15,9 +16,5 @@ def get_column_row(latitude: float, longitude: float, zoom: int): lat_rad = latitude * math.pi / 180 n = math.pow(2, zoom) x_tile = n * ((longitude + 180) / 360) - y_tile = ( - n - * (1 - (math.log(math.tan(lat_rad) + 1 / math.cos(lat_rad)) / math.pi)) - / 2 - ) + y_tile = n * (1 - (math.log(math.tan(lat_rad) + 1 / math.cos(lat_rad)) / math.pi)) / 2 return int(x_tile), int(y_tile) diff --git a/herepy/models.py b/src/herepy/models.py similarity index 76% rename from herepy/models.py rename to src/herepy/models.py index a34c4e7..8de69fc 100644 --- a/herepy/models.py +++ b/src/herepy/models.py @@ -1,15 +1,17 @@ import json -class HEREModel(object): +class HEREModel: """Base class from which all here models will inherit.""" def __init__(self, **kwargs): self.param_defaults = {} def __str__(self): - """Returns a string representation of HEREModel. By default - this is the same as as_json_string().""" + """ + Returns a string representation of HEREModel. By default + this is the same as as_json_string(). + """ return self.as_json_string() def __eq__(self, other): @@ -19,17 +21,20 @@ def __ne__(self, other): return not self.__eq__(other) def as_json_string(self): - """Returns the HEREModel as a JSON string based on key/value - pairs returned from the as_dict() method.""" + """ + Returns the HEREModel as a JSON string based on key/value + pairs returned from the as_dict() method. + """ return json.dumps(self.as_dict(), sort_keys=True) def as_dict(self): - """Create a dictionary representation of the object. Please see inline - comments on construction when dictionaries contain HEREModels.""" + """ + Create a dictionary representation of the object. Please see inline + comments on construction when dictionaries contain HEREModels. + """ data = {} - for (key, value) in self.param_defaults.items(): - + for key, value in self.param_defaults.items(): # If the value is a list, we need to create a list to hold the # dicts created by an object supporting the as_dict() method, # i.e., if it inherits from HEREModel. If the item in the list @@ -60,14 +65,15 @@ def as_dict(self): @classmethod def new_from_jsondict(cls, data, **kwargs): - """Create a new instance based on a JSON dict. Any kwargs should be + """ + Create a new instance based on a JSON dict. Any kwargs should be supplied by the inherited, calling class. Args: data (dict): A JSON dict, as converted from the JSON in the here API. - """ + """ json_data = data.copy() if kwargs: for key, val in kwargs.items(): @@ -82,10 +88,10 @@ class GeocoderResponse(HEREModel): """A class representing the Geocoder Api response data.""" def __init__(self, **kwargs): - super(GeocoderResponse, self).__init__() + super().__init__() self.param_defaults = {"items": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -93,10 +99,10 @@ class GeocoderReverseResponse(HEREModel): """A class representing the Geocoder Reverse Api response data.""" def __init__(self, **kwargs): - super(GeocoderReverseResponse, self).__init__() + super().__init__() self.param_defaults = {"items": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -104,10 +110,10 @@ class RoutingResponse(HEREModel): """A class representing the Routing Api response data.""" def __init__(self, **kwargs): - super(RoutingResponse, self).__init__() + super().__init__() self.param_defaults = {"response": None, "route_short": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -115,10 +121,10 @@ class RoutingResponseV8(HEREModel): """A class representing the Routing Api v8 response data.""" def __init__(self, **kwargs): - super(RoutingResponseV8, self).__init__() + super().__init__() self.param_defaults = {"routes": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -126,14 +132,14 @@ class RoutingMatrixResponse(HEREModel): """A class representing the Routing Api matrix response data.""" def __init__(self, **kwargs): - super(RoutingMatrixResponse, self).__init__() + super().__init__() self.param_defaults = { "matrixId": None, "matrix": None, "regionDefinition": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -141,10 +147,10 @@ class GeocoderAutoCompleteResponse(HEREModel): """A class representing the Geocoder Autocomplete Api response data.""" def __init__(self, **kwargs): - super(GeocoderAutoCompleteResponse, self).__init__() + super().__init__() self.param_defaults = {"items": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -152,10 +158,10 @@ class RmeResponse(HEREModel): """A class representing the RME (Route Matcher) Api response data.""" def __init__(self, **kwargs): - super(RmeResponse, self).__init__() + super().__init__() self.param_defaults = {"RouteLinks": [], "TracePoints": [], "Warnings": []} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -163,10 +169,10 @@ class PlacesResponse(HEREModel): """A class representing the Places (Search) Api response data.""" def __init__(self, **kwargs): - super(PlacesResponse, self).__init__() + super().__init__() self.param_defaults = {"items": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -174,10 +180,10 @@ class PublicTransitResponse(HEREModel): """A class representing the Public Transit Api response data.""" def __init__(self, **kwargs): - super(PublicTransitResponse, self).__init__() + super().__init__() self.param_defaults = {"Res": None} - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -185,7 +191,7 @@ class TrafficIncidentResponse(HEREModel): """A class representing the Traffic Incidents response provided by Traffic Api.""" def __init__(self, **kwargs): - super(TrafficIncidentResponse, self).__init__() + super().__init__() self.param_defaults = { "TIMESTAMP": None, "VERSION": None, @@ -194,7 +200,7 @@ def __init__(self, **kwargs): "error": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -202,22 +208,23 @@ class DestinationWeatherResponse(HEREModel): """A class representing the Weather Forecasts for DestinationWeather Api.""" def __init__(self, param_defaults, **kwargs): - super(DestinationWeatherResponse, self).__init__() + super().__init__() self.param_defaults = param_defaults - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @classmethod def new_from_jsondict(cls, data, param_defaults, **kwargs): - """Create a new instance based on a JSON dict. Any kwargs should be + """ + Create a new instance based on a JSON dict. Any kwargs should be supplied by the inherited, calling class. Args: data (dict): A JSON dict, as converted from the JSON in the here API. - """ + """ json_data = data.copy() if kwargs: for key, val in kwargs.items(): @@ -232,14 +239,14 @@ class EVChargingStationsResponse(HEREModel): """A class representing the EV Charging Stations response data.""" def __init__(self, **kwargs): - super(EVChargingStationsResponse, self).__init__() + super().__init__() self.param_defaults = { "hasMore": False, "count": 0, "evStations": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -247,14 +254,14 @@ class WaypointSequenceResponse(HEREModel): """A class representing the Fleet Telematics Waypoint Sequence response data.""" def __init__(self, **kwargs): - super(WaypointSequenceResponse, self).__init__() + super().__init__() self.param_defaults = { "results": None, "errors": None, "warnings": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -262,13 +269,13 @@ class TrafficFlowResponse(HEREModel): """A class representing the Traffic API Flow response data.""" def __init__(self, **kwargs): - super(TrafficFlowResponse, self).__init__() + super().__init__() self.param_defaults = { "RWS": [], "error": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -276,13 +283,13 @@ class TrafficFlowAvailabilityResponse(HEREModel): """A class representing the Traffic API Flow availability response data.""" def __init__(self, **kwargs): - super(TrafficFlowAvailabilityResponse, self).__init__() + super().__init__() self.param_defaults = { "Response": [], "error": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) @@ -290,7 +297,7 @@ class IsolineRoutingResponse(HEREModel): """A class representing the Isoline Routing API Flow response data.""" def __init__(self, **kwargs): - super(IsolineRoutingResponse, self).__init__() + super().__init__() self.param_defaults = { "departure": None, "arrival": None, @@ -298,5 +305,5 @@ def __init__(self, **kwargs): "error": None, } - for (param, default) in self.param_defaults.items(): + for param, default in self.param_defaults.items(): setattr(self, param, kwargs.get(param, default)) diff --git a/herepy/objects.py b/src/herepy/objects.py similarity index 84% rename from herepy/objects.py rename to src/herepy/objects.py index be8febf..163e2dd 100644 --- a/herepy/objects.py +++ b/src/herepy/objects.py @@ -1,10 +1,12 @@ -from typing import List +from herepy.here_enum import ( + AvoidFeature, + ShippedHazardousGood, + TruckType, + TunnelCategory, +) -from herepy.here_enum import (AvoidFeature, ShippedHazardousGood, TruckType, - TunnelCategory) - -class AvoidArea(object): +class AvoidArea: """List of areas to avoid.""" def __init__( @@ -15,7 +17,9 @@ def __init__( east: int, avoid_type: str = "boundingBox", ): - """Returns a AvoidArea instance. + """ + Returns a AvoidArea instance. + Args: north (int): Latitude in WGS-84 degrees of the northern boundary of the box. @@ -27,8 +31,8 @@ def __init__( Longitude in WGS-84 degrees of the eastern boundary of the box. avoid_type (str): Type of avoid, default `boundingBox`. - """ + """ self.north = north self.south = south self.west = west @@ -36,18 +40,20 @@ def __init__( self.avoid_type = avoid_type -class Avoid(object): +class Avoid: """Class that helps RoutingAPI to avoid routes that violate the properties it has.""" - def __init__(self, features: List[AvoidFeature], areas: List[AvoidArea]): - """Returns a Avoid instance. + def __init__(self, features: list[AvoidFeature], areas: list[AvoidArea]): + """ + Returns a Avoid instance. + Args: features (List[AvoidFeature]): List of routing features to avoid during route calculation. areas (List[AvoidArea]): List of areas to avoid. - """ + """ self.features = [avoid_feature.__str__() for avoid_feature in features] self.areas = [ { @@ -61,12 +67,12 @@ def __init__(self, features: List[AvoidFeature], areas: List[AvoidArea]): ] -class Truck(object): +class Truck: """Different truck options to use during route calculation when transportMode = truck""" def __init__( self, - shipped_hazardous_goods: List[ShippedHazardousGood], + shipped_hazardous_goods: list[ShippedHazardousGood], gross_weight: int, weight_per_axle: int, height: int, @@ -77,7 +83,9 @@ def __init__( truck_type: TruckType, trailer_count: int, ): - """Returns a Truck instance. + """ + Returns a Truck instance. + Args: shipped_hazardous_goods (List[ShippedHazardousGood]): List of hazardous materials in the vehicle. @@ -99,11 +107,9 @@ def __init__( Specifies the type of truck. trailer_count (int): Number of trailers attached to the vehicle. - """ - self.shipped_hazardous_goods = [ - hazardous_goods.__str__() for hazardous_goods in shipped_hazardous_goods - ] + """ + self.shipped_hazardous_goods = [hazardous_goods.__str__() for hazardous_goods in shipped_hazardous_goods] self.gross_weight = gross_weight self.weight_per_axle = weight_per_axle self.height = height diff --git a/herepy/places_api.py b/src/herepy/places_api.py similarity index 75% rename from herepy/places_api.py rename to src/herepy/places_api.py index c7770d6..8c4ecc5 100644 --- a/herepy/places_api.py +++ b/src/herepy/places_api.py @@ -2,13 +2,11 @@ import json import sys -from typing import List, Optional import requests from herepy.error import HEREError, UnauthorizedError from herepy.here_api import HEREApi -from herepy.here_enum import PlacesCategory from herepy.models import PlacesResponse from herepy.utils import Utils @@ -17,37 +15,35 @@ class PlacesApi(HEREApi): """A python interface into the HERE Places (Search) API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a PlacesApi instance. + """ + Returns a PlacesApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(PlacesApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://discover.search.hereapi.com/v1/discover" def __get(self, data): url = Utils.build_url(self._base_url, extra_params=data) response = requests.get(url, timeout=self._timeout) json_data = json.loads(response.content.decode("utf8")) - if json_data.get("items") != None: + if json_data.get("items") is not None: return PlacesResponse.new_from_jsondict(json_data) elif "error" in json_data: if json_data["error"] == "Unauthorized": raise UnauthorizedError(json_data["error_description"]) else: - raise HEREError( - json_data.get( - "message", "Error occurred on " + sys._getframe(1).f_code.co_name - ) - ) - - def onebox_search( - self, coordinates: List[float], query: str, limit: int = 20, lang: str = "en-US" - ) -> Optional[PlacesResponse]: - """Request a list of places based on a query string. + raise HEREError(json_data.get("message", "Error occurred on " + sys._getframe(1).f_code.co_name)) + + def onebox_search(self, coordinates: list[float], query: str, limit: int = 20, lang: str = "en-US") -> PlacesResponse | None: + """ + Request a list of places based on a query string. + Args: coordinates (List): List contains latitude and longitude in order. @@ -57,11 +53,13 @@ def onebox_search( Limits items to return, with default value 10. Max value 100. lang (str): BCP47 compliant Language Code. + Returns: PlacesResponse Raises: - HEREError""" + HEREError + """ data = { "at": str.format("{0},{1}", coordinates[0], coordinates[1]), "q": query, @@ -73,13 +71,15 @@ def onebox_search( def search_in_country( self, - coordinates: List[float], + coordinates: list[float], query: str, country_code: str, limit: int = 20, lang: str = "en-US", - ) -> Optional[PlacesResponse]: - """Request a list of places based on a query string. + ) -> PlacesResponse | None: + """ + Request a list of places based on a query string. + Args: coordinates (List): List contains latitude and longitude in order. @@ -94,8 +94,9 @@ def search_in_country( Returns: PlacesResponse Raises: - HEREError""" + HEREError + """ data = { "at": str.format("{0},{1}", coordinates[0], coordinates[1]), "q": query, @@ -108,13 +109,14 @@ def search_in_country( def places_in_circle( self, - coordinates: List[float], + coordinates: list[float], radius: int, query: str, limit: int = 20, lang: str = "en-US", - ) -> Optional[PlacesResponse]: - """Request a list of popular places around a location + ) -> PlacesResponse | None: + """ + Request a list of popular places around a location Args: coordinates (List): List contains latitude and longitude in order. @@ -127,12 +129,10 @@ def places_in_circle( Returns: PlacesResponse Raises: - HEREError""" - + HEREError + """ data = { - "in": str.format( - "circle:{0},{1};r={2}", coordinates[0], coordinates[1], radius - ), + "in": str.format("circle:{0},{1};r={2}", coordinates[0], coordinates[1], radius), "q": query, "limit": limit, "lang": lang, diff --git a/herepy/platform/__init__.py b/src/herepy/platform/__init__.py similarity index 100% rename from herepy/platform/__init__.py rename to src/herepy/platform/__init__.py diff --git a/herepy/platform/tour_planning_api.py b/src/herepy/platform/tour_planning_api.py similarity index 79% rename from herepy/platform/tour_planning_api.py rename to src/herepy/platform/tour_planning_api.py index 6d282a7..f5ffb25 100644 --- a/herepy/platform/tour_planning_api.py +++ b/src/herepy/platform/tour_planning_api.py @@ -5,13 +5,15 @@ class TourPlanningApi(HEREApi): """A python interface into the HERE Tour Planning API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a TourPlanningApi instance. + """ + Returns a TourPlanningApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(TourPlanningApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://tourplanning.hereapi.com/v3/" diff --git a/herepy/polling.py b/src/herepy/polling.py similarity index 90% rename from herepy/polling.py rename to src/herepy/polling.py index d851fd7..e4d7866 100644 --- a/herepy/polling.py +++ b/src/herepy/polling.py @@ -26,14 +26,18 @@ class MaxCallException(PollingException): def step_constant(step): - """Use this function when you want the step to remain fixed in every iteration (typically good for - instances when you know approximately how long the function should poll for)""" + """ + Use this function when you want the step to remain fixed in every iteration (typically good for + instances when you know approximately how long the function should poll for) + """ return step def step_linear_double(step): - """Use this function when you want the step to double each iteration (e.g. like the way ArrayList works in - Java). Note that this can result in very long poll times after a few iterations""" + """ + Use this function when you want the step to double each iteration (e.g. like the way ArrayList works in + Java). Note that this can result in very long poll times after a few iterations + """ return step * 2 @@ -55,9 +59,10 @@ def poll( poll_forever=False, collect_values=None, *a, - **k + **k, ): - """Poll by calling a target function until a certain condition is met. You must specify at least a target + """ + Poll by calling a target function until a certain condition is met. You must specify at least a target function to be called and the step -- base wait time between each function call. :param step: Step defines the amount of time to wait (in seconds) :param args: Arguments to be passed to the target function @@ -93,15 +98,14 @@ def poll( :return: Polling will return first value from the target function that meets the condions of the check_success callback. By default, this will be the first value that is not None, 0, False, '', or an empty collection. """ - assert (timeout is not None or max_tries is not None) or poll_forever, ( "You did not specify a maximum number of tries or a timeout. Without either of these set, the polling " 'function will poll forever. If this is the behavior you want, pass "poll_forever=True"' ) - assert not ( - (timeout is not None or max_tries is not None) and poll_forever - ), "You cannot specify both the option to poll_forever and max_tries/timeout." + assert not ((timeout is not None or max_tries is not None) and poll_forever), ( + "You cannot specify both the option to poll_forever and max_tries/timeout." + ) kwargs = kwargs or dict() values = collect_values or Queue() diff --git a/herepy/public_transit_api.py b/src/herepy/public_transit_api.py similarity index 84% rename from herepy/public_transit_api.py rename to src/herepy/public_transit_api.py index 56416fe..0077e5d 100644 --- a/herepy/public_transit_api.py +++ b/src/herepy/public_transit_api.py @@ -2,14 +2,16 @@ import json import sys -from typing import List, Optional import requests from herepy.error import HEREError, UnauthorizedError from herepy.here_api import HEREApi -from herepy.here_enum import (PublicTransitModeType, PublicTransitRoutingMode, - PublicTransitSearchMethod) +from herepy.here_enum import ( + PublicTransitModeType, + PublicTransitRoutingMode, + PublicTransitSearchMethod, +) from herepy.models import PublicTransitResponse from herepy.utils import Utils @@ -18,15 +20,17 @@ class PublicTransitApi(HEREApi): """A python interface into the HERE Public Transit API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a PublicTransitApi instance. + """ + Returns a PublicTransitApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(PublicTransitApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://transit.ls.hereapi.com/v3/" def __get(self, data, path, json_node): @@ -48,13 +52,15 @@ def __get(self, data, path, json_node): def find_stations_by_name( self, - center: List[float], + center: list[float], name: str, max_count: int = 5, method: PublicTransitSearchMethod = PublicTransitSearchMethod.fuzzy, radius: int = 20000, - ) -> Optional[PublicTransitResponse]: - """Request a list of public transit stations based on name. + ) -> PublicTransitResponse | None: + """ + Request a list of public transit stations based on name. + Args: center (List): List contains latitude and longitude in order. @@ -66,12 +72,13 @@ def find_stations_by_name( Matching method from PublicTransitSearchMethod (Default is fuzzy). radius (int): specifies radius in kilometers (Default is 20000km). + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "center": str.format("{0},{1}", center[0], center[1]), "name": name, @@ -82,10 +89,10 @@ def find_stations_by_name( } return self.__get(data, "stations/by_name.json", "Stations") - def find_stations_nearby( - self, center: List[float], radius: int = 500, max_count: int = 5 - ) -> Optional[PublicTransitResponse]: - """Request a list of public transit stations within a given geo-location. + def find_stations_nearby(self, center: list[float], radius: int = 500, max_count: int = 5) -> PublicTransitResponse | None: + """ + Request a list of public transit stations within a given geo-location. + Args: center (List): List contains latitude and longitude in order. @@ -93,12 +100,13 @@ def find_stations_nearby( specifies radius in meters (Default is 500m). max_count (int): maximum number of stations (Default is 5). + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "center": str.format("{0},{1}", center[0], center[1]), "radius": radius, @@ -115,21 +123,22 @@ def __prepare_station_ids(cls, ids): station_ids = station_ids[:-1] return station_ids - def find_stations_by_id( - self, ids: List[int], lang: str - ) -> Optional[PublicTransitResponse]: - """Request details of a specific transit station based on a previous request. + def find_stations_by_id(self, ids: list[int], lang: str) -> PublicTransitResponse | None: + """ + Request details of a specific transit station based on a previous request. + Args: ids (List): List contains station ids. lang (str): language code for response like `en`. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "stnIds": self.__prepare_station_ids(ids), "lang": lang, @@ -137,10 +146,10 @@ def find_stations_by_id( } return self.__get(data, "stations/by_ids.json", "Stations") - def find_transit_coverage_in_cities( - self, center: List[float], political_view: str, radius: int - ) -> Optional[PublicTransitResponse]: - """Request a list of transit operators available in cities nearby. + def find_transit_coverage_in_cities(self, center: list[float], political_view: str, radius: int) -> PublicTransitResponse | None: + """ + Request a list of transit operators available in cities nearby. + Args: center (List): List contains latitude and longitude in order. @@ -148,12 +157,13 @@ def find_transit_coverage_in_cities( switch for grouping results like `CHN`. radius (int): specifies radius in meters. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "center": str.format("{0},{1}", center[0], center[1]), "politicalview": political_view, @@ -162,10 +172,10 @@ def find_transit_coverage_in_cities( } return self.__get(data, "coverage/city.json", "Coverage") - def next_nearby_departures_of_station( - self, station_id: int, time: str, lang: str = "en" - ) -> Optional[PublicTransitResponse]: - """Request a list of next departure times and destinations of a particular station. + def next_nearby_departures_of_station(self, station_id: int, time: str, lang: str = "en") -> PublicTransitResponse | None: + """ + Request a list of next departure times and destinations of a particular station. + Args: lang (str): language code for response like `en` Default is `en`. @@ -173,12 +183,13 @@ def next_nearby_departures_of_station( station id for departures. time (str): time formattes in yyyy-mm-ddThh:mm:ss. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "lang": lang, "stnId": station_id, @@ -189,13 +200,15 @@ def next_nearby_departures_of_station( def next_departures_from_location( self, - center: List[float], + center: list[float], time: str, lang: str = "en", max: int = 40, max_station: int = 40, - ) -> Optional[PublicTransitResponse]: - """Request a list of all next departure times and destinations from a given location. + ) -> PublicTransitResponse | None: + """ + Request a list of all next departure times and destinations from a given location. + Args: center (List): List contains latitude and longitude in order. @@ -207,12 +220,13 @@ def next_departures_from_location( maximum number of next departures per station. Default is 40. max_station (int): maximum number of stations for which departures are required. Default is 40. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "lang": lang, "center": str.format("{0},{1}", center[0], center[1]), @@ -225,13 +239,15 @@ def next_departures_from_location( def next_departures_for_stations( self, - station_ids: List[int], + station_ids: list[int], time: str, lang: str = "en", max: int = 40, max_station: int = 40, - ) -> Optional[PublicTransitResponse]: - """Request a list of all next departure times and destinations for a give list of stations. + ) -> PublicTransitResponse | None: + """ + Request a list of all next departure times and destinations for a give list of stations. + Args: station_ids (List): a list of stop ids. @@ -243,12 +259,13 @@ def next_departures_for_stations( maximum number of next departures per station. Default is 40. max_station (int): maximum number of stations for which departures are required. Default is 40. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "lang": lang, "time": time, @@ -261,22 +278,24 @@ def next_departures_for_stations( def calculate_route( self, - departure: List[float], - arrival: List[float], + departure: list[float], + arrival: list[float], time: str, max_connections: int = 3, changes: int = -1, lang: str = "en", - include_modes: List[PublicTransitModeType] = None, - exclude_modes: List[PublicTransitModeType] = None, + include_modes: list[PublicTransitModeType] = None, + exclude_modes: list[PublicTransitModeType] = None, units: str = "metric", max_walking_distance: int = 2000, walking_speed: int = 100, show_arrival_times: bool = True, graph: bool = False, routing_mode: PublicTransitRoutingMode = PublicTransitRoutingMode.schedule, - ) -> Optional[PublicTransitResponse]: - """Request a public transit route between any two places. + ) -> PublicTransitResponse | None: + """ + Request a public transit route between any two places. + Args: departure (List): List contains latitude and longitude in order. @@ -309,12 +328,13 @@ def calculate_route( flag to indicate if response should contain coordinate pairs to allow the drawing of a polyline for the route. routing_type (PublicTransitRoutingType): type of routing. Default is time_tabled. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "dep": str.format("{0},{1}", departure[0], departure[1]), "arr": str.format("{0},{1}", arrival[0], arrival[1]), @@ -324,9 +344,9 @@ def calculate_route( "lang": lang, "units": units, "walk": ",".join([str(max_walking_distance), str(walking_speed)]), - "arrival": 1 if show_arrival_times == True else 0, + "arrival": 1 if show_arrival_times else 0, "apikey": self._api_key, - "graph": 1 if graph == True else 0, + "graph": 1 if graph else 0, "routingMode": routing_mode.__str__(), } @@ -351,8 +371,10 @@ def coverage_witin_a_city( max: int = None, details: int = 1, lang: str = "en", - ) -> Optional[PublicTransitResponse]: - """Request a list of transit operator coverage within a specified city. + ) -> PublicTransitResponse | None: + """ + Request a list of transit operator coverage within a specified city. + Args: city_name (str): the name or part of the name of the search city. @@ -365,12 +387,13 @@ def coverage_witin_a_city( Set to 0 just return the matching city names. lang (str): the language of the response, default `en`. + Returns: PublicTransitResponse Raises: HEREError - """ + """ data = { "name": city_name, "apikey": self._api_key, @@ -383,19 +406,21 @@ def coverage_witin_a_city( del data["max"] return self.__get(data, "coverage/search.json", "Coverage") - def coverage_nearby( - self, details: int, center: List[float] - ) -> Optional[PublicTransitResponse]: - """Request a list of transit operators and station coverage nearby. + def coverage_nearby(self, details: int, center: list[float]) -> PublicTransitResponse | None: + """ + Request a list of transit operators and station coverage nearby. + Args: details (int): 0 disables showing line info, 1 enables showing line info.abs center (List): List contains latitude and longitude in order. + Returns: PublicTransitResponse Raises: HEREError + """ data = { "details": details, @@ -409,9 +434,7 @@ def _get_response_with_short_route(self, public_transit_response): connections = response.Res["Connections"]["Connection"] for connection in connections: - connection["short_route"] = self._get_route_from_public_transit_connection( - connection - ) + connection["short_route"] = self._get_route_from_public_transit_connection(connection) return response def _get_route_from_public_transit_connection(self, public_transit_connection): diff --git a/herepy/py.typed b/src/herepy/py.typed similarity index 100% rename from herepy/py.typed rename to src/herepy/py.typed diff --git a/herepy/rme_api.py b/src/herepy/rme_api.py similarity index 76% rename from herepy/rme_api.py rename to src/herepy/rme_api.py index 7d10087..f232c10 100644 --- a/herepy/rme_api.py +++ b/src/herepy/rme_api.py @@ -2,7 +2,6 @@ import json import sys -from typing import List, Optional import requests @@ -16,15 +15,17 @@ class RmeApi(HEREApi): """A python interface into the RME API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a RmeApi instance. + """ + Returns a RmeApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(RmeApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://m.fleet.ls.hereapi.com/2/matchroute.json" def __get(self, data): @@ -32,7 +33,7 @@ def __get(self, data): response = requests.get(url, timeout=self._timeout) try: json_data = json.loads(response.content.decode("utf8")) - if json_data.get("TracePoints") != None: + if json_data.get("TracePoints") is not None: return RmeResponse.new_from_jsondict(json_data) else: raise HEREError( @@ -42,17 +43,11 @@ def __get(self, data): ) ) except ValueError as err: - raise HEREError( - "Error occurred on function " - + sys._getframe(1).f_code.co_name - + " " - + str(err) - ) + raise HEREError("Error occurred on function " + sys._getframe(1).f_code.co_name + " " + str(err)) - def match_route( - self, gpx_file_content: str, route_mode: str = "car", pde_layers: List[str] = [] - ) -> Optional[RmeResponse]: - """Retrieves misc information about the route given in gpx file + def match_route(self, gpx_file_content: str, route_mode: str = "car", pde_layers: list[str] = []) -> RmeResponse | None: + """ + Retrieves misc information about the route given in gpx file Args: gpxfile content (str): gpx file content as string @@ -68,11 +63,13 @@ def match_route( ROAD_GEOM_FCn(*) SPEED_LIMITS_FCn(*) + Returns: RmeResponse Raises: - HEREError""" + HEREError + """ data = { "file": Utils.get_zipped_base64(gpx_file_content), "routemode": route_mode, diff --git a/herepy/routing_api.py b/src/herepy/routing_api.py similarity index 78% rename from herepy/routing_api.py rename to src/herepy/routing_api.py index 2f75615..bde8f4d 100644 --- a/herepy/routing_api.py +++ b/src/herepy/routing_api.py @@ -4,7 +4,6 @@ import json import os import sys -from typing import Dict, List, Optional, Union from warnings import warn import requests @@ -13,13 +12,20 @@ from herepy.error import AccessDeniedError, HEREError, InvalidRequestError from herepy.geocoder_api import GeocoderApi from herepy.here_api import HEREApi -from herepy.here_enum import (MatrixRoutingMode, MatrixRoutingProfile, - MatrixRoutingTransportMode, MatrixRoutingType, - MatrixSummaryAttribute, RouteMode, - RoutingApiReturnField, RoutingApiSpanField, - RoutingMetric, RoutingMode, RoutingTransportMode) -from herepy.models import (RoutingMatrixResponse, RoutingResponse, - RoutingResponseV8) +from herepy.here_enum import ( + MatrixRoutingMode, + MatrixRoutingProfile, + MatrixRoutingTransportMode, + MatrixRoutingType, + MatrixSummaryAttribute, + RouteMode, + RoutingApiReturnField, + RoutingApiSpanField, + RoutingMetric, + RoutingMode, + RoutingTransportMode, +) +from herepy.models import RoutingMatrixResponse, RoutingResponse, RoutingResponseV8 from herepy.objects import Avoid, Truck from herepy.utils import Utils @@ -32,15 +38,17 @@ class RoutingApi(HEREApi): URL_CALCULATE_MATRIX = "https://matrix.router.hereapi.com/v8/matrix" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a RoutingApi instance. + """ + Returns a RoutingApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(RoutingApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) def __get( self, @@ -49,8 +57,8 @@ def __get( key, response_cls, manipulation_key: str = None, - keys_for_manipulation: List = None, - headers: Optional[Dict[str, str]] = None, + keys_for_manipulation: list = None, + headers: dict[str, str] | None = None, ): url = Utils.build_url(base_url, extra_params=data) if manipulation_key and keys_for_manipulation: @@ -94,24 +102,17 @@ def _route(self, waypoint_a, waypoint_b, modes=None, departure=None, arrival=Non if arrival is not None: arrival = self._convert_datetime_to_isoformat(arrival) data["arrival"] = arrival - response = self.__get( - self.URL_CALCULATE_ROUTE, data, "response", RoutingResponse - ) + response = self.__get(self.URL_CALCULATE_ROUTE, data, "response", RoutingResponse) route = response.response["route"] maneuver = route[0]["leg"][0]["maneuver"] if any(mode in modes for mode in [RouteMode.car, RouteMode.truck]): # Get Route for Car and Truck response.route_short = self._get_route_from_vehicle_maneuver(maneuver) - elif any( - mode in modes - for mode in [RouteMode.publicTransport, RouteMode.publicTransportTimeTable] - ): + elif any(mode in modes for mode in [RouteMode.publicTransport, RouteMode.publicTransportTimeTable]): # Get Route for Public Transport public_transport_line = route[0]["publicTransportLine"] - response.route_short = self._get_route_from_public_transport_line( - public_transport_line - ) + response.route_short = self._get_route_from_public_transport_line(public_transport_line) elif any(mode in modes for mode in [RouteMode.pedestrian, RouteMode.bicycle]): # Get Route for Pedestrian and Biyclce response.route_short = self._get_route_from_non_vehicle_maneuver(maneuver) @@ -119,12 +120,13 @@ def _route(self, waypoint_a, waypoint_b, modes=None, departure=None, arrival=Non def bicycle_route( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Request a bicycle route between two points + ) -> RoutingResponse | None: + """ + Request a bicycle route between two points Args: waypoint_a: List contains latitude and longitude in order @@ -136,23 +138,26 @@ def bicycle_route( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.bicycle, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def car_route( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Request a driving route between two points + ) -> RoutingResponse | None: + """ + Request a driving route between two points Args: waypoint_a (List): List contains latitude and longitude in order @@ -164,23 +169,26 @@ def car_route( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.car, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def pedestrian_route( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Request a pedestrian route between two points + ) -> RoutingResponse | None: + """ + Request a pedestrian route between two points Args: waypoint_a (List): List contains latitude and longitude in order @@ -192,24 +200,27 @@ def pedestrian_route( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.pedestrian, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def intermediate_route( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - waypoint_c: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + waypoint_c: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Request a intermediate route from three points + ) -> RoutingResponse | None: + """ + Request a intermediate route from three points Args: waypoint_a (List): Starting List contains latitude and longitude in order @@ -224,24 +235,27 @@ def intermediate_route( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.car, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def public_transport( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, combine_change: bool, - modes: List[RouteMode] = None, + modes: list[RouteMode] = None, departure="now", - ) -> Optional[RoutingResponse]: - """Request a public transport route between two points + ) -> RoutingResponse | None: + """ + Request a public transport route between two points Args: waypoint_a (List): Starting List contains latitude and longitude in order @@ -256,25 +270,28 @@ def public_transport( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.publicTransport, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def public_transport_timetable( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, combine_change: bool, - modes: List[RouteMode] = None, + modes: list[RouteMode] = None, departure: str = None, arrival: str = None, - ) -> Optional[RoutingResponse]: - """Request a public transport route between two points based on timetables + ) -> RoutingResponse | None: + """ + Request a public transport route between two points based on timetables Args: waypoint_a (List): Starting List contains latitude and longitude in order @@ -291,23 +308,26 @@ def public_transport_timetable( Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `None`. arrival (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `None`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.publicTransportTimeTable, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure, arrival) def location_near_motorway( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Calculates the fastest car route between two location + ) -> RoutingResponse | None: + """ + Calculates the fastest car route between two location Args: waypoint_a (List): List contains latitude and longitude in order @@ -319,23 +339,26 @@ def location_near_motorway( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.car, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) def truck_route( self, - waypoint_a: Union[List[float], str], - waypoint_b: Union[List[float], str], - modes: List[RouteMode] = None, + waypoint_a: list[float] | str, + waypoint_b: list[float] | str, + modes: list[RouteMode] = None, departure: str = "now", - ) -> Optional[RoutingResponse]: - """Calculates the fastest truck route between two location + ) -> RoutingResponse | None: + """ + Calculates the fastest truck route between two location Args: waypoint_a (List): List contains latitude and longitude in order @@ -347,11 +370,13 @@ def truck_route( List contains RouteMode enums. departure (str): Date time str in format `yyyy-mm-ddThh:mm:ss`. Default `now`. + Returns: RoutingResponse Raises: - HEREError""" + HEREError + """ if modes is None: modes = [RouteMode.truck, RouteMode.fastest] return self._route(waypoint_a, waypoint_b, modes, departure) @@ -359,24 +384,26 @@ def truck_route( def route_v8( self, transport_mode: RoutingTransportMode, - origin: Union[List[float], str], - destination: Union[List[float], str], - via: Optional[List[List[float]]] = None, - departure_time: Optional[str] = None, + origin: list[float] | str, + destination: list[float] | str, + via: list[list[float]] | None = None, + departure_time: str | None = None, routing_mode: RoutingMode = RoutingMode.fast, - alternatives: Optional[int] = None, - avoid: Optional[Dict[str, List[str]]] = None, - exclude: Optional[Dict[str, List[str]]] = None, - units: Optional[RoutingMetric] = None, - lang: Optional[str] = None, - return_fields: List[RoutingApiReturnField] = [RoutingApiReturnField.polyline], - span_fields: Optional[List[RoutingApiSpanField]] = None, - truck: Optional[Dict[str, List[str]]] = None, - vehicle: Optional[Dict[str, List[str]]] = None, - scooter: Optional[Dict[str, str]] = None, - headers: Optional[dict] = None, - ) -> Optional[RoutingResponseV8]: - """Calculates the route between given origin and destination. + alternatives: int | None = None, + avoid: dict[str, list[str]] | None = None, + exclude: dict[str, list[str]] | None = None, + units: RoutingMetric | None = None, + lang: str | None = None, + return_fields: list[RoutingApiReturnField] = [RoutingApiReturnField.polyline], + span_fields: list[RoutingApiSpanField] | None = None, + truck: dict[str, list[str]] | None = None, + vehicle: dict[str, list[str]] | None = None, + scooter: dict[str, str] | None = None, + headers: dict | None = None, + ) -> RoutingResponseV8 | None: + """ + Calculates the route between given origin and destination. + Args: transport_mode (RoutingTransportMode): Mode of transport to be used for the calculation of the route. @@ -433,12 +460,13 @@ def route_v8( X-Request-ID User-provided token that can be used to trace a request or a group of requests sent to the service. + Returns: RoutingResponseV8 Raises: HEREError - """ + """ if isinstance(origin, str): origin = self._get_coordinates_for_location_name(origin) if isinstance(destination, str): @@ -493,25 +521,25 @@ def route_v8( RoutingResponseV8, manipulation_key="via", keys_for_manipulation=via_keys, - headers=headers + headers=headers, ) return response def __prepare_matrix_request_body( self, - origins: Union[List[float], str], - destinations: Union[List[float], str], + origins: list[float] | str, + destinations: list[float] | str, matrix_type: MatrixRoutingType = MatrixRoutingType.world, - center: Optional[List[float]] = None, - radius: Optional[int] = None, - profile: Optional[MatrixRoutingProfile] = None, + center: list[float] | None = None, + radius: int | None = None, + profile: MatrixRoutingProfile | None = None, departure: str = None, - routing_mode: Optional[MatrixRoutingMode] = None, - transport_mode: Optional[MatrixRoutingTransportMode] = None, - avoid: Optional[Avoid] = None, - truck: Optional[Truck] = None, - matrix_attributes: Optional[List[MatrixSummaryAttribute]] = None, - ) -> Dict: + routing_mode: MatrixRoutingMode | None = None, + transport_mode: MatrixRoutingTransportMode | None = None, + avoid: Avoid | None = None, + truck: Truck | None = None, + matrix_attributes: list[MatrixSummaryAttribute] | None = None, + ) -> dict: region_definition = { "type": matrix_type.__str__(), } @@ -530,9 +558,7 @@ def __prepare_matrix_request_body( if transport_mode: request_body["transportMode"] = transport_mode.__str__() if matrix_attributes: - request_body["matrixAttributes"] = [ - attribute.__str__() for attribute in matrix_attributes - ] + request_body["matrixAttributes"] = [attribute.__str__() for attribute in matrix_attributes] if avoid: request_body["avoid"] = {"features": avoid.features, "areas": avoid.areas} if truck: @@ -562,9 +588,7 @@ def __prepare_matrix_request_body( destination_list = [] for i, destination in enumerate(destinations): if isinstance(destination, str): - destination_waypoint = self._get_coordinates_for_location_name( - destination - ) + destination_waypoint = self._get_coordinates_for_location_name(destination) else: destination_waypoint = destination lat_long = {"lat": destination_waypoint[0], "lng": destination_waypoint[1]} @@ -575,20 +599,22 @@ def __prepare_matrix_request_body( def sync_matrix( self, - origins: Union[List[float], str], - destinations: Union[List[float], str], + origins: list[float] | str, + destinations: list[float] | str, matrix_type: MatrixRoutingType = MatrixRoutingType.world, - center: Optional[List[float]] = None, - radius: Optional[int] = None, - profile: Optional[MatrixRoutingProfile] = None, + center: list[float] | None = None, + radius: int | None = None, + profile: MatrixRoutingProfile | None = None, departure: str = None, - routing_mode: Optional[MatrixRoutingMode] = None, - transport_mode: Optional[MatrixRoutingTransportMode] = None, - avoid: Optional[Avoid] = None, - truck: Optional[Truck] = None, - matrix_attributes: Optional[List[MatrixSummaryAttribute]] = None, - ) -> Optional[RoutingMatrixResponse]: - """Sync request a matrix of route summaries between M starts and N destinations. + routing_mode: MatrixRoutingMode | None = None, + transport_mode: MatrixRoutingTransportMode | None = None, + avoid: Avoid | None = None, + truck: Truck | None = None, + matrix_attributes: list[MatrixSummaryAttribute] | None = None, + ) -> RoutingMatrixResponse | None: + """ + Sync request a matrix of route summaries between M starts and N destinations. + Args: origins (List): List of lists of coordinates [lat,long] of start waypoints. @@ -617,12 +643,13 @@ def sync_matrix( Different truck options to use during route calculation when transportMode = truck. matrix_attributes (List): List of MatrixSummaryAttribute enums. + Returns: RoutingMatrixResponse Raises: HEREError: If an error is received from the server. - """ + """ query_params = { "apiKey": self._api_key, "async": "false", @@ -645,9 +672,7 @@ def sync_matrix( url = Utils.build_url(self.URL_CALCULATE_MATRIX, extra_params=query_params) headers = {"Content-Type": "application/json"} - response = requests.post( - url, json=request_body, headers=headers, timeout=self._timeout - ) + response = requests.post(url, json=request_body, headers=headers, timeout=self._timeout) json_data = json.loads(response.content.decode("utf8")) if response.status_code == requests.codes.OK: if json_data.get("matrix") is not None: @@ -669,10 +694,7 @@ def sync_matrix( ) ) else: - raise HEREError( - "Error occurred on routing_api sync_matrix " - + sys._getframe(1).f_code.co_name - ) + raise HEREError("Error occurred on routing_api sync_matrix " + sys._getframe(1).f_code.co_name) def __download_file(self, fileurl: str): filename = os.path.basename(fileurl) @@ -681,7 +703,7 @@ def __download_file(self, fileurl: str): with open(filename, "wb") as f: for chunk in r.iter_content(chunk_size=8192): f.write(chunk) - print("{} file saved!".format(filename)) + print(f"{filename} file saved!") return filename def __is_correct_response(self, response): @@ -690,44 +712,34 @@ def __is_correct_response(self, response): if json_data.get("matrix") is not None: return json_data elif json_data.get("status") is not None: - print( - "Matrix {} calculation {}".format( - json_data["matrixId"], json_data["status"] - ) - ) + print("Matrix {} calculation {}".format(json_data["matrixId"], json_data["status"])) return False elif json_data.get("error") is not None and json_data.get("error_description"): raise HEREError( - "Error occurred on __is_correct_response: " - + json_data["error"] - + ", description: " - + json_data["error_description"] + "Error occurred on __is_correct_response: " + json_data["error"] + ", description: " + json_data["error_description"] ) elif json_data.get("title") is not None and json_data.get("status"): - raise HEREError( - "Error occurred on __is_correct_response: " - + json_data["title"] - + ", status: " - + json_data["status"] - ) + raise HEREError("Error occurred on __is_correct_response: " + json_data["title"] + ", status: " + json_data["status"]) def async_matrix( self, token: str, - origins: Union[List[float], str], - destinations: Union[List[float], str], + origins: list[float] | str, + destinations: list[float] | str, matrix_type: MatrixRoutingType = MatrixRoutingType.world, - center: Optional[List[float]] = None, - radius: Optional[int] = None, - profile: Optional[MatrixRoutingProfile] = None, + center: list[float] | None = None, + radius: int | None = None, + profile: MatrixRoutingProfile | None = None, departure: str = None, - routing_mode: Optional[MatrixRoutingMode] = None, - transport_mode: Optional[MatrixRoutingTransportMode] = None, - avoid: Optional[Avoid] = None, - truck: Optional[Truck] = None, - matrix_attributes: Optional[List[MatrixSummaryAttribute]] = None, - ) -> Optional[RoutingMatrixResponse]: - """Async request a matrix of route summaries between M starts and N destinations. + routing_mode: MatrixRoutingMode | None = None, + transport_mode: MatrixRoutingTransportMode | None = None, + avoid: Avoid | None = None, + truck: Truck | None = None, + matrix_attributes: list[MatrixSummaryAttribute] | None = None, + ) -> RoutingMatrixResponse | None: + """ + Async request a matrix of route summaries between M starts and N destinations. + Args: token (str): Bearer token required for async calls. This is the only working solution for now. @@ -761,12 +773,14 @@ def async_matrix( Different truck options to use during route calculation when transportMode = truck. matrix_attributes (List): List of MatrixSummaryAttribute enums. + Returns: RoutingMatrixResponse. + Raises: HEREError: If an error is received from the server. - """ + """ query_params = {} request_body = self.__prepare_matrix_request_body( @@ -790,16 +804,10 @@ def async_matrix( "Authorization": str.format("Bearer {0}", token), } json_data = json.dumps(request_body) - response = requests.post( - url, json=request_body, headers=headers, timeout=self._timeout - ) + response = requests.post(url, json=request_body, headers=headers, timeout=self._timeout) if response.status_code == requests.codes.ACCEPTED: json_data = response.json() - print( - "Matrix {} calculation {}".format( - json_data["matrixId"], json_data["status"] - ) - ) + print("Matrix {} calculation {}".format(json_data["matrixId"], json_data["status"])) poll_url = json_data["statusUrl"] headers = {"Authorization": str.format("Bearer {0}", token)} print("Polling matrix calculation started!") @@ -814,34 +822,17 @@ def async_matrix( return RoutingMatrixResponse.new_from_jsondict(poll_data) else: json_data = response.json() - if ( - json_data.get("error") is not None - and json_data.get("error_description") is not None - ): - raise HEREError( - "Error occurred on async_matrix: " - + json_data["error"] - + ", description: " - + json_data["error_description"] - ) - elif ( - json_data.get("title") is not None - and json_data.get("cause") is not None - ): + if json_data.get("error") is not None and json_data.get("error_description") is not None: raise HEREError( - "Error occurred on async_matrix: " - + json_data["title"] - + ", cause: " - + json_data["cause"] + "Error occurred on async_matrix: " + json_data["error"] + ", description: " + json_data["error_description"] ) + elif json_data.get("title") is not None and json_data.get("cause") is not None: + raise HEREError("Error occurred on async_matrix: " + json_data["title"] + ", cause: " + json_data["cause"]) else: - raise HEREError( - "Error occurred on async_matrix " + sys._getframe(1).f_code.co_name - ) + raise HEREError("Error occurred on async_matrix " + sys._getframe(1).f_code.co_name) - def _get_coordinates_for_location_name(self, location_name: str) -> List[float]: + def _get_coordinates_for_location_name(self, location_name: str) -> list[float]: """Use the Geocoder API to resolve a location name to a set of coordinates.""" - geocoder_api = GeocoderApi(self._api_key) try: geocoder_response = geocoder_api.free_form(location_name) @@ -853,7 +844,6 @@ def _get_coordinates_for_location_name(self, location_name: str) -> List[float]: @staticmethod def _convert_datetime_to_isoformat(datetime_object): """Convert a datetime.datetime object to an ISO8601 string.""" - if isinstance(datetime_object, datetime.datetime): datetime_object = datetime_object.isoformat() return datetime_object @@ -861,15 +851,12 @@ def _convert_datetime_to_isoformat(datetime_object): @staticmethod def _get_route_from_non_vehicle_maneuver(maneuver): """Extract a short route description from the maneuver instructions.""" - road_names = [] for step in maneuver: instruction = step["instruction"] try: - road_name = instruction.split('')[1].split( - "" - )[0] + road_name = instruction.split('')[1].split("")[0] road_name = road_name.replace("(", "").replace(")", "") # Only add if it does not repeat @@ -883,7 +870,6 @@ def _get_route_from_non_vehicle_maneuver(maneuver): @staticmethod def _get_route_from_public_transport_line(public_transport_line_segment): """Extract a short route description from the public transport lines.""" - lines = [] for line_info in public_transport_line_segment: lines.append(line_info["lineName"] + " - " + line_info["destination"]) @@ -894,21 +880,16 @@ def _get_route_from_public_transport_line(public_transport_line_segment): @staticmethod def _get_route_from_vehicle_maneuver(maneuver): """Extract a short route description from the maneuver instructions.""" - road_names = [] for step in maneuver: instruction = step["instruction"] try: - road_number = instruction.split('')[1].split( - "" - )[0] + road_number = instruction.split('')[1].split("")[0] road_name = road_number.replace("(", "").replace(")", "") try: - street_name = instruction.split('')[ - 1 - ].split("")[0] + street_name = instruction.split('')[1].split("")[0] street_name = street_name.replace("(", "").replace(")", "") road_name += " - " + street_name @@ -926,8 +907,8 @@ def _get_route_from_vehicle_maneuver(maneuver): class InvalidCredentialsError(HEREError): - - """Invalid Credentials Error Type. + """ + Invalid Credentials Error Type. This error is returned if the specified token was invalid or no contract could be found for this token. @@ -935,8 +916,8 @@ class InvalidCredentialsError(HEREError): class InvalidInputDataError(HEREError): - - """Invalid Input Data Error Type. + """ + Invalid Input Data Error Type. This error is returned if the specified request parameters contain invalid data, such as due to wrong parameter syntax or invalid parameter @@ -945,8 +926,8 @@ class InvalidInputDataError(HEREError): class WaypointNotFoundError(HEREError): - - """Waypoint not found Error Type. + """ + Waypoint not found Error Type. This error indicates that one of the requested waypoints (start/end or via point) could not be found in the routing network. @@ -954,8 +935,8 @@ class WaypointNotFoundError(HEREError): class NoRouteFoundError(HEREError): - - """No Route Found Error Type. + """ + No Route Found Error Type. This error indicates that no route could be constructed based on the input parameter. @@ -963,8 +944,8 @@ class NoRouteFoundError(HEREError): class LinkIdNotFoundError(HEREError): - - """Link Not Found Error Type. + """ + Link Not Found Error Type. This error indicates that a link ID passed as input parameter could not be found in the underlying map data. @@ -972,8 +953,8 @@ class LinkIdNotFoundError(HEREError): class RouteNotReconstructedError(HEREError): - - """Route Not Reconstructed Error Type. + """ + Route Not Reconstructed Error Type. This error indicates that the RouteId is invalid (RouteId can not be decoded into valid data) or route failed to be reconstructed from the @@ -985,7 +966,6 @@ class RouteNotReconstructedError(HEREError): # pylint: disable=R0911 def error_from_routing_service_error(json_data): """Return the correct error class for routing errors.""" - if "error" in json_data: return _auth_error(json_data) elif "status" in json_data: @@ -994,13 +974,12 @@ def error_from_routing_service_error(json_data): return _request_error(json_data) else: return _default_error(json_data) - -def _auth_error(json_data): - """ 'error' in response data, return appropriate error.""" +def _auth_error(json_data): + """'error' in response data, return appropriate error.""" error_type = json_data["error"] - + if error_type in ["Unauthorized", "Forbidden"]: return InvalidCredentialsError(json_data["error_description"]) else: @@ -1008,8 +987,7 @@ def _auth_error(json_data): def _status_error(json_data): - """ 'status' in response data, return appropriate error.""" - + """'status' in response data, return appropriate error.""" error_msg = f"Cause: {json_data['cause']}; Action: {json_data['action']}" status_code = json_data["status"] if status_code == 400: @@ -1020,10 +998,8 @@ def _status_error(json_data): return _default_error(json_data) - def _request_error(json_data): - """ 'subtype' in error response, return appropriate response""" - + """'subtype' in error response, return appropriate response""" subtype = json_data["subtype"] details = json_data["details"] @@ -1042,8 +1018,7 @@ def _request_error(json_data): def _default_error(json_data): - """ default response message when error type is unknown.""" - - function_name = sys._getframe(1).f_code.co_name - default_error_message = f"Error occurred on {function_name} - API Response: {json_data}" - return HEREError(default_error_message) + """Default response message when error type is unknown.""" + function_name = sys._getframe(1).f_code.co_name + default_error_message = f"Error occurred on {function_name} - API Response: {json_data}" + return HEREError(default_error_message) diff --git a/herepy/traffic_api.py b/src/herepy/traffic_api.py similarity index 75% rename from herepy/traffic_api.py rename to src/herepy/traffic_api.py index 671afd0..ac8a9b3 100644 --- a/herepy/traffic_api.py +++ b/src/herepy/traffic_api.py @@ -3,16 +3,21 @@ import json import sys from enum import Enum -from typing import List, Optional import requests from herepy.error import HEREError, InvalidRequestError, UnauthorizedError from herepy.here_api import HEREApi -from herepy.here_enum import (FlowProximityAdditionalAttributes, - IncidentsCriticalityInt, IncidentsCriticalityStr) -from herepy.models import (TrafficFlowAvailabilityResponse, - TrafficFlowResponse, TrafficIncidentResponse) +from herepy.here_enum import ( + FlowProximityAdditionalAttributes, + IncidentsCriticalityInt, + IncidentsCriticalityStr, +) +from herepy.models import ( + TrafficFlowAvailabilityResponse, + TrafficFlowResponse, + TrafficIncidentResponse, +) from herepy.utils import Utils @@ -20,22 +25,24 @@ class TrafficApi(HEREApi): """A python interface into the HERE Traffic API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a TrafficApi instance. + """ + Returns a TrafficApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(TrafficApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://traffic.ls.hereapi.com/traffic/6.1/" def __get(self, url, data): url = Utils.build_url(url, extra_params=data) response = requests.get(url, timeout=self._timeout) json_data = json.loads(response._content.decode("utf8")) - if json_data.get("TRAFFIC_ITEMS") != None: + if json_data.get("TRAFFIC_ITEMS") is not None: return TrafficIncidentResponse.new_from_jsondict( json_data, param_defaults={ @@ -46,7 +53,7 @@ def __get(self, url, data): "error": None, }, ) - elif json_data.get("RWS") != None: + elif json_data.get("RWS") is not None: return TrafficFlowResponse.new_from_jsondict( json_data, param_defaults={ @@ -56,10 +63,8 @@ def __get(self, url, data): "UNITS": None, }, ) - elif json_data.get("Response") != None: - return TrafficFlowAvailabilityResponse.new_from_jsondict( - json_data, param_defaults={"Response": None} - ) + elif json_data.get("Response") is not None: + return TrafficFlowAvailabilityResponse.new_from_jsondict(json_data, param_defaults={"Response": None}) else: error = self.__get_error_from_response(json_data) raise error @@ -69,9 +74,7 @@ def __get_error_from_response(self, json_data): if json_data["error"] == "Unauthorized": return UnauthorizedError(json_data["error_description"]) error_type = json_data.get("Type") - error_message = json_data.get( - "Message", "Error occurred on " + sys._getframe(1).f_code.co_name - ) + error_message = json_data.get("Message", "Error occurred on " + sys._getframe(1).f_code.co_name) if error_type == "Invalid Request": return InvalidRequestError(error_message) else: @@ -84,16 +87,14 @@ def __prepare_str_values(self, enums: [Enum]): values = values[:-1] return values - def __prepare_criticality_int_values( - self, criticality_enums: [IncidentsCriticalityInt] - ): + def __prepare_criticality_int_values(self, criticality_enums: [IncidentsCriticalityInt]): criticality_values = "" for criticality in criticality_enums: criticality_values += str(criticality.__int__()) + "," criticality_values = criticality_values[:-1] return criticality_values - def __prepare_corridor_value(self, points: List[List[float]], width: int): + def __prepare_corridor_value(self, points: list[list[float]], width: int): corridor_str = "" for lat_long_pair in points: corridor_str += str.format("{0},{1};", lat_long_pair[0], lat_long_pair[1]) @@ -102,11 +103,13 @@ def __prepare_corridor_value(self, points: List[List[float]], width: int): def incidents_in_bounding_box( self, - top_left: List[float], - bottom_right: List[float], + top_left: list[float], + bottom_right: list[float], criticality: [IncidentsCriticalityStr], - ) -> Optional[TrafficIncidentResponse]: - """Request traffic incident information within specified area. + ) -> TrafficIncidentResponse | None: + """ + Request traffic incident information within specified area. + Args: top_left (List): List contains latitude and longitude in order. @@ -114,11 +117,13 @@ def incidents_in_bounding_box( List contains latitude and longitude in order. criticality (List): List of IncidentsCriticalityStr. + Returns: TrafficIncidentResponse Raises: - HEREError""" + HEREError + """ data = { "bbox": str.format( "{0},{1};{2},{3}", @@ -132,20 +137,22 @@ def incidents_in_bounding_box( } return self.__get(self._base_url + "incidents.json", data) - def incidents_in_corridor( - self, points: List[List[float]], width: int - ) -> Optional[TrafficIncidentResponse]: - """Request traffic incidents for a defined route. + def incidents_in_corridor(self, points: list[list[float]], width: int) -> TrafficIncidentResponse | None: + """ + Request traffic incidents for a defined route. + Args: points (List): List contains lists of latitude and longitude pairs in order. width (int): Width of corridor. + Returns: TrafficIncidentResponse Raises: - HEREError""" + HEREError + """ data = { "corridor": self.__prepare_corridor_value(points=points, width=width), "apiKey": self._api_key, @@ -158,8 +165,10 @@ def incidents_via_proximity( longitude: float, radius: int, criticality: [IncidentsCriticalityInt], - ) -> Optional[TrafficIncidentResponse]: - """Request traffic incident information within specified area. + ) -> TrafficIncidentResponse | None: + """ + Request traffic incident information within specified area. + Args: latitude (float): Latitude of specified area. @@ -169,30 +178,34 @@ def incidents_via_proximity( Radius of area in meters. criticality (List): List of IncidentsCriticalityInt. + Returns: TrafficIncidentResponse Raises: - HEREError""" + HEREError + """ data = { "prox": str.format("{0},{1},{2}", latitude, longitude, radius), - "criticality": self.__prepare_criticality_int_values( - criticality_enums=criticality - ), + "criticality": self.__prepare_criticality_int_values(criticality_enums=criticality), "apiKey": self._api_key, } return self.__get(self._base_url + "incidents.json", data) - def flow_using_quadkey(self, quadkey: str) -> Optional[TrafficFlowResponse]: - """Request traffic flow information using a quadkey. + def flow_using_quadkey(self, quadkey: str) -> TrafficFlowResponse | None: + """ + Request traffic flow information using a quadkey. + Args: quadkey (str): The quadkey unique defines a region of the globe using a standard addressing algortihm. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "quadkey": quadkey, "apiKey": self._api_key, @@ -201,11 +214,13 @@ def flow_using_quadkey(self, quadkey: str) -> Optional[TrafficFlowResponse]: def flow_within_boundingbox( self, - top_left: List[float], - bottom_right: List[float], + top_left: list[float], + bottom_right: list[float], response_attributes: str = "sh,fc", - ) -> Optional[TrafficFlowResponse]: - """Request traffic flow information within specified area. + ) -> TrafficFlowResponse | None: + """ + Request traffic flow information within specified area. + Args: top_left (List): List contains latitude and longitude in order. @@ -213,11 +228,13 @@ def flow_within_boundingbox( List contains latitude and longitude in order. response_attributes (String): String containing response attributes separated by commas. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "bbox": str.format( "{0},{1};{2},{3}", @@ -231,10 +248,10 @@ def flow_within_boundingbox( } return self.__get(self._base_url + "flow.json", data) - def flow_using_proximity( - self, latitude: float, longitude: float, distance: int - ) -> Optional[TrafficFlowResponse]: - """Request traffic flow for a circle around a defined point. + def flow_using_proximity(self, latitude: float, longitude: float, distance: int) -> TrafficFlowResponse | None: + """ + Request traffic flow for a circle around a defined point. + Args: latitude (float): List contains latitude and longitude in order. @@ -242,11 +259,13 @@ def flow_using_proximity( List contains latitude and longitude in order. distance (int): Extending a distance of metres in all directions. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "prox": str.format( "{0},{1},{2}", @@ -264,8 +283,10 @@ def flow_using_proximity_returning_additional_attributes( longitude: float, distance: int, attributes: [FlowProximityAdditionalAttributes], - ) -> Optional[TrafficFlowResponse]: - """Request traffic flow information using proximity, returning shape and functional class. + ) -> TrafficFlowResponse | None: + """ + Request traffic flow information using proximity, returning shape and functional class. + Args: latitude (float): List contains latitude and longitude in order. @@ -275,11 +296,13 @@ def flow_using_proximity_returning_additional_attributes( Extending a distance of metres in all directions. attributes (List): List that contains FlowProximityAdditionalAttributes. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "prox": str.format( "{0},{1},{2}", @@ -293,9 +316,11 @@ def flow_using_proximity_returning_additional_attributes( return self.__get(self._base_url + "flow.json", data) def flow_with_minimum_jam_factor( - self, top_left: List[float], bottom_right: List[float], min_jam_factor: int = 7 - ) -> Optional[TrafficFlowResponse]: - """Request traffic flow information in specified area with a jam factor. + self, top_left: list[float], bottom_right: list[float], min_jam_factor: int = 7 + ) -> TrafficFlowResponse | None: + """ + Request traffic flow information in specified area with a jam factor. + Args: top_left (List): List contains latitude and longitude in order. @@ -303,11 +328,13 @@ def flow_with_minimum_jam_factor( List contains latitude and longitude in order. min_jam_factor (int): Severe congestion with a jam factor greater than 7. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "bbox": str.format( "{0},{1};{2},{3}", @@ -321,52 +348,59 @@ def flow_with_minimum_jam_factor( } return self.__get(self._base_url + "flow.json", data) - def flow_in_corridor( - self, points: List[List[float]], width: int - ) -> Optional[TrafficFlowResponse]: - """Request traffic flow for a defined route. + def flow_in_corridor(self, points: list[list[float]], width: int) -> TrafficFlowResponse | None: + """ + Request traffic flow for a defined route. + Args: points (List): List contains lists of latitude and longitude pairs in order. width (int): Width of corridor (in meters). + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "corridor": self.__prepare_corridor_value(points=points, width=width), "apiKey": self._api_key, } return self.__get(self._base_url + "flow.json", data) - def flow_availability_data(self) -> Optional[TrafficFlowAvailabilityResponse]: - """Flow availability requests allow you to see what traffic flow coverage exists in the current Traffic API. + def flow_availability_data(self) -> TrafficFlowAvailabilityResponse | None: + """ + Flow availability requests allow you to see what traffic flow coverage exists in the current Traffic API. + Returns: TrafficFlowAvailabilityResponse Raises: - HEREError""" + HEREError + """ data = { "apiKey": self._api_key, } return self.__get(self._base_url + "flowavailability.json", data) - def additional_attributes( - self, quadkey: str, attributes: [FlowProximityAdditionalAttributes] - ) -> [TrafficFlowResponse]: - """Request traffic flow including shape and functional class information. + def additional_attributes(self, quadkey: str, attributes: [FlowProximityAdditionalAttributes]) -> [TrafficFlowResponse]: + """ + Request traffic flow including shape and functional class information. + Args: quadkey (str): The quadkey unique defines a region of the globe using a standard addressing algortihm. attributes (List): List that contains FlowProximityAdditionalAttributes. + Returns: TrafficFlowResponse Raises: - HEREError""" + HEREError + """ data = { "quadkey": quadkey, "responseattibutes": self.__prepare_str_values(enums=attributes), diff --git a/herepy/utils.py b/src/herepy/utils.py similarity index 91% rename from herepy/utils.py rename to src/herepy/utils.py index 5b384b2..1fef167 100644 --- a/herepy/utils.py +++ b/src/herepy/utils.py @@ -7,19 +7,23 @@ from herepy.error import HEREError -class Utils(object): +class Utils: """Helper class for main api classes""" @staticmethod def encode_parameters(parameters): - """Return a string in key=value&key=value form. + """ + Return a string in key=value&key=value form. Values of None are not included in the output string. + Args: parameters (dict): dictionary of query parameters to be converted. + Returns: A URL-encoded string in "key=value&key=value" form. If the parameter value is a dict, the encoded string is converted to "main_key[sub_key]=sub_value". + """ if parameters is None: return None @@ -38,16 +42,20 @@ def encode_parameters(parameters): @staticmethod def build_url(url, extra_params=None): - """Builds a url with given parameters which will + """ + Builds a url with given parameters which will be used in requests. + Args: url (str): base url. extra_params (dict): dictionary of query parameters. + Returns: - A encoded url ready for the request""" + A encoded url ready for the request + """ # Break url into constituent parts (scheme, netloc, path, params, query, fragment) = urlparse(url) diff --git a/herepy/vector_tile_api.py b/src/herepy/vector_tile_api.py similarity index 82% rename from herepy/vector_tile_api.py rename to src/herepy/vector_tile_api.py index 6a74b31..9f1e395 100644 --- a/herepy/vector_tile_api.py +++ b/src/herepy/vector_tile_api.py @@ -2,7 +2,6 @@ import json import sys -from typing import Dict, Optional import requests @@ -16,15 +15,17 @@ class VectorTileApi(HEREApi): """A python interface into the HERE Vector Tile API""" def __init__(self, api_key: str = None, timeout: int = None): - """Returns a VectorTileApi instance. + """ + Returns a VectorTileApi instance. + Args: api_key (str): API key taken from HERE Developer Portal. timeout (int): Timeout limit for requests. - """ - super(VectorTileApi, self).__init__(api_key, timeout) + """ + super().__init__(api_key, timeout) self._base_url = "https://vector.hereapi.com/v2/vectortiles/" def __get_error_from_response(self, json_data): @@ -35,9 +36,7 @@ def __get_error_from_response(self, json_data): error_type = json_data.get("Type") error_message = json_data.get( "Message", - error_description - + ", error occurred on " - + sys._getframe(1).f_code.co_name, + error_description + ", error occurred on " + sys._getframe(1).f_code.co_name, ) if error_type == "Invalid Request": return InvalidRequestError(error_message) @@ -52,10 +51,12 @@ def get_vectortile( layer: VectorMapTileLayer = VectorMapTileLayer.base, projection: str = "mc", tile_format: str = "omv", - query_parameters: Optional[Dict] = None, - headers: Optional[Dict] = None, - ) -> Optional[bytes]: - """Retrieves the protocol buffer encoded binary tile. + query_parameters: dict | None = None, + headers: dict | None = None, + ) -> bytes | None: + """ + Retrieves the protocol buffer encoded binary tile. + Args: latitude (float): Latitude value to be used to fetch map tile. @@ -74,15 +75,15 @@ def get_vectortile( Optional Query Parameters. Refer to the API definition for values. headers (Optional[Dict]): Optional headers. Refer to the API definition for values. + Returns: Vector tile as bytes. + Raises: HEREError - """ - column, row = MercatorProjection.get_column_row( - latitude=latitude, longitude=longitude, zoom=zoom - ) + """ + column, row = MercatorProjection.get_column_row(latitude=latitude, longitude=longitude, zoom=zoom) url = str.format( self._base_url + "{}/{}/{}/{}/{}/{}", layer.__str__(), @@ -97,15 +98,13 @@ def get_vectortile( else: query_parameters = {"apiKey": self._api_key} url = Utils.build_url(url, extra_params=query_parameters) - response = requests.get( - url, headers=headers, timeout=self._timeout, stream=True - ) + response = requests.get(url, headers=headers, timeout=self._timeout, stream=True) if isinstance(response.content, bytes): try: json_data = json.loads(response.content.decode("utf8")) if "error" in json_data: error = self.__get_error_from_response(json_data) raise error - except UnicodeDecodeError as err: + except UnicodeDecodeError: print("Vector tile downloaded") return response.content diff --git a/tests/test_destination_weather_api.py b/tests/test_destination_weather_api.py index 8484e04..216cc15 100644 --- a/tests/test_destination_weather_api.py +++ b/tests/test_destination_weather_api.py @@ -1,14 +1,16 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses -from herepy import (DestinationWeatherApi, DestinationWeatherResponse, - InvalidRequestError, UnauthorizedError, WeatherProductType) +from herepy import ( + DestinationWeatherApi, + DestinationWeatherResponse, + InvalidRequestError, + UnauthorizedError, + WeatherProductType, +) class DestinationWeatherApiTest(unittest.TestCase): @@ -26,9 +28,7 @@ def test_initiation(self): @responses.activate def test_invalid_request_is_thrown(self): - with open( - "testdata/models/destination_weather_error_invalid_request.json", "r" - ) as f: + with open("testdata/models/destination_weather_error_invalid_request.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -43,9 +43,7 @@ def test_invalid_request_is_thrown(self): @responses.activate def test_unauthorized_is_thrown(self): - with open( - "testdata/models/destination_weather_error_unauthorized.json", "r" - ) as f: + with open("testdata/models/destination_weather_error_unauthorized.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -60,7 +58,7 @@ def test_unauthorized_is_thrown(self): @responses.activate def test_weather_for_location_name(self): - with open("testdata/models/destination_weather_forecasts.json", "r") as f: + with open("testdata/models/destination_weather_forecasts.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -76,7 +74,7 @@ def test_weather_for_location_name(self): @responses.activate def test_weather_for_coordinates(self): - with open("testdata/models/destination_weather_forecasts.json", "r") as f: + with open("testdata/models/destination_weather_forecasts.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -93,7 +91,7 @@ def test_weather_for_coordinates(self): @responses.activate def test_weather_for_zip_code(self): - with open("testdata/models/destination_weather_forecasts.json", "r") as f: + with open("testdata/models/destination_weather_forecasts.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -109,7 +107,7 @@ def test_weather_for_zip_code(self): @responses.activate def test_weather_product_type_alerts(self): - with open("testdata/models/destination_weather_alerts.json", "r") as f: + with open("testdata/models/destination_weather_alerts.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -125,7 +123,7 @@ def test_weather_product_type_alerts(self): @responses.activate def test_weather_product_type_forecast_7days(self): - with open("testdata/models/destination_weather_forecasts.json", "r") as f: + with open("testdata/models/destination_weather_forecasts.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -141,9 +139,7 @@ def test_weather_product_type_forecast_7days(self): @responses.activate def test_weather_product_type_forecast_7days_simple(self): - with open( - "testdata/models/destination_weather_forecasts_simple.json", "r" - ) as f: + with open("testdata/models/destination_weather_forecasts_simple.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -159,9 +155,7 @@ def test_weather_product_type_forecast_7days_simple(self): @responses.activate def test_weather_product_type_forecast_astronomy(self): - with open( - "testdata/models/destination_weather_forecasts_astronomy.json", "r" - ) as f: + with open("testdata/models/destination_weather_forecasts_astronomy.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -177,9 +171,7 @@ def test_weather_product_type_forecast_astronomy(self): @responses.activate def test_weather_product_type_forecast_hourly(self): - with open( - "testdata/models/destination_weather_forecasts_hourly.json", "r" - ) as f: + with open("testdata/models/destination_weather_forecasts_hourly.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -195,9 +187,7 @@ def test_weather_product_type_forecast_hourly(self): @responses.activate def test_weather_product_type_nws_alerts(self): - with open( - "testdata/models/destination_weather_forecasts_nsw_alerts.json", "r" - ) as f: + with open("testdata/models/destination_weather_forecasts_nsw_alerts.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_enum.py b/tests/test_enum.py index d4f04f1..0d2ed59 100644 --- a/tests/test_enum.py +++ b/tests/test_enum.py @@ -1,25 +1,44 @@ #!/usr/bin/env python -import sys import unittest -from enum import Enum - -from herepy import (AerialMapTileResourceType, AvoidFeature, - BaseMapTileResourceType, EVStationConnectorTypes, - FlowProximityAdditionalAttributes, IncidentsCriticalityInt, - IncidentsCriticalityStr, IsolineRoutingMode, - IsolineRoutingOptimizationMode, IsolineRoutingRangeType, - IsolineRoutingTransportMode, MapImageFormatType, - MapImageResourceType, MapTileApiType, MatrixRoutingMode, - MatrixRoutingProfile, MatrixRoutingTransportMode, - MatrixRoutingType, MatrixSummaryAttribute, - MultiplePickupOfferType, PlacesCategory, - PublicTransitModeType, PublicTransitRoutingMode, - PublicTransitSearchMethod, RouteMode, - RoutingApiReturnField, RoutingApiSpanField, RoutingMetric, - RoutingMode, RoutingTransportMode, ShippedHazardousGood, - TrafficMapTileResourceType, TruckType, TunnelCategory, - VectorMapTileLayer, WeatherProductType) + +from herepy import ( + AerialMapTileResourceType, + AvoidFeature, + BaseMapTileResourceType, + EVStationConnectorTypes, + FlowProximityAdditionalAttributes, + IncidentsCriticalityInt, + IncidentsCriticalityStr, + IsolineRoutingMode, + IsolineRoutingOptimizationMode, + IsolineRoutingRangeType, + IsolineRoutingTransportMode, + MapImageFormatType, + MapImageResourceType, + MapTileApiType, + MatrixRoutingMode, + MatrixRoutingProfile, + MatrixRoutingTransportMode, + MatrixRoutingType, + MatrixSummaryAttribute, + MultiplePickupOfferType, + PlacesCategory, + PublicTransitModeType, + PublicTransitRoutingMode, + PublicTransitSearchMethod, + RouteMode, + RoutingApiReturnField, + RoutingApiSpanField, + RoutingMetric, + RoutingMode, + RoutingTransportMode, + ShippedHazardousGood, + TrafficMapTileResourceType, + TruckType, + TunnelCategory, + VectorMapTileLayer, +) class RouteModeTest(unittest.TestCase): diff --git a/tests/test_ev_charging_stations_api.py b/tests/test_ev_charging_stations_api.py index 79b0fcd..3465769 100644 --- a/tests/test_ev_charging_stations_api.py +++ b/tests/test_ev_charging_stations_api.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses @@ -23,7 +20,7 @@ def test_initiation(self): @responses.activate def test_get_stations_circular_search_whensucceed(self): - with open("testdata/models/ev_charging_stations_circular.json", "r") as f: + with open("testdata/models/ev_charging_stations_circular.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -45,9 +42,7 @@ def test_get_stations_circular_search_whensucceed(self): @responses.activate def test_get_stations_circular_search_whenerroroccurred(self): - with open( - "testdata/models/ev_charging_stations_error_unauthorized.json", "r" - ) as f: + with open("testdata/models/ev_charging_stations_error_unauthorized.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -56,13 +51,11 @@ def test_get_stations_circular_search_whenerroroccurred(self): status=200, ) with self.assertRaises(herepy.HEREError): - self._api.get_stations_circular_search( - latitude=52.516667, longitude=13.383333, radius=5000 - ) + self._api.get_stations_circular_search(latitude=52.516667, longitude=13.383333, radius=5000) @responses.activate def test_get_stations_bounding_box_whensucceed(self): - with open("testdata/models/ev_charging_stations_circular.json", "r") as f: + with open("testdata/models/ev_charging_stations_circular.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -83,9 +76,7 @@ def test_get_stations_bounding_box_whensucceed(self): @responses.activate def test_get_stations_bounding_box_whenerroroccurred(self): - with open( - "testdata/models/ev_charging_stations_error_unauthorized.json", "r" - ) as f: + with open("testdata/models/ev_charging_stations_error_unauthorized.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -94,13 +85,11 @@ def test_get_stations_bounding_box_whenerroroccurred(self): status=200, ) with self.assertRaises(herepy.HEREError): - self._api.get_stations_bounding_box( - top_left=[52.8, 11.37309], bottom_right=[52.31, 13.2] - ) + self._api.get_stations_bounding_box(top_left=[52.8, 11.37309], bottom_right=[52.31, 13.2]) @responses.activate def test_get_stations_corridor_whensucceed(self): - with open("testdata/models/ev_charging_stations_circular.json", "r") as f: + with open("testdata/models/ev_charging_stations_circular.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -120,9 +109,7 @@ def test_get_stations_corridor_whensucceed(self): @responses.activate def test_get_stations_corridor_whenerroroccurred(self): - with open( - "testdata/models/ev_charging_stations_error_unauthorized.json", "r" - ) as f: + with open("testdata/models/ev_charging_stations_error_unauthorized.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -146,7 +133,7 @@ def test_get_stations_corridor_whenerroroccurred(self): @responses.activate def test_get_station_details_whensucceed(self): station_id = "276u33db-b2c840878cfc409fa5a0aef858419037" - with open("testdata/models/ev_charging_station_details.json", "r") as f: + with open("testdata/models/ev_charging_station_details.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -161,9 +148,7 @@ def test_get_station_details_whensucceed(self): @responses.activate def test_get_station_details_whenerroroccurred(self): station_id = "276u33db-b2c840878cfc409fa5a0aef858419037" - with open( - "testdata/models/ev_charging_stations_error_unauthorized.json", "r" - ) as f: + with open("testdata/models/ev_charging_stations_error_unauthorized.json") as f: expected_response = f.read() responses.add( responses.GET, diff --git a/tests/test_fleet_telematics_api.py b/tests/test_fleet_telematics_api.py index b87deb8..78ebabe 100644 --- a/tests/test_fleet_telematics_api.py +++ b/tests/test_fleet_telematics_api.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses @@ -22,7 +19,7 @@ def test_initiation(self): @responses.activate def test_find_sequence_whensucceed(self): - with open("testdata/models/fleet_telematics_find_sequence.json", "r") as f: + with open("testdata/models/fleet_telematics_find_sequence.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -54,7 +51,7 @@ def test_find_sequence_whensucceed(self): @responses.activate def test_find_sequence_whenerroroccurred(self): - with open("testdata/models/fleet_telematics_unauthorized_error.json", "r") as f: + with open("testdata/models/fleet_telematics_unauthorized_error.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -87,7 +84,7 @@ def test_find_sequence_whenerroroccurred(self): @responses.activate def test_find_pickups_whensucceed(self): - with open("testdata/models/fleet_telematics_find_pickups.json", "r") as f: + with open("testdata/models/fleet_telematics_find_pickups.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -150,7 +147,7 @@ def test_find_pickups_whensucceed(self): @responses.activate def test_find_pickups_whenerroroccurred(self): - with open("testdata/models/fleet_telematics_unauthorized_error.json", "r") as f: + with open("testdata/models/fleet_telematics_unauthorized_error.json") as f: expected_response = f.read() responses.add( responses.GET, diff --git a/tests/test_geocoder_api.py b/tests/test_geocoder_api.py index caedaf3..93fff84 100644 --- a/tests/test_geocoder_api.py +++ b/tests/test_geocoder_api.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses @@ -18,13 +15,11 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, herepy.GeocoderApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://geocode.search.hereapi.com/v1/geocode" - ) + self.assertEqual(self._api._base_url, "https://geocode.search.hereapi.com/v1/geocode") @responses.activate def test_freeform_whensucceed(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -38,7 +33,7 @@ def test_freeform_whensucceed(self): @responses.activate def test_freeform_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -51,7 +46,7 @@ def test_freeform_whenerroroccurred(self): @responses.activate def test_address_withboundingbox_whensucceed(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -59,15 +54,13 @@ def test_address_withboundingbox_whensucceed(self): expectedResponse, status=200, ) - response = self._api.address_with_boundingbox( - "200 S Mathilda Sunnyvale CA", [42.3952, -71.1056], [42.3312, -71.0228] - ) + response = self._api.address_with_boundingbox("200 S Mathilda Sunnyvale CA", [42.3952, -71.1056], [42.3312, -71.0228]) self.assertTrue(response) self.assertIsInstance(response, herepy.GeocoderResponse) @responses.activate def test_address_withboundingbox_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -76,13 +69,11 @@ def test_address_withboundingbox_whenerroroccurred(self): status=200, ) with self.assertRaises(herepy.HEREError): - self._api.address_with_boundingbox( - "", [-42.3952, -71.1056], [-42.3312, -71.0228] - ) + self._api.address_with_boundingbox("", [-42.3952, -71.1056], [-42.3312, -71.0228]) @responses.activate def test_addresswithdetails_whensucceed(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -102,7 +93,7 @@ def test_addresswithdetails_whensucceed(self): @responses.activate def test_address_with_detail_without_street(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -110,18 +101,13 @@ def test_address_with_detail_without_street(self): expected_response, status=200, ) - response = self._api.address_with_details( - city="Istanbul", - country="Turkey", - house_number=34, - street= None - ) + response = self._api.address_with_details(city="Istanbul", country="Turkey", house_number=34, street=None) self.assertTrue(response) self.assertIsInstance(response, herepy.GeocoderResponse) @responses.activate def test_address_with_detail_without_house_number(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -129,18 +115,13 @@ def test_address_with_detail_without_house_number(self): expected_response, status=200, ) - response = self._api.address_with_details( - street="Barbaros", - city="Istanbul", - country="Turkey", - house_number= None - ) + response = self._api.address_with_details(street="Barbaros", city="Istanbul", country="Turkey", house_number=None) self.assertTrue(response) self.assertIsInstance(response, herepy.GeocoderResponse) @responses.activate def test_address_with_detail_without_country(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expected_response = f.read() responses.add( responses.GET, @@ -148,11 +129,7 @@ def test_address_with_detail_without_country(self): expected_response, status=200, ) - response = self._api.address_with_details( - street="Barbaros", - city="Istanbul", - country= None - ) + response = self._api.address_with_details(street="Barbaros", city="Istanbul", country=None) self.assertTrue(response) self.assertIsInstance(response, herepy.GeocoderResponse) @@ -187,7 +164,7 @@ def test_address_with_detail_without_any_detail_raise(self): @responses.activate def test_addresswithdetails_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -200,7 +177,7 @@ def test_addresswithdetails_whenerroroccurred(self): @responses.activate def test_streetintersection_whensucceed(self): - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -214,7 +191,7 @@ def test_streetintersection_whensucceed(self): @responses.activate def test_streetintersection_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_geocoder_autocomplete_api.py b/tests/test_geocoder_autocomplete_api.py index 64bc58e..6cfdda1 100644 --- a/tests/test_geocoder_autocomplete_api.py +++ b/tests/test_geocoder_autocomplete_api.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses @@ -25,7 +22,7 @@ def test_initiation(self): @responses.activate def test_addresssuggestion_whensucceed(self): - with open("testdata/models/geocoder_autocomplete.json", "r") as f: + with open("testdata/models/geocoder_autocomplete.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -39,7 +36,7 @@ def test_addresssuggestion_whensucceed(self): @responses.activate def test_addresssuggestion_whenerroroccurred(self): - with open("testdata/models/geocoder_autocomplete_error.json", "r") as f: + with open("testdata/models/geocoder_autocomplete_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -52,7 +49,7 @@ def test_addresssuggestion_whenerroroccurred(self): @responses.activate def test_limitresultsbyaddress_whensucceed(self): - with open("testdata/models/geocoder_autocomplete.json", "r") as f: + with open("testdata/models/geocoder_autocomplete.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -66,7 +63,7 @@ def test_limitresultsbyaddress_whensucceed(self): @responses.activate def test_limitresultsbyaddress_whenerroroccurred(self): - with open("testdata/models/geocoder_autocomplete_error.json", "r") as f: + with open("testdata/models/geocoder_autocomplete_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_geocoder_reverse_api.py b/tests/test_geocoder_reverse_api.py index dafb136..2770d9e 100644 --- a/tests/test_geocoder_reverse_api.py +++ b/tests/test_geocoder_reverse_api.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import json -import os -import time import unittest import responses @@ -18,13 +15,11 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, herepy.GeocoderReverseApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://revgeocode.search.hereapi.com/v1/revgeocode" - ) + self.assertEqual(self._api._base_url, "https://revgeocode.search.hereapi.com/v1/revgeocode") @responses.activate def test_retrieve_addresses_whensucceed(self): - with open("testdata/models/geocoder_reverse.json", "r") as f: + with open("testdata/models/geocoder_reverse.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -38,7 +33,7 @@ def test_retrieve_addresses_whensucceed(self): @responses.activate def test_retrieve_addresses_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_isoline_routing_api.py b/tests/test_isoline_routing_api.py index 24165e6..adb53f0 100644 --- a/tests/test_isoline_routing_api.py +++ b/tests/test_isoline_routing_api.py @@ -1,16 +1,18 @@ #!/usr/bin/env python import codecs -import json -import os -import time import unittest import responses -from herepy import (HEREError, IsolineRoutingApi, IsolineRoutingMode, - IsolineRoutingResponse, IsolineRoutingTransportMode, - UnauthorizedError) +from herepy import ( + HEREError, + IsolineRoutingApi, + IsolineRoutingMode, + IsolineRoutingResponse, + IsolineRoutingTransportMode, + UnauthorizedError, +) class IsolineRoutingApiTest(unittest.TestCase): @@ -21,9 +23,7 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, IsolineRoutingApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://isoline.router.hereapi.com/v8/isolines" - ) + self.assertEqual(self._api._base_url, "https://isoline.router.hereapi.com/v8/isolines") @responses.activate def test_distance_based_isoline_success(self): @@ -51,9 +51,7 @@ def test_distance_based_isoline_success(self): @responses.activate def test_distance_based_isoline_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -94,9 +92,7 @@ def test_time_isoline_success(self): @responses.activate def test_time_isoline_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -185,9 +181,7 @@ def test_isoline_based_on_consumption_succeed(self): @responses.activate def test_isoline_based_on_consumption_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -301,9 +295,7 @@ def test_isoline_routing_at_specific_time_succeed_with_destination_succeed(self) @responses.activate def test_isoline_routing_at_specific_time_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_map_image_api.py b/tests/test_map_image_api.py index 56ad3a6..1d36705 100644 --- a/tests/test_map_image_api.py +++ b/tests/test_map_image_api.py @@ -1,10 +1,5 @@ #!/usr/bin/env python -import codecs -import io -import json -import os -import sys import unittest from unittest.mock import Mock, patch @@ -19,9 +14,7 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, MapImageApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://image.maps.ls.hereapi.com/mia/1.6/mapview" - ) + self.assertEqual(self._api._base_url, "https://image.maps.ls.hereapi.com/mia/1.6/mapview") @patch("herepy.map_image_api.requests.get") def test_get_mapimage_with_boundingbox(self, mock_get): @@ -66,9 +59,7 @@ def test_get_mapimage_hybrid_daylight_succeed(self, mock_get): mock_get.return_value = Mock(ok=True) byte_im = f.read() mock_get.return_value.content = byte_im - map_image = self._api.get_mapimage( - coordinates=[28.371425, 77.387695], uncertainty="5m", map_scheme=3 - ) + map_image = self._api.get_mapimage(coordinates=[28.371425, 77.387695], uncertainty="5m", map_scheme=3) self.assertIsNotNone(map_image) self.assertTrue(isinstance(map_image, bytes)) @@ -78,9 +69,7 @@ def test_get_mapimage_nodot_succeed(self, mock_get): mock_get.return_value = Mock(ok=True) byte_im = f.read() mock_get.return_value.content = byte_im - map_image = self._api.get_mapimage( - coordinates=[28.371425, 77.387695], uncertainty="5m", nodot=True - ) + map_image = self._api.get_mapimage(coordinates=[28.371425, 77.387695], uncertainty="5m", nodot=True) self.assertIsNotNone(map_image) self.assertTrue(isinstance(map_image, bytes)) @@ -106,9 +95,7 @@ def test_get_mapimage_country_name(self, mock_get): mock_get.return_value = Mock(ok=True) byte_im = f.read() mock_get.return_value.content = byte_im - map_image = self._api.get_mapimage( - coordinates=[60.17675, 24.929974], country_name="Finland", zoom=15 - ) + map_image = self._api.get_mapimage(coordinates=[60.17675, 24.929974], country_name="Finland", zoom=15) self.assertIsNotNone(map_image) self.assertTrue(isinstance(map_image, bytes)) @@ -133,9 +120,7 @@ def test_get_mapimage_encoded_geo_coordinate(self, mock_get): mock_get.return_value = Mock(ok=True) byte_im = f.read() mock_get.return_value.content = byte_im - map_image = self._api.get_mapimage( - encoded_geo_coordinate="QeL4rkKaxoA", zoom=10 - ) + map_image = self._api.get_mapimage(encoded_geo_coordinate="QeL4rkKaxoA", zoom=10) self.assertIsNotNone(map_image) self.assertTrue(isinstance(map_image, bytes)) diff --git a/tests/test_map_tile_api.py b/tests/test_map_tile_api.py index d26c381..d4031c8 100644 --- a/tests/test_map_tile_api.py +++ b/tests/test_map_tile_api.py @@ -1,14 +1,9 @@ #!/usr/bin/env python -import codecs -import io -import json -import os -import sys import unittest from unittest.mock import Mock, patch -from herepy import MapTileApi, MapTileApiType, UnauthorizedError +from herepy import MapTileApi, UnauthorizedError class MapTileApiTest(unittest.TestCase): @@ -26,18 +21,14 @@ def test_get_map_tile_with_parameters_succeed(self, mock_get): with open("testdata/tiles/berlin.png", "rb") as tile: mock_get.return_value = Mock(ok=True) mock_get.return_value.content = tile.read - map_tile = self._api.get_maptile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + map_tile = self._api.get_maptile(latitude=52.525439, longitude=13.38727, zoom=12) self.assertIsNotNone(map_tile) @patch("herepy.map_tile_api.requests.get") def test_get_map_tile_with_parameters_fails(self, mock_get): mock_get.return_value = Mock(ok=True) mock_get.return_value.content = None - map_tile = self._api.get_maptile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + map_tile = self._api.get_maptile(latitude=52.525439, longitude=13.38727, zoom=12) self.assertIsNone(map_tile) @patch("herepy.map_tile_api.requests.get") @@ -70,6 +61,4 @@ def test_get_map_tile_with_default_parameters_unauthorized(self, mock_get): mock_get.return_value = Mock(ok=True) mock_get.return_value.content = f.read() with self.assertRaises(UnauthorizedError): - map_tile = self._api.get_maptile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + map_tile = self._api.get_maptile(latitude=52.525439, longitude=13.38727, zoom=12) diff --git a/tests/test_mercator_projection.py b/tests/test_mercator_projection.py index 50bb415..dbafd97 100644 --- a/tests/test_mercator_projection.py +++ b/tests/test_mercator_projection.py @@ -7,8 +7,6 @@ class MercatorProjectionTest(unittest.TestCase): def test_get_column_row(self): - column, row = MercatorProjection.get_column_row( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + column, row = MercatorProjection.get_column_row(latitude=52.525439, longitude=13.38727, zoom=12) self.assertEqual(column, 2200) self.assertEqual(row, 1343) diff --git a/tests/test_models.py b/tests/test_models.py index 141ba7a..2eb9ebe 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,14 +1,12 @@ #!/usr/bin/env python import json -import re import unittest import herepy class ModelsTest(unittest.TestCase): - with open("testdata/models/geocoder.json", "rb") as f: GEOCODER_SAMPLE_JSON = json.loads(f.read().decode("utf8")) @@ -43,9 +41,7 @@ class ModelsTest(unittest.TestCase): ISOLINE_ROUTING_DISTANCE_JSON = json.loads(f.read().decode("utf8")) def test_geocoder_response(self): - geocoderResponse = herepy.GeocoderResponse.new_from_jsondict( - self.GEOCODER_SAMPLE_JSON - ) + geocoderResponse = herepy.GeocoderResponse.new_from_jsondict(self.GEOCODER_SAMPLE_JSON) try: geocoderResponse.__repr__() except Exception as e: @@ -54,9 +50,7 @@ def test_geocoder_response(self): self.assertTrue(geocoderResponse.as_dict()) def test_routing_response(self): - routingResponse = herepy.RoutingResponse.new_from_jsondict( - self.ROUTING_SAMPLE_JSON - ) + routingResponse = herepy.RoutingResponse.new_from_jsondict(self.ROUTING_SAMPLE_JSON) try: routingResponse.__repr__() except Exception as e: @@ -65,9 +59,7 @@ def test_routing_response(self): self.assertTrue(routingResponse.as_dict()) def test_routingapi_matrix_response(self): - routing_matrix_response = herepy.RoutingResponse.new_from_jsondict( - self.ROUTING_MATRIX_SAMPLE_JSON - ) + routing_matrix_response = herepy.RoutingResponse.new_from_jsondict(self.ROUTING_MATRIX_SAMPLE_JSON) try: routing_matrix_response.__repr__() except Exception as e: @@ -76,11 +68,7 @@ def test_routingapi_matrix_response(self): self.assertTrue(routing_matrix_response.as_dict()) def test_geocoder_autocompleteresponse(self): - geocoderAutoCompleteResponse = ( - herepy.GeocoderAutoCompleteResponse.new_from_jsondict( - self.GEOCODER_AUTO_COMPLETE_SAMPLE_JSON - ) - ) + geocoderAutoCompleteResponse = herepy.GeocoderAutoCompleteResponse.new_from_jsondict(self.GEOCODER_AUTO_COMPLETE_SAMPLE_JSON) try: geocoderAutoCompleteResponse.__repr__() except Exception as e: @@ -89,9 +77,7 @@ def test_geocoder_autocompleteresponse(self): self.assertTrue(geocoderAutoCompleteResponse.as_dict()) def test_placesapi_response(self): - placesApiResponse = herepy.PlacesResponse.new_from_jsondict( - self.PLACES_API_SAMPLE_JSON - ) + placesApiResponse = herepy.PlacesResponse.new_from_jsondict(self.PLACES_API_SAMPLE_JSON) try: placesApiResponse.__repr__() except Exception as e: @@ -100,9 +86,7 @@ def test_placesapi_response(self): self.assertTrue(placesApiResponse.as_dict()) def test_publictransitapi_response(self): - publicTransitResponse = herepy.PublicTransitResponse.new_from_jsondict( - self.PUBLIC_TRANSIT_API_SAMPLE_JSON - ) + publicTransitResponse = herepy.PublicTransitResponse.new_from_jsondict(self.PUBLIC_TRANSIT_API_SAMPLE_JSON) try: publicTransitResponse.__repr__() except Exception as e: @@ -111,9 +95,7 @@ def test_publictransitapi_response(self): self.assertTrue(publicTransitResponse.as_dict()) def test_traffic_incident_response(self): - trafficIncidentResponse = herepy.TrafficIncidentResponse.new_from_jsondict( - self.TRAFFIC_INCIDENTS_SAMPLE_JSON - ) + trafficIncidentResponse = herepy.TrafficIncidentResponse.new_from_jsondict(self.TRAFFIC_INCIDENTS_SAMPLE_JSON) try: trafficIncidentResponse.__repr__() except Exception as e: @@ -122,10 +104,8 @@ def test_traffic_incident_response(self): self.assertTrue(trafficIncidentResponse.as_dict()) def test_destination_weather_response(self): - destinationWeatherResponse = ( - herepy.DestinationWeatherResponse.new_from_jsondict( - self.DESTINATION_WEATHER_SAMPLE_JSON, {"observations": None} - ) + destinationWeatherResponse = herepy.DestinationWeatherResponse.new_from_jsondict( + self.DESTINATION_WEATHER_SAMPLE_JSON, {"observations": None} ) try: destinationWeatherResponse.__repr__() @@ -135,9 +115,7 @@ def test_destination_weather_response(self): self.assertTrue(destinationWeatherResponse.as_dict()) def test_traffic_flow_response(self): - trafficFlowResponse = herepy.TrafficFlowResponse.new_from_jsondict( - self.TRAFFIC_FLOW_SAMPLE_JSON - ) + trafficFlowResponse = herepy.TrafficFlowResponse.new_from_jsondict(self.TRAFFIC_FLOW_SAMPLE_JSON) try: trafficFlowResponse.__repr__() except Exception as e: @@ -146,27 +124,17 @@ def test_traffic_flow_response(self): self.assertIsNotNone(trafficFlowResponse.as_dict()) def test_traffic_flow_availability_response(self): - trafficFlowAvailabilityResponse = ( - herepy.TrafficFlowAvailabilityResponse.new_from_jsondict( - self.TRAFFIC_FLOW_AVAILABILITY_JSON - ) - ) + trafficFlowAvailabilityResponse = herepy.TrafficFlowAvailabilityResponse.new_from_jsondict(self.TRAFFIC_FLOW_AVAILABILITY_JSON) try: trafficFlowAvailabilityResponse.__repr__() except Exception as e: self.fail(e) self.assertIsNotNone(trafficFlowAvailabilityResponse.as_json_string()) self.assertIsNotNone(trafficFlowAvailabilityResponse.as_dict()) - self.assertIsNotNone( - trafficFlowAvailabilityResponse.as_dict()["Response"]["Region"] - ) + self.assertIsNotNone(trafficFlowAvailabilityResponse.as_dict()["Response"]["Region"]) def test_isoline_routing_response(self): - isolineRoutingDistanceResponse = ( - herepy.IsolineRoutingResponse.new_from_jsondict( - self.ISOLINE_ROUTING_DISTANCE_JSON - ) - ) + isolineRoutingDistanceResponse = herepy.IsolineRoutingResponse.new_from_jsondict(self.ISOLINE_ROUTING_DISTANCE_JSON) try: isolineRoutingDistanceResponse.__repr__() except Exception as e: diff --git a/tests/test_places_api.py b/tests/test_places_api.py index b571a75..c5eec51 100644 --- a/tests/test_places_api.py +++ b/tests/test_places_api.py @@ -1,9 +1,5 @@ #!/usr/bin/env python -import codecs -import io -import os -import sys import unittest import responses @@ -19,13 +15,11 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, herepy.PlacesApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://discover.search.hereapi.com/v1/discover" - ) + self.assertEqual(self._api._base_url, "https://discover.search.hereapi.com/v1/discover") @responses.activate def test_onebox_search_whensucceed(self): - with open("testdata/models/places_api.json", "r") as f: + with open("testdata/models/places_api.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -39,7 +33,7 @@ def test_onebox_search_whensucceed(self): @responses.activate def test_onebox_search_whenerroroccurred(self): - with open("testdata/models/places_api_error.json", "r") as f: + with open("testdata/models/places_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -52,7 +46,7 @@ def test_onebox_search_whenerroroccurred(self): @responses.activate def test_search_in_country_whensucceed(self): - with open("testdata/models/places_api.json", "r") as f: + with open("testdata/models/places_api.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -66,7 +60,7 @@ def test_search_in_country_whensucceed(self): @responses.activate def test_search_in_country_whenerroroccurred(self): - with open("testdata/models/places_api_error.json", "r") as f: + with open("testdata/models/places_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -79,7 +73,7 @@ def test_search_in_country_whenerroroccurred(self): @responses.activate def test_places_in_circle_whensucceed(self): - with open("testdata/models/places_api.json", "r") as f: + with open("testdata/models/places_api.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -93,7 +87,7 @@ def test_places_in_circle_whensucceed(self): @responses.activate def test_places_in_circle_whenerroroccurred(self): - with open("testdata/models/places_api_error.json", "r") as f: + with open("testdata/models/places_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_publictransit_api.py b/tests/test_publictransit_api.py index db2a6b3..8855fd3 100644 --- a/tests/test_publictransit_api.py +++ b/tests/test_publictransit_api.py @@ -1,9 +1,5 @@ #!/usr/bin/env python -import codecs -import io -import os -import sys import unittest import responses @@ -23,7 +19,7 @@ def test_initiation(self): @responses.activate def test_find_stations_by_name_whensucceed(self): - with open("testdata/models/public_transit_api.json", "r") as f: + with open("testdata/models/public_transit_api.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -43,7 +39,7 @@ def test_find_stations_by_name_whensucceed(self): @responses.activate def test_find_stations_by_name_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -56,9 +52,7 @@ def test_find_stations_by_name_whenerroroccurred(self): @responses.activate def test_find_stations_nearby_whensucceed(self): - with io.open( - "testdata/models/public_transit_api_nearby.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_api_nearby.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -72,7 +66,7 @@ def test_find_stations_nearby_whensucceed(self): @responses.activate def test_find_stations_nearby_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -85,9 +79,7 @@ def test_find_stations_nearby_whenerroroccurred(self): @responses.activate def test_find_stations_by_id_whensucceed(self): - with io.open( - "testdata/models/public_transit_api_by_id.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_api_by_id.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -101,7 +93,7 @@ def test_find_stations_by_id_whensucceed(self): @responses.activate def test_find_stations_by_id_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -114,9 +106,8 @@ def test_find_stations_by_id_whenerroroccurred(self): @responses.activate def test_find_transit_coverage_in_cities_whensucceed(self): - with io.open( + with open( "testdata/models/public_transit_api_coverage_cities.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -126,15 +117,13 @@ def test_find_transit_coverage_in_cities_whensucceed(self): expectedResponse, status=200, ) - response = self._api.find_transit_coverage_in_cities( - [42.3580, -71.0636], "USA", 50000 - ) + response = self._api.find_transit_coverage_in_cities([42.3580, -71.0636], "USA", 50000) self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @responses.activate def test_find_transit_coverage_in_cities_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -147,9 +136,8 @@ def test_find_transit_coverage_in_cities_whenerroroccurred(self): @responses.activate def test_next_nearby_departures_of_station_whensucceed(self): - with io.open( + with open( "testdata/models/public_transit_api_next_nearby_departures.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -159,15 +147,13 @@ def test_next_nearby_departures_of_station_whensucceed(self): expectedResponse, status=200, ) - response = self._api.next_nearby_departures_of_station( - 402000653, "2017-11-21T11:10:00" - ) + response = self._api.next_nearby_departures_of_station(402000653, "2017-11-21T11:10:00") self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @responses.activate def test_next_nearby_departures_of_station_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -180,9 +166,8 @@ def test_next_nearby_departures_of_station_whenerroroccurred(self): @responses.activate def test_next_departures_from_location_whensucceed(self): - with io.open( + with open( "testdata/models/public_transit_api_next_departures_location.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -192,15 +177,13 @@ def test_next_departures_from_location_whensucceed(self): expectedResponse, status=200, ) - response = self._api.next_departures_from_location( - [51.4477, -0.1669], "2017-11-21T07:30:00" - ) + response = self._api.next_departures_from_location([51.4477, -0.1669], "2017-11-21T07:30:00") self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @responses.activate def test_next_departures_from_location_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -213,9 +196,8 @@ def test_next_departures_from_location_whenerroroccurred(self): @responses.activate def test_next_departures_for_stations_whensucceed(self): - with io.open( + with open( "testdata/models/public_transit_api_next_departures_for_stations.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -225,15 +207,13 @@ def test_next_departures_for_stations_whensucceed(self): expectedResponse, status=200, ) - response = self._api.next_departures_for_stations( - [402000656, 402000653, 402061786], "2017-11-22T07:30:00" - ) + response = self._api.next_departures_for_stations([402000656, 402000653, 402061786], "2017-11-22T07:30:00") self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @responses.activate def test_next_departures_for_stations_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -246,9 +226,7 @@ def test_next_departures_for_stations_whenerroroccurred(self): @responses.activate def test_calculate_route_whensucceed(self): - with io.open( - "testdata/models/public_transit_calculate_route.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_calculate_route.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -256,17 +234,13 @@ def test_calculate_route_whensucceed(self): expectedResponse, status=200, ) - response = self._api.calculate_route( - [41.9773, -87.9019], [41.8961, -87.6552], "2017-11-22T07:30:00" - ) + response = self._api.calculate_route([41.9773, -87.9019], [41.8961, -87.6552], "2017-11-22T07:30:00") self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @responses.activate def test_calculate_route_include_modes(self): - with io.open( - "testdata/models/public_transit_calculate_route.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_calculate_route.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -289,9 +263,7 @@ def test_calculate_route_include_modes(self): @responses.activate def test_calculate_route_exclude_modes(self): - with io.open( - "testdata/models/public_transit_calculate_route.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_calculate_route.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -314,9 +286,8 @@ def test_calculate_route_exclude_modes(self): @responses.activate def test_calculate_route_short_route(self): - with io.open( + with open( "testdata/models/public_transit_api_calculate_route_many_transfers.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -327,12 +298,9 @@ def test_calculate_route_short_route(self): status=200, ) expected_short_route = ( - "RE 29511 - Frankfurt(Main)Hbf; ICE 76 - Hamburg-Altona; " - "ICE 849 - Berlin Gesundbrunnen; S5 - Strausberg Nord" - ) - response = self._api.calculate_route( - [41.9773, -87.9019], [41.8961, -87.6552], "2017-11-22T07:30:00" + "RE 29511 - Frankfurt(Main)Hbf; ICE 76 - Hamburg-Altona; ICE 849 - Berlin Gesundbrunnen; S5 - Strausberg Nord" ) + response = self._api.calculate_route([41.9773, -87.9019], [41.8961, -87.6552], "2017-11-22T07:30:00") short_route = response.Res["Connections"]["Connection"][0]["short_route"] self.assertTrue(response) self.assertIsInstance(response, herepy.PublicTransitResponse) @@ -340,7 +308,7 @@ def test_calculate_route_short_route(self): @responses.activate def test_calculate_route_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -349,15 +317,11 @@ def test_calculate_route_whenerroroccurred(self): status=200, ) with self.assertRaises(herepy.HEREError): - self._api.calculate_route( - [-9999, -9999], [-9999, -9999], "2017-11-22T07:30:00" - ) + self._api.calculate_route([-9999, -9999], [-9999, -9999], "2017-11-22T07:30:00") @responses.activate def test_coverage_witin_a_city_whensucceed(self): - with io.open( - "testdata/models/public_transit_city_coverage.json", "r", encoding="utf-8" - ) as f: + with open("testdata/models/public_transit_city_coverage.json", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -371,7 +335,7 @@ def test_coverage_witin_a_city_whensucceed(self): @responses.activate def test_coverage_witin_a_city_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -384,9 +348,8 @@ def test_coverage_witin_a_city_whenerroroccurred(self): @responses.activate def test_coverage_nearby_whensucceed(self): - with io.open( + with open( "testdata/models/public_transit_api_nearby_coverage.json", - "r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -402,7 +365,7 @@ def test_coverage_nearby_whensucceed(self): @responses.activate def test_coverage_nearby_whenerroroccurred(self): - with open("testdata/models/public_transit_api_error.json", "r") as f: + with open("testdata/models/public_transit_api_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_rme_api.py b/tests/test_rme_api.py index 0f440b1..2c3cfcf 100644 --- a/tests/test_rme_api.py +++ b/tests/test_rme_api.py @@ -1,9 +1,5 @@ #!/usr/bin/env python -import io -import json -import os -import time import unittest import responses @@ -19,13 +15,11 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, herepy.RmeApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://m.fleet.ls.hereapi.com/2/matchroute.json" - ) + self.assertEqual(self._api._base_url, "https://m.fleet.ls.hereapi.com/2/matchroute.json") @responses.activate def test_match_route_whensucceed(self): - with io.open("testdata/models/rme_match_route_api.json", "r") as f: + with open("testdata/models/rme_match_route_api.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -33,7 +27,7 @@ def test_match_route_whensucceed(self): expectedResponse, status=200, ) - with io.open("testdata/routes/sample.gpx", encoding="utf-8") as gpx_file: + with open("testdata/routes/sample.gpx", encoding="utf-8") as gpx_file: gpx_content = gpx_file.read() response = self._api.match_route(gpx_content, ["ADAS_ATTRIB_FCn(SLOPES)"]) self.assertTrue(response) @@ -41,7 +35,7 @@ def test_match_route_whensucceed(self): @responses.activate def test_match_route_whenerroroccurred(self): - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_routing_api.py b/tests/test_routing_api.py index 204a723..d9e485f 100644 --- a/tests/test_routing_api.py +++ b/tests/test_routing_api.py @@ -3,13 +3,20 @@ import codecs import datetime import unittest -import pytest +import pytest import responses import herepy -from herepy import (Avoid, AvoidArea, AvoidFeature, ShippedHazardousGood, - Truck, TruckType, TunnelCategory) +from herepy import ( + Avoid, + AvoidArea, + AvoidFeature, + ShippedHazardousGood, + Truck, + TruckType, + TunnelCategory, +) class RoutingApiTest(unittest.TestCase): @@ -23,9 +30,7 @@ def test_initiation(self): @responses.activate def test_bicycleroute_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing_bicycle.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_bicycle.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -39,9 +44,7 @@ def test_bicycleroute_withdefaultmodes_whensucceed(self): @responses.activate def test_bicycleroute_route_short(self): - with codecs.open( - "testdata/models/routing_bicycle.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_bicycle.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -59,9 +62,7 @@ def test_bicycleroute_route_short(self): @responses.activate def test_carroute_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -69,17 +70,13 @@ def test_carroute_whensucceed(self): expectedResponse, status=200, ) - response = self._api.car_route( - [11.0, 12.0], [22.0, 23.0], [herepy.RouteMode.car, herepy.RouteMode.fastest] - ) + response = self._api.car_route([11.0, 12.0], [22.0, 23.0], [herepy.RouteMode.car, herepy.RouteMode.fastest]) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_carroute_route_short(self): - with codecs.open( - "testdata/models/routing_car_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_car_route_short.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -88,17 +85,12 @@ def test_carroute_route_short(self): status=200, ) response = self._api.car_route([38.9, -77.04833], [39.0, -77.1]) - expected_short_route = ( - "US-29 - K St NW; US-29 - Whitehurst Fwy; " - "I-495 N - Capital Beltway; MD-187 S - Old Georgetown Rd" - ) + expected_short_route = "US-29 - K St NW; US-29 - Whitehurst Fwy; I-495 N - Capital Beltway; MD-187 S - Old Georgetown Rd" self.assertEqual(response.route_short, expected_short_route) @responses.activate def test_carroute_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -112,7 +104,7 @@ def test_carroute_withdefaultmodes_whensucceed(self): @responses.activate def test_carroute_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -129,7 +121,7 @@ def test_carroute_when_error_invalid_input_data_occurred(self): @responses.activate def test_carroute_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -143,7 +135,7 @@ def test_carroute_when_error_invalid_credentials_occurred(self): @responses.activate def test_carroute_when_error_forbidden_credentials_occurred(self): - with open("testdata/models/routing_error_forbidden_credentials.json", "r") as f: + with open("testdata/models/routing_error_forbidden_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -157,7 +149,7 @@ def test_carroute_when_error_forbidden_credentials_occurred(self): @responses.activate def test_carroute_when_error_no_route_found_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -170,9 +162,7 @@ def test_carroute_when_error_no_route_found_occurred(self): @responses.activate def test_pedestrianroute_whensucceed(self): - with codecs.open( - "testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -190,9 +180,7 @@ def test_pedestrianroute_whensucceed(self): @responses.activate def test_pedestrianroute_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -206,7 +194,7 @@ def test_pedestrianroute_withdefaultmodes_whensucceed(self): @responses.activate def test_pedestrianroute_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -223,7 +211,7 @@ def test_pedestrianroute_when_error_invalid_input_data_occurred(self): @responses.activate def test_pedestrianroute_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -237,7 +225,7 @@ def test_pedestrianroute_when_error_invalid_credentials_occurred(self): @responses.activate def test_pedestrianroute_when_error_no_route_found_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -250,9 +238,7 @@ def test_pedestrianroute_when_error_no_route_found_occurred(self): @responses.activate def test_pedestrianroute_route_short(self): - with codecs.open( - "testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_pedestrian.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -274,9 +260,7 @@ def test_pedestrianroute_route_short(self): @responses.activate def test_intermediateroute_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -295,9 +279,7 @@ def test_intermediateroute_whensucceed(self): @responses.activate def test_intermediateroute_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -305,15 +287,13 @@ def test_intermediateroute_withdefaultmodes_whensucceed(self): expectedResponse, status=200, ) - response = self._api.intermediate_route( - [11.0, 12.0], [15.0, 16.0], [22.0, 23.0] - ) + response = self._api.intermediate_route([11.0, 12.0], [15.0, 16.0], [22.0, 23.0]) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_intermediateroute_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -331,7 +311,7 @@ def test_intermediateroute_when_error_invalid_input_data_occurred(self): @responses.activate def test_intermediateroute_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -345,7 +325,7 @@ def test_intermediateroute_when_error_invalid_credentials_occurred(self): @responses.activate def test_intermediateroute_when_error_no_route_found_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -354,15 +334,11 @@ def test_intermediateroute_when_error_no_route_found_occurred(self): status=400, ) with self.assertRaises(herepy.NoRouteFoundError): - self._api.intermediate_route( - [11.0, 12.0], [47.013399, -10.171986], [22.0, 23.0] - ) + self._api.intermediate_route([11.0, 12.0], [47.013399, -10.171986], [22.0, 23.0]) @responses.activate def test_publictransport_whensucceed(self): - with codecs.open( - "testdata/models/routing_public.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -381,9 +357,7 @@ def test_publictransport_whensucceed(self): @responses.activate def test_publictransport_route_short(self): - with codecs.open( - "testdata/models/routing_public.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -392,17 +366,12 @@ def test_publictransport_route_short(self): status=200, ) response = self._api.public_transport([11.0, 12.0], [15.0, 16.0], True) - expected_short_route = ( - "332 - Palmer/Schiller; 332 - Cargo Rd./Delta Cargo; " - "332 - Palmer/Schiller" - ) + expected_short_route = "332 - Palmer/Schiller; 332 - Cargo Rd./Delta Cargo; 332 - Palmer/Schiller" self.assertEqual(response.route_short, expected_short_route) @responses.activate def test_publictransport_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing_public.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -416,7 +385,7 @@ def test_publictransport_withdefaultmodes_whensucceed(self): @responses.activate def test_publictransport_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -434,7 +403,7 @@ def test_publictransport_when_error_invalid_input_data_occurred(self): @responses.activate def test_publictransport_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -448,7 +417,7 @@ def test_publictransport_when_error_invalid_credentials_occurred(self): @responses.activate def test_publictransport_when_error_no_route_found_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -461,9 +430,7 @@ def test_publictransport_when_error_no_route_found_occurred(self): @responses.activate def test_publictransporttimetable_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -471,17 +438,13 @@ def test_publictransporttimetable_withdefaultmodes_whensucceed(self): expectedResponse, status=200, ) - response = self._api.public_transport_timetable( - [11.0, 12.0], [15.0, 16.0], True - ) + response = self._api.public_transport_timetable([11.0, 12.0], [15.0, 16.0], True) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_publictransporttimetable_route_short(self): - with codecs.open( - "testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -489,19 +452,13 @@ def test_publictransporttimetable_route_short(self): expectedResponse, status=200, ) - response = self._api.public_transport_timetable( - [11.0, 12.0], [15.0, 16.0], True - ) - expected_short_route = ( - "330 - Archer/Harlem (Terminal); 309 - Elmhurst Metra Station" - ) + response = self._api.public_transport_timetable([11.0, 12.0], [15.0, 16.0], True) + expected_short_route = "330 - Archer/Harlem (Terminal); 309 - Elmhurst Metra Station" self.assertEqual(response.route_short, expected_short_route) @responses.activate def test_locationnearmotorway_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -509,17 +466,13 @@ def test_locationnearmotorway_whensucceed(self): expectedResponse, status=200, ) - response = self._api.location_near_motorway( - [11.0, 12.0], [22.0, 23.0], [herepy.RouteMode.car, herepy.RouteMode.fastest] - ) + response = self._api.location_near_motorway([11.0, 12.0], [22.0, 23.0], [herepy.RouteMode.car, herepy.RouteMode.fastest]) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_locationnearmotorway_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -533,7 +486,7 @@ def test_locationnearmotorway_withdefaultmodes_whensucceed(self): @responses.activate def test_locationnearmotorway_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -550,7 +503,7 @@ def test_locationnearmotorway_when_error_invalid_input_data_occurred(self): @responses.activate def test_locationnearmotorway_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -564,7 +517,7 @@ def test_locationnearmotorway_when_error_invalid_credentials_occurred(self): @responses.activate def test_locationnearmotorway_when_error_no_route_found_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -577,9 +530,7 @@ def test_locationnearmotorway_when_error_no_route_found_occurred(self): @responses.activate def test_truckroute_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -597,9 +548,7 @@ def test_truckroute_whensucceed(self): @responses.activate def test_truckroute_route_short(self): - with codecs.open( - "testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -609,16 +558,13 @@ def test_truckroute_route_short(self): ) response = self._api.truck_route([11.0, 12.0], [22.0, 23.0]) expected_short_route = ( - "I-190; I-294 S - Tri-State Tollway; I-290 W - Eisenhower Expy W; " - "IL-64 W - E North Ave; I-290 E - Eisenhower Expy E; I-290" + "I-190; I-294 S - Tri-State Tollway; I-290 W - Eisenhower Expy W; IL-64 W - E North Ave; I-290 E - Eisenhower Expy E; I-290" ) self.assertEqual(response.route_short, expected_short_route) @responses.activate def test_truckroute_withdefaultmodes_whensucceed(self): - with codecs.open( - "testdata/models/routing.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -632,7 +578,7 @@ def test_truckroute_withdefaultmodes_whensucceed(self): @responses.activate def test_truckroute_when_error_invalid_input_data_occurred(self): - with open("testdata/models/routing_error_invalid_input_data.json", "r") as f: + with open("testdata/models/routing_error_invalid_input_data.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -649,7 +595,7 @@ def test_truckroute_when_error_invalid_input_data_occurred(self): @responses.activate def test_truckroute_when_error_invalid_credentials_occurred(self): - with open("testdata/models/routing_error_invalid_credentials.json", "r") as f: + with open("testdata/models/routing_error_invalid_credentials.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -663,7 +609,7 @@ def test_truckroute_when_error_invalid_credentials_occurred(self): @responses.activate def test_truckroute_when_error_no_route_found_no_endpoint_occurred(self): - with open("testdata/models/routing_error_no_route_found.json", "r") as f: + with open("testdata/models/routing_error_no_route_found.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -676,7 +622,7 @@ def test_truckroute_when_error_no_route_found_no_endpoint_occurred(self): @responses.activate def test_truckroute_when_error_no_route_found_graph_disconnect_occurred(self): - with open("testdata/models/routing_error_no_route_found_truck.json", "r") as f: + with open("testdata/models/routing_error_no_route_found_truck.json") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -689,9 +635,7 @@ def test_truckroute_when_error_no_route_found_graph_disconnect_occurred(self): @responses.activate def test_sync_matrix_whensucceed(self): - with codecs.open( - "testdata/models/routing_matrix.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_matrix.json", mode="r", encoding="utf-8") as f: server_response = f.read() responses.add( responses.POST, @@ -768,7 +712,7 @@ def test_sync_matrix_multiple_start_names(self): server_response, status=200, ) - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedGeocoderResponse = f.read() responses.add( responses.GET, @@ -824,7 +768,7 @@ def test_sync_matrix_multiple_destinations(self): server_response, status=200, ) - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedGeocoderResponse = f.read() responses.add( responses.GET, @@ -870,7 +814,6 @@ def test_sync_matrix_bad_request(self): def test_async_matrix_whensucceed(self): with open( "testdata/models/routing_async_matrix_calculation.json", - mode="r", encoding="utf-8", ) as f: server_response = f.read() @@ -882,7 +825,6 @@ def test_async_matrix_whensucceed(self): ) with open( "testdata/models/routing_async_matrix_completed.json", - mode="r", encoding="utf-8", ) as f: server_response = f.read() @@ -926,9 +868,7 @@ def test_async_matrix_whensucceed(self): @responses.activate def test_departure_as_datetime(self): - with codecs.open( - "testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -936,18 +876,14 @@ def test_departure_as_datetime(self): expectedResponse, status=200, ) - date = datetime.datetime( - 2013, 7, 4, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)) - ) + date = datetime.datetime(2013, 7, 4, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 7200))) response = self._api.truck_route([11.0, 12.0], [22.0, 23.0], departure=date) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_departure_as_string(self): - with codecs.open( - "testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -962,9 +898,7 @@ def test_departure_as_string(self): @responses.activate def test_arrival_as_string(self): - with codecs.open( - "testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -973,17 +907,13 @@ def test_arrival_as_string(self): status=200, ) date = "2013-07-04T17:00:00+02:00" - response = self._api.public_transport_timetable( - [11.0, 12.0], [15.0, 16.0], True, arrival=date - ) + response = self._api.public_transport_timetable([11.0, 12.0], [15.0, 16.0], True, arrival=date) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_arrival_as_datetime(self): - with codecs.open( - "testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -991,20 +921,14 @@ def test_arrival_as_datetime(self): expectedResponse, status=200, ) - date = datetime.datetime( - 2013, 7, 4, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)) - ) - response = self._api.public_transport_timetable( - [11.0, 12.0], [15.0, 16.0], True, arrival=date - ) + date = datetime.datetime(2013, 7, 4, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(0, 7200))) + response = self._api.public_transport_timetable([11.0, 12.0], [15.0, 16.0], True, arrival=date) self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_error_arrival_and_departure_set(self): - with codecs.open( - "testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_public_time_table.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -1023,9 +947,7 @@ def test_error_arrival_and_departure_set(self): @responses.activate def test_location_by_name(self): - with codecs.open( - "testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8") as f: expectedRoutingResponse = f.read() responses.add( responses.GET, @@ -1033,7 +955,7 @@ def test_location_by_name(self): expectedRoutingResponse, status=200, ) - with open("testdata/models/geocoder.json", "r") as f: + with open("testdata/models/geocoder.json") as f: expectedGeocoderResponse = f.read() responses.add( responses.GET, @@ -1041,17 +963,13 @@ def test_location_by_name(self): expectedGeocoderResponse, status=200, ) - response = self._api.truck_route( - "200 S Mathilda Sunnyvale CA", "200 S Mathilda Sunnyvale CA" - ) + response = self._api.truck_route("200 S Mathilda Sunnyvale CA", "200 S Mathilda Sunnyvale CA") self.assertTrue(response) self.assertIsInstance(response, herepy.RoutingResponse) @responses.activate def test_location_by_name_throws_WaypointNotFoundError(self): - with codecs.open( - "testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_truck_route_short.json", mode="r", encoding="utf-8") as f: expectedRoutingResponse = f.read() responses.add( responses.GET, @@ -1059,7 +977,7 @@ def test_location_by_name_throws_WaypointNotFoundError(self): expectedRoutingResponse, status=200, ) - with open("testdata/models/geocoder_error.json", "r") as f: + with open("testdata/models/geocoder_error.json") as f: expectedGeocoderResponse = f.read() responses.add( responses.GET, @@ -1068,15 +986,11 @@ def test_location_by_name_throws_WaypointNotFoundError(self): status=200, ) with self.assertRaises(herepy.WaypointNotFoundError): - response = self._api.truck_route( - "200 S Mathilda Sunnyvale CA", "200 S Mathilda Sunnyvale CA" - ) + response = self._api.truck_route("200 S Mathilda Sunnyvale CA", "200 S Mathilda Sunnyvale CA") @responses.activate def test_route_v8_success(self): - with codecs.open( - "testdata/models/routing_v8_response.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/routing_v8_response.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -1106,7 +1020,6 @@ def test_route_v8_success(self): def test_route_v8_error_invalid_credentials(self): with open( "testdata/models/routing_error_invalid_credentials.json", - mode="r", encoding="utf-8", ) as f: expectedResponse = f.read() @@ -1136,9 +1049,7 @@ def test_route_v8_error_invalid_credentials(self): @responses.activate def test_route_v8_error_malformed_request(self): - """ - Usually this error occurs - """ + """Usually this error occurs""" with codecs.open( "testdata/models/routing_v8_error_malformed_req.json", mode="r", @@ -1202,11 +1113,7 @@ def test_route_v8_multiple_via_points(self): "https://router.hereapi.com/v8/routes", "{}", status=200, - match=[ - responses.matchers.query_param_matcher( - {"via": ["41.9339,-87.9021"] * 11}, strict_match=False - ) - ], + match=[responses.matchers.query_param_matcher({"via": ["41.9339,-87.9021"] * 11}, strict_match=False)], ) response = self._api.route_v8( transport_mode=herepy.RoutingTransportMode.car, @@ -1226,14 +1133,16 @@ def test_route_v8_url_parameters_multiple(self): status=200, match=[ responses.matchers.query_param_matcher( - {"vehicle[height]": "15000", "vehicle[width]": "3000"}, strict_match=False + {"vehicle[height]": "15000", "vehicle[width]": "3000"}, + strict_match=False, ) ], ) - self._api.route_v8(transport_mode=herepy.RoutingTransportMode.truck, + self._api.route_v8( + transport_mode=herepy.RoutingTransportMode.truck, origin=[41.9798, -87.8801], destination=[41.9043, -87.9216], - vehicle={"height": ["15000"], "width": ["3000"]} + vehicle={"height": ["15000"], "width": ["3000"]}, ) @responses.activate diff --git a/tests/test_traffic_api.py b/tests/test_traffic_api.py index a30208e..a7d7a5f 100644 --- a/tests/test_traffic_api.py +++ b/tests/test_traffic_api.py @@ -1,9 +1,6 @@ #!/usr/bin/env python import codecs -import datetime -import os -import sys import unittest import responses @@ -49,9 +46,7 @@ def test_incidents_in_bounding_box_success(self): @responses.activate def test_incidents_in_bounding_box_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -90,9 +85,7 @@ def test_incidents_in_corridor_success(self): @responses.activate def test_incidents_in_corridor_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -101,9 +94,7 @@ def test_incidents_in_corridor_fails(self): status=200, ) with self.assertRaises(herepy.UnauthorizedError): - self._api.incidents_in_corridor( - points=[[51.5072, -0.1275], [51.50781, -0.13112]], width=1000 - ) + self._api.incidents_in_corridor(points=[[51.5072, -0.1275], [51.50781, -0.13112]], width=1000) @responses.activate def test_incidents_via_proximity_success(self): @@ -134,9 +125,7 @@ def test_incidents_via_proximity_success(self): @responses.activate def test_incidents_via_proximity_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -176,9 +165,7 @@ def test_flow_using_quadkey_success(self): @responses.activate def test_flow_using_quadkey_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -203,18 +190,14 @@ def test_flow_within_boundingbox_success(self): expectedResponse, status=200, ) - response = self._api.flow_within_boundingbox( - top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035] - ) + response = self._api.flow_within_boundingbox(top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035]) self.assertTrue(response) self.assertIsInstance(response, herepy.TrafficFlowResponse) self.assertIsNotNone(response.as_dict()) @responses.activate def test_flow_within_boundingbox_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -223,9 +206,7 @@ def test_flow_within_boundingbox_fails(self): status=200, ) with self.assertRaises(herepy.UnauthorizedError): - self._api.flow_within_boundingbox( - top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035] - ) + self._api.flow_within_boundingbox(top_left=[52.5311, 13.3644], bottom_right=[52.5114, 13.4035]) @responses.activate def test_flow_using_proximity_success(self): @@ -241,18 +222,14 @@ def test_flow_using_proximity_success(self): expectedResponse, status=200, ) - response = self._api.flow_using_proximity( - latitude=51.5072, longitude=-0.1275, distance=100 - ) + response = self._api.flow_using_proximity(latitude=51.5072, longitude=-0.1275, distance=100) self.assertTrue(response) self.assertIsInstance(response, herepy.TrafficFlowResponse) self.assertIsNotNone(response.as_dict()) @responses.activate def test_flow_using_proximity_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -261,9 +238,7 @@ def test_flow_using_proximity_fails(self): status=200, ) with self.assertRaises(herepy.UnauthorizedError): - self._api.flow_using_proximity( - latitude=51.5072, longitude=-0.1275, distance=100 - ) + self._api.flow_using_proximity(latitude=51.5072, longitude=-0.1275, distance=100) @responses.activate def test_flow_using_proximity_returning_additional_attributes_success(self): @@ -294,9 +269,7 @@ def test_flow_using_proximity_returning_additional_attributes_success(self): @responses.activate def test_flow_using_proximity_returning_additional_attributes_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -340,9 +313,7 @@ def test_flow_with_minimum_jam_factor_success(self): @responses.activate def test_flow_with_minimum_jam_factor_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -381,9 +352,7 @@ def test_flow_in_corridor_success(self): @responses.activate def test_flow_in_corridor_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -392,9 +361,7 @@ def test_flow_in_corridor_fails(self): status=200, ) with self.assertRaises(herepy.UnauthorizedError): - self._api.flow_in_corridor( - points=[[51.5072, -0.1275], [51.50781, -0.13112]], width=1000 - ) + self._api.flow_in_corridor(points=[[51.5072, -0.1275], [51.50781, -0.13112]], width=1000) @responses.activate def test_flow_availability_data_success(self): @@ -417,9 +384,7 @@ def test_flow_availability_data_success(self): @responses.activate def test_flow_availability_data_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, @@ -454,9 +419,7 @@ def test_additional_attributes_success(self): @responses.activate def test_additional_attributes_fails(self): - with codecs.open( - "testdata/models/unauthorized_error.json", mode="r", encoding="utf-8" - ) as f: + with codecs.open("testdata/models/unauthorized_error.json", mode="r", encoding="utf-8") as f: expectedResponse = f.read() responses.add( responses.GET, diff --git a/tests/test_utils.py b/tests/test_utils.py index 8afc183..2e77607 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,9 +1,7 @@ #!/usr/bin/env python -import os import unittest -import herepy from herepy.utils import Utils @@ -25,9 +23,7 @@ def test_buildurl(self): "app_id": "app_id", "app_code": "app_code", } - url = Utils.build_url( - "https://geocoder.cit.api.here.com/6.2/geocode.json", data - ) + url = Utils.build_url("https://geocoder.cit.api.here.com/6.2/geocode.json", data) self.assertTrue(url) def test_build_url_sub_data(self): @@ -36,4 +32,7 @@ def test_build_url_sub_data(self): "key2": {"sub_key": "sub_val", "sub_key2": "sub_val2"}, } url = Utils.build_url("https://router.hereapi.com/v8/routes", data) - self.assertEqual(url, "https://router.hereapi.com/v8/routes?key1=val&key2%5Bsub_key%5D=sub_val&key2%5Bsub_key2%5D=sub_val2") + self.assertEqual( + url, + "https://router.hereapi.com/v8/routes?key1=val&key2%5Bsub_key%5D=sub_val&key2%5Bsub_key2%5D=sub_val2", + ) diff --git a/tests/test_vector_tile_api.py b/tests/test_vector_tile_api.py index c3e7082..7f1600d 100644 --- a/tests/test_vector_tile_api.py +++ b/tests/test_vector_tile_api.py @@ -1,15 +1,9 @@ #!/usr/bin/env python -import codecs -import io -import json -import os -import sys import unittest from unittest.mock import Mock, patch -from herepy import (HEREError, UnauthorizedError, VectorMapTileLayer, - VectorTileApi) +from herepy import HEREError, UnauthorizedError, VectorMapTileLayer, VectorTileApi class VectorTileApiTest(unittest.TestCase): @@ -20,27 +14,21 @@ def setUp(self): def test_initiation(self): self.assertIsInstance(self._api, VectorTileApi) self.assertEqual(self._api._api_key, "api_key") - self.assertEqual( - self._api._base_url, "https://vector.hereapi.com/v2/vectortiles/" - ) + self.assertEqual(self._api._base_url, "https://vector.hereapi.com/v2/vectortiles/") @patch("herepy.vector_tile_api.requests.get") def test_get_vector_tile_succeed(self, mock_get): with open("testdata/tiles/omv", "rb") as tile: mock_get.return_value = Mock(ok=True) mock_get.return_value.content = tile.read - vector_tile = self._api.get_vectortile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + vector_tile = self._api.get_vectortile(latitude=52.525439, longitude=13.38727, zoom=12) self.assertIsNotNone(vector_tile) @patch("herepy.vector_tile_api.requests.get") def test_get_vector_tile_fails(self, mock_get): mock_get.return_value = Mock(ok=True) mock_get.return_value.content = None - vector_tile = self._api.get_vectortile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + vector_tile = self._api.get_vectortile(latitude=52.525439, longitude=13.38727, zoom=12) self.assertIsNone(vector_tile) @patch("herepy.vector_tile_api.requests.get") @@ -49,9 +37,7 @@ def test_get_vector_tile_when_receives_unauthorized_error(self, mock_get): mock_get.return_value = Mock(ok=True) mock_get.return_value.content = f.read() with self.assertRaises(UnauthorizedError) as cm: - vector_tile = self._api.get_vectortile( - latitude=52.525439, longitude=13.38727, zoom=12 - ) + vector_tile = self._api.get_vectortile(latitude=52.525439, longitude=13.38727, zoom=12) self.assertEqual("apiKey invalid. apiKey not found.", str(cm.exception)) @patch("herepy.vector_tile_api.requests.get") diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..db4ebfc --- /dev/null +++ b/uv.lock @@ -0,0 +1,1620 @@ +version = 1 +revision = 3 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.15'", + "python_full_version < '3.15'", +] + +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + +[[package]] +name = "ast-serialize" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/81/9d/09e27731bd5864a9ce04e3244074e674bb8936bf62b45e0357248717adac/ast_serialize-0.5.0.tar.gz", hash = "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6", size = 61157, upload-time = "2026-05-17T17:48:29.429Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/9a/13dde51ba9e15f8b97957ab7cb0120d0e381524d651c6bd630b9c359227f/ast_serialize-0.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a", size = 1183520, upload-time = "2026-05-17T17:47:30.831Z" }, + { url = "https://files.pythonhosted.org/packages/37/de/5a7f0a9fe68944f536632a5af84676739c7d2582be42deb082634bf3a754/ast_serialize-0.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b", size = 1175779, upload-time = "2026-05-17T17:47:32.551Z" }, + { url = "https://files.pythonhosted.org/packages/9c/81/0bb853e76e4f6e9a1855d569003c59e19ffac45f7079d91505d1bb212f92/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1", size = 1233750, upload-time = "2026-05-17T17:47:34.731Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d3/4cf705beeccc08754d0bbda99aefff26110e209b9a07ac8a6b60eec48531/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6", size = 1235942, upload-time = "2026-05-17T17:47:36.287Z" }, + { url = "https://files.pythonhosted.org/packages/26/c8/ee097e437ea27dd2b8b227865c875492b585650a5802a22d82b304c8201b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2", size = 1442517, upload-time = "2026-05-17T17:47:38.17Z" }, + { url = "https://files.pythonhosted.org/packages/ff/bd/68063442838f1ba68ec72b5436430bc75b3bb17a1a3c3063f09b0c05ae2b/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903", size = 1254081, upload-time = "2026-05-17T17:47:39.826Z" }, + { url = "https://files.pythonhosted.org/packages/50/e2/1e520793bc6a4e4524a6ab022391e827825eaa0c3811828bfdc6852eca26/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261", size = 1259910, upload-time = "2026-05-17T17:47:41.369Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e1/49b60f467979979cfe6913b43948ff25bca971ad0591d181812f163a988e/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027", size = 1250678, upload-time = "2026-05-17T17:47:43.702Z" }, + { url = "https://files.pythonhosted.org/packages/74/ba/66ab9555de6275677566f6574e5ef6c29cb185ea866f643bc06f8280a8ee/ast_serialize-0.5.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937", size = 1301603, upload-time = "2026-05-17T17:47:46.256Z" }, + { url = "https://files.pythonhosted.org/packages/66/42/6aca9b9abc710014b2be9059689e5dd1679339e78f567ffb4d255a9e2050/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c", size = 1410332, upload-time = "2026-05-17T17:47:47.899Z" }, + { url = "https://files.pythonhosted.org/packages/47/68/2f76594432a22581ecf878b5e75a9b8601c24b2241cf0bbeb1e21fcf370c/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b", size = 1509979, upload-time = "2026-05-17T17:47:50.942Z" }, + { url = "https://files.pythonhosted.org/packages/40/ac/a93c9b58292653f6c595752f677a08e608f903b710594909e9231a389b3b/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab", size = 1505002, upload-time = "2026-05-17T17:47:54.093Z" }, + { url = "https://files.pythonhosted.org/packages/14/2e/b278f68c497ee2f1d1576cbbef8db5281cd4a5f2db040537592ac9c8862e/ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3", size = 1456231, upload-time = "2026-05-17T17:47:56.311Z" }, + { url = "https://files.pythonhosted.org/packages/0b/43/419be1c566a4c504cd8fd60ce2f84e790f295495c0f327cfaeadf3d51012/ast_serialize-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38", size = 1058668, upload-time = "2026-05-17T17:47:58.305Z" }, + { url = "https://files.pythonhosted.org/packages/03/6f/c9d4d549295ed05111aeb8853232d1afd9d0a179fddb01eeffbb3a4a6842/ast_serialize-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c", size = 1101075, upload-time = "2026-05-17T17:48:00.35Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8e/d00c5ab30c58222e07d62956fca86c59d91b9ad32997e633c38b526623a3/ast_serialize-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb", size = 1075347, upload-time = "2026-05-17T17:48:01.753Z" }, + { url = "https://files.pythonhosted.org/packages/e0/9e/dc2530acb3a60dc6e46d65abf27d1d9f86721694757906a148d90a6860de/ast_serialize-0.5.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101", size = 1191380, upload-time = "2026-05-17T17:48:03.738Z" }, + { url = "https://files.pythonhosted.org/packages/26/0a/bd3d18a582f273d6c843d16bb9e22e9e16365ff7991e92f18f798e9f1224/ast_serialize-0.5.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a", size = 1183879, upload-time = "2026-05-17T17:48:05.463Z" }, + { url = "https://files.pythonhosted.org/packages/40/ae/1f919100f8620887af58fcc381c61a1f218cdf89c6e155f87b213e61010a/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211", size = 1244529, upload-time = "2026-05-17T17:48:07.008Z" }, + { url = "https://files.pythonhosted.org/packages/c6/ca/6376559dcce707cdbc1d0d9a13c8d3baaaa501e949ce0ebdc4230cd881aa/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf", size = 1240560, upload-time = "2026-05-17T17:48:08.46Z" }, + { url = "https://files.pythonhosted.org/packages/35/b2/a620e206b5aeb7efbf2710336df57d457cffbb3991076bbcc1147ef9abd4/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9", size = 1451172, upload-time = "2026-05-17T17:48:09.922Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e0/4ad5c04c24a40481b2935ce9a0ccdb6023dc8b667167d06ae530cc3512f2/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee", size = 1265072, upload-time = "2026-05-17T17:48:11.469Z" }, + { url = "https://files.pythonhosted.org/packages/b2/71/4d1d479aa56d0101c40e17720c3d6ac2af7269ea0487a80b18e7bfd1a5b7/ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809", size = 1270488, upload-time = "2026-05-17T17:48:13.575Z" }, + { url = "https://files.pythonhosted.org/packages/6d/4f/0de1bbe06f6edef9fde4ed12ca8e7b3ec7e6e2bd4e672c5af487f7957665/ast_serialize-0.5.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43", size = 1260702, upload-time = "2026-05-17T17:48:15.141Z" }, + { url = "https://files.pythonhosted.org/packages/75/61/e00872439cfdddcc3c1b6cdaa6e5d904ba8e26a18807c67c4e14409d0ca8/ast_serialize-0.5.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934", size = 1311182, upload-time = "2026-05-17T17:48:16.779Z" }, + { url = "https://files.pythonhosted.org/packages/76/8e/699a5b955f7926956c95e9e1d74132acad73c2fe7a426f94da89123c20aa/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759", size = 1421410, upload-time = "2026-05-17T17:48:18.527Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ae/d5b7626874478997adc7a29ab28accf21e596fb590c944290401dfd0b29e/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887", size = 1516587, upload-time = "2026-05-17T17:48:20.133Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ce/b59e02a82d9c4244d64cde502e0b00e83e38816abe19155ceb5437402c7f/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27", size = 1515171, upload-time = "2026-05-17T17:48:21.921Z" }, + { url = "https://files.pythonhosted.org/packages/8b/38/d8d90042747d05aa08d4efcf1c99035a5f670a6bf4c214d31644392afbca/ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d", size = 1464668, upload-time = "2026-05-17T17:48:23.544Z" }, + { url = "https://files.pythonhosted.org/packages/dd/51/5b840c4df7334104cecffa28f23904fe81ca89ca223d2450e288de39fd3c/ast_serialize-0.5.0-cp39-abi3-win32.whl", hash = "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a", size = 1068311, upload-time = "2026-05-17T17:48:25.027Z" }, + { url = "https://files.pythonhosted.org/packages/41/11/ca5672c7d491825bc4cd6702dea106a6b60d928707712ec257c7833ae476/ast_serialize-0.5.0-cp39-abi3-win_amd64.whl", hash = "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590", size = 1108931, upload-time = "2026-05-17T17:48:26.591Z" }, + { url = "https://files.pythonhosted.org/packages/45/19/cc8bd127d28a43da249aa955cfd164cf8fd534e79e42cea96c4854d72fd0/ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642", size = 1081181, upload-time = "2026-05-17T17:48:28.122Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "babel" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, +] + +[[package]] +name = "cachetools" +version = "7.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/8b/0d3945a13955303b81272f759a0331e54c5c793da455e6f5706b89d2639c/cachetools-7.1.4.tar.gz", hash = "sha256:437f55a4e0c1b01a4f3077cc470e6991d47430970e36fbcb77e2be0df4fc1cd6", size = 40085, upload-time = "2026-05-21T22:40:43.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/7b/1fc1c09cc0756cf25861a3be10565915953876da48bb228fb9a672b20a42/cachetools-7.1.4-py3-none-any.whl", hash = "sha256:323dc4127934744db5b54eb4924482d7edafbf9554e820d1531c2e08c0e4ef54", size = 16761, upload-time = "2026-05-21T22:40:41.845Z" }, +] + +[[package]] +name = "certifi" +version = "2026.5.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, +] + +[[package]] +name = "chardet" +version = "7.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/b6/9df434a8eeba2e6628c465a1dfa31034228ef79b26f76f46278f4ef7e49d/chardet-7.4.3.tar.gz", hash = "sha256:cc1d4eb92a4ec1c2df3b490836ffa46922e599d34ce0bb75cf41fd2bf6303d56", size = 784800, upload-time = "2026-04-13T21:33:39.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/1b/7f73766c119a1344eb69e31890ede7c5825ce03d69a9d29292d1bd1cfa1b/chardet-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0c79b13c9908ac7dfe0a74116ebc9a0f28b2319d23c32f3dfcdfbe1279c7eaf", size = 874121, upload-time = "2026-04-13T21:32:47.065Z" }, + { url = "https://files.pythonhosted.org/packages/8b/02/b677c8203d34dad6c2af48287bb1f8c5dff63db2094636fbe634b555b7fb/chardet-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bba8bea1b28d927b3e99e47deafe53658d34497c0a891d95ff1ba8ff6663f01c", size = 856900, upload-time = "2026-04-13T21:32:48.893Z" }, + { url = "https://files.pythonhosted.org/packages/c4/4b/1361a485a999d97cac4c895e615326f69a639532a52ef365a468bd09bad1/chardet-7.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23163921dccf3103ce59540b0443c106d2c0a0ff2e0503e05196f5e6fdea453f", size = 876634, upload-time = "2026-04-13T21:32:50.238Z" }, + { url = "https://files.pythonhosted.org/packages/87/23/e31c8ad33aa448f0845fd58af5fc22da1626407616d09df4973b2b34f477/chardet-7.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfb54563fe5f130da17c44c6a4e2e8052ba628e5ab4eab7ef8190f736f0f8f72", size = 886497, upload-time = "2026-04-13T21:32:52.111Z" }, + { url = "https://files.pythonhosted.org/packages/18/ef/ea4edec8c87f7e6eda02673acc68fe48725e564fc5a1865782efb53d5598/chardet-7.4.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3990fffcc6a6045f2234ab72752ad037e3b2d48c72037f244d42738db397eb75", size = 881061, upload-time = "2026-04-13T21:32:53.755Z" }, + { url = "https://files.pythonhosted.org/packages/f2/11/fc10600da98541777d720ad9e6bc040c0e0af1adb92e27142e35158957cb/chardet-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c7116b0452994734ccff35e154b44240090eb0f4f74b9106292668133557c175", size = 942533, upload-time = "2026-04-13T21:32:55.134Z" }, + { url = "https://files.pythonhosted.org/packages/19/52/505c207f334d51e937cbaa27ff95776e16e2d120e13cbe491cd7b3a70b50/chardet-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:25a862cddc6a9ac07023e808aedd297115345fbaabc2690479481ddc0f980e09", size = 870747, upload-time = "2026-04-13T21:32:56.916Z" }, + { url = "https://files.pythonhosted.org/packages/14/4b/d3c79495dee4831b8bebca2790e72cb90f0c5849c940570a7c7e5b70b952/chardet-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7005c88da26fd95d8abb8acbe6281d833e9a9181b03cf49b4546c4555389bd97", size = 853210, upload-time = "2026-04-13T21:32:58.309Z" }, + { url = "https://files.pythonhosted.org/packages/b9/99/f6a822ad1bde25a4c38dc3e770485e78e0893dfd871cd6e18ed3ea3a795e/chardet-7.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc50f28bad067393cce0af9091052c3b8df7a23115afd8ba7b2e0947f0cef1f8", size = 873625, upload-time = "2026-04-13T21:32:59.606Z" }, + { url = "https://files.pythonhosted.org/packages/b1/10/31932775c94a86814f76b41c4a772b52abfb0e6125324f32c6da1196c297/chardet-7.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3da294de1a681097848ab58bd3f2771a674f8039d2d87a5538b28856b815e9", size = 883436, upload-time = "2026-04-13T21:33:01.351Z" }, + { url = "https://files.pythonhosted.org/packages/6c/63/0f43e3acf2c436fdb32a0f904aeb03a2904d2126eed34a042a194d235926/chardet-7.4.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:93c45e116dd51b66226a53ade3f9f635e870de5399b90e00ce45dcc311093bf4", size = 876589, upload-time = "2026-04-13T21:33:02.636Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a6/e9b8f8a3e99602792b01fa7d0a731737615ab56d8bfd0b52935a0ef88b85/chardet-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:ccc1f83ab4bcfb901cf39e0c4ba6bc6e726fc6264735f10e24ceb5cb47387578", size = 941866, upload-time = "2026-04-13T21:33:04.282Z" }, + { url = "https://files.pythonhosted.org/packages/61/33/29de185079e6675c3f375546e30a559b7ddc75ce972f18d6e566cd9ea4eb/chardet-7.4.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:75d3c65cc16bddf40b8da1fd25ba84fca5f8070f2b14e86083653c1c85aee971", size = 874870, upload-time = "2026-04-13T21:33:05.977Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2f/4c5af01fd1a7506a1d5375403d68925eac70289229492db5aa68b58103d8/chardet-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:29af5999f654e8729d251f1724a62b538b1262d9292cccaefddf8a02aae1ef6a", size = 854859, upload-time = "2026-04-13T21:33:07.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/21/edb36ad5dfa48d7f8eed97ab43931ecdaa8c15166c21b1d614967e49d681/chardet-7.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:626f00299ad62dfe937058a09572beed442ccc7b58f87aa667949b20fd3db235", size = 875032, upload-time = "2026-04-13T21:33:08.741Z" }, + { url = "https://files.pythonhosted.org/packages/e5/59/a32a241d861cf180853a11c8e5a67641cb1b2af13c3a5ccce83ec07e2c9f/chardet-7.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9a4904dd5f071b7a7d7f50b4a67a86db3c902d243bf31708f1d5cde2f68239cb", size = 888283, upload-time = "2026-04-13T21:33:10.213Z" }, + { url = "https://files.pythonhosted.org/packages/87/2e/e1ee6a77abf3782c00e05b89c4d4328c8353bf9500661c4348df1dd68614/chardet-7.4.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5d2879598bc220689e8ce509fe9c3f37ad2fca53a36be9c9bd91abdd91dd364f", size = 879974, upload-time = "2026-04-13T21:33:11.448Z" }, + { url = "https://files.pythonhosted.org/packages/32/60/fca69c534602a7ced04280c952a246ad1edde2a6ca3a164f65d32ac41fe7/chardet-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:4b2799bd58e7245cfa8d4ab2e8ad1d76a5c3a5b1f32318eb6acca4c69a3e7101", size = 943973, upload-time = "2026-04-13T21:33:12.756Z" }, + { url = "https://files.pythonhosted.org/packages/7c/43/79ac9b4db5bc87020c9dbc419125371d80882d1d197e9c4765ba8682b605/chardet-7.4.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a9e4486df251b8962e86ea9f139ca235aa6e0542a00f7844c9a04160afb99aa9", size = 873769, upload-time = "2026-04-13T21:33:14.002Z" }, + { url = "https://files.pythonhosted.org/packages/55/5f/25bdec773905bff0ff6cf35ca73b17bd05593b4f87bd8c5fa43705f7167d/chardet-7.4.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4fbff1907925b0c5a1064cffb5e040cd5e338585c9c552625f30de6bc2f3107a", size = 853991, upload-time = "2026-04-13T21:33:15.564Z" }, + { url = "https://files.pythonhosted.org/packages/b4/07/a29380ee0b215d23d77733b5ad60c5c0c7969650e080c667acdf9462040d/chardet-7.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:365135eaf37ba65a828f8e668eb0a8c38c479dcbec724dc25f4dfd781049c357", size = 874024, upload-time = "2026-04-13T21:33:16.915Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b1/3338e121cbd4c8a126b8ccb1061170c2ce51a53f678c502793ea49c6fd6d/chardet-7.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfc134b70c846c21ead8e43ada3ae1a805fff732f6922f8abcf2ff27b8f6493d", size = 887410, upload-time = "2026-04-13T21:33:18.368Z" }, + { url = "https://files.pythonhosted.org/packages/63/1c/44a9a9e0c59c185a5d307ceaeee8768afa1558f0a24f7a4b5fa11b67586b/chardet-7.4.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9acd9988a93e09390f3cd231201ea7166c415eb8da1b735928990ffc05cb9fbb", size = 879269, upload-time = "2026-04-13T21:33:20.377Z" }, + { url = "https://files.pythonhosted.org/packages/1b/b3/5d0e77ea774bd3224321c248880ea0c0379000ac5c2bb6d77609549de247/chardet-7.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:e1b98790c284ff813f18f7cf7de5f05ea2435a080030c7f1a8318f3a4f80b131", size = 944155, upload-time = "2026-04-13T21:33:21.694Z" }, + { url = "https://files.pythonhosted.org/packages/70/a8/bf0811d859e13801279a2ae64f37a408027b282f2047bc0001c75dd356ad/chardet-7.4.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d892d3dcd652fdef53e3d6327d39b17c0df40a899dfc919abaeb64c974497531", size = 872887, upload-time = "2026-04-13T21:33:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/51/ac/b9d68ebddfe1b02c77af5bf81120e12b036b4432dc6af7a303d90e2bc38b/chardet-7.4.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:acc46d1b8b7d5783216afe15db56d1c179b9a40e5a1558bc13164c4fd20674c4", size = 853964, upload-time = "2026-04-13T21:33:24.724Z" }, + { url = "https://files.pythonhosted.org/packages/2a/81/17fa103ea9caf5d325a5e4051ab2ba65996fd66baa60b81ee41af1f54e10/chardet-7.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ac3bf11c645734a1701a3804e43eabd98851838192267d08c353a834ab79fea", size = 876006, upload-time = "2026-04-13T21:33:26.098Z" }, + { url = "https://files.pythonhosted.org/packages/c2/20/193faab46a68ea550587331a698c3dca8099f8901d10937c4443135c7ed9/chardet-7.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e3bd9f936e04bae89c254262af08d9e5b98f805175ba1e29d454e6cba3107b7", size = 887680, upload-time = "2026-04-13T21:33:27.49Z" }, + { url = "https://files.pythonhosted.org/packages/40/c6/94a3c673327392652ee8bdea9a45bc8a5f5365197a7387d68f0eed007115/chardet-7.4.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:27cc23da03630cdecc9aa81a895aa86629c211f995cd57651f0fbc280717bf93", size = 879865, upload-time = "2026-04-13T21:33:29.052Z" }, + { url = "https://files.pythonhosted.org/packages/b1/2c/cad8b5e3623a987f3c930b68e2bdd06cfc388cd91cd42ed05f1227701b73/chardet-7.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:b95c934b9ad59e2ba8abb9be49df70d3ad1b0d95d864b9fdb7588d4fa8bd921c", size = 939594, upload-time = "2026-04-13T21:33:31.391Z" }, + { url = "https://files.pythonhosted.org/packages/33/e0/d06e42fd6f02a58e5e227e5106587751cb38adcff0aaf949add744b78b6e/chardet-7.4.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c77867f0c1cb8bd819502249fcdc500364aedb07881e11b743726fa2148e7b6e", size = 889714, upload-time = "2026-04-13T21:33:32.772Z" }, + { url = "https://files.pythonhosted.org/packages/d4/ed/40d091954d48abea037baae6be8fb79905e5f78d34d12ea955132c7d8011/chardet-7.4.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cf1efeaf65a6ef2f5b9cc3a1df6f08ba2831b369ccaa4c7018eaf90aa757bb11", size = 872319, upload-time = "2026-04-13T21:33:34.427Z" }, + { url = "https://files.pythonhosted.org/packages/bb/77/82a46821dbfbdfe062710d2bf2ede13426304e3567a23c57d919c0c31630/chardet-7.4.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9f3504c139a2ad544077dd2d9e412cd08b01786843d76997cd43bb6de311723c", size = 892021, upload-time = "2026-04-13T21:33:35.766Z" }, + { url = "https://files.pythonhosted.org/packages/49/57/42d30c562bda5b4a839766c1aad8d5856b798ad2a1c3247b72a679afec94/chardet-7.4.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457f619882ba66327d4d8d14c6c342269bdb1e4e1c38e8117df941d14d351b04", size = 902509, upload-time = "2026-04-13T21:33:37.096Z" }, + { url = "https://files.pythonhosted.org/packages/8c/6c/0a40afdb50a0fe041ab95553b835a8160b6cf0e81edf2ae2fe9f5224cbf9/chardet-7.4.3-py3-none-any.whl", hash = "sha256:1173b74051570cf08099d7429d92e4882d375ad4217f92a6e5240ccfb26f231e", size = 626562, upload-time = "2026-04-13T21:33:38.559Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/a1/67fe25fac3c7642725500a3f6cfe5821ad557c3abb11c9d20d12c7008d3e/charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5", size = 144271, upload-time = "2026-04-02T09:28:39.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/08/0f303cb0b529e456bb116f2d50565a482694fbb94340bf56d44677e7ed03/charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d", size = 315182, upload-time = "2026-04-02T09:25:40.673Z" }, + { url = "https://files.pythonhosted.org/packages/24/47/b192933e94b546f1b1fe4df9cc1f84fcdbf2359f8d1081d46dd029b50207/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8", size = 209329, upload-time = "2026-04-02T09:25:42.354Z" }, + { url = "https://files.pythonhosted.org/packages/c2/b4/01fa81c5ca6141024d89a8fc15968002b71da7f825dd14113207113fabbd/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790", size = 231230, upload-time = "2026-04-02T09:25:44.281Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/7b991776844dfa058017e600e6e55ff01984a063290ca5622c0b63162f68/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc", size = 225890, upload-time = "2026-04-02T09:25:45.475Z" }, + { url = "https://files.pythonhosted.org/packages/20/e7/bed0024a0f4ab0c8a9c64d4445f39b30c99bd1acd228291959e3de664247/charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393", size = 216930, upload-time = "2026-04-02T09:25:46.58Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ab/b18f0ab31cdd7b3ddb8bb76c4a414aeb8160c9810fdf1bc62f269a539d87/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153", size = 202109, upload-time = "2026-04-02T09:25:48.031Z" }, + { url = "https://files.pythonhosted.org/packages/82/e5/7e9440768a06dfb3075936490cb82dbf0ee20a133bf0dd8551fa096914ec/charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af", size = 214684, upload-time = "2026-04-02T09:25:49.245Z" }, + { url = "https://files.pythonhosted.org/packages/71/94/8c61d8da9f062fdf457c80acfa25060ec22bf1d34bbeaca4350f13bcfd07/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34", size = 212785, upload-time = "2026-04-02T09:25:50.671Z" }, + { url = "https://files.pythonhosted.org/packages/66/cd/6e9889c648e72c0ab2e5967528bb83508f354d706637bc7097190c874e13/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1", size = 203055, upload-time = "2026-04-02T09:25:51.802Z" }, + { url = "https://files.pythonhosted.org/packages/92/2e/7a951d6a08aefb7eb8e1b54cdfb580b1365afdd9dd484dc4bee9e5d8f258/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752", size = 232502, upload-time = "2026-04-02T09:25:53.388Z" }, + { url = "https://files.pythonhosted.org/packages/58/d5/abcf2d83bf8e0a1286df55cd0dc1d49af0da4282aa77e986df343e7de124/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53", size = 214295, upload-time = "2026-04-02T09:25:54.765Z" }, + { url = "https://files.pythonhosted.org/packages/47/3a/7d4cd7ed54be99973a0dc176032cba5cb1f258082c31fa6df35cff46acfc/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616", size = 227145, upload-time = "2026-04-02T09:25:55.904Z" }, + { url = "https://files.pythonhosted.org/packages/1d/98/3a45bf8247889cf28262ebd3d0872edff11565b2a1e3064ccb132db3fbb0/charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a", size = 218884, upload-time = "2026-04-02T09:25:57.074Z" }, + { url = "https://files.pythonhosted.org/packages/ad/80/2e8b7f8915ed5c9ef13aa828d82738e33888c485b65ebf744d615040c7ea/charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374", size = 148343, upload-time = "2026-04-02T09:25:58.199Z" }, + { url = "https://files.pythonhosted.org/packages/35/1b/3b8c8c77184af465ee9ad88b5aea46ea6b2e1f7b9dc9502891e37af21e30/charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943", size = 159174, upload-time = "2026-04-02T09:25:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/feb40dca40dbb21e0a908801782d9288c64fc8d8e562c2098e9994c8c21b/charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008", size = 147805, upload-time = "2026-04-02T09:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/c2/d7/b5b7020a0565c2e9fa8c09f4b5fa6232feb326b8c20081ccded47ea368fd/charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7", size = 309705, upload-time = "2026-04-02T09:26:02.191Z" }, + { url = "https://files.pythonhosted.org/packages/5a/53/58c29116c340e5456724ecd2fff4196d236b98f3da97b404bc5e51ac3493/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7", size = 206419, upload-time = "2026-04-02T09:26:03.583Z" }, + { url = "https://files.pythonhosted.org/packages/b2/02/e8146dc6591a37a00e5144c63f29fb7c97a734ea8a111190783c0e60ab63/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e", size = 227901, upload-time = "2026-04-02T09:26:04.738Z" }, + { url = "https://files.pythonhosted.org/packages/fb/73/77486c4cd58f1267bf17db420e930c9afa1b3be3fe8c8b8ebbebc9624359/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c", size = 222742, upload-time = "2026-04-02T09:26:06.36Z" }, + { url = "https://files.pythonhosted.org/packages/a1/fa/f74eb381a7d94ded44739e9d94de18dc5edc9c17fb8c11f0a6890696c0a9/charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df", size = 214061, upload-time = "2026-04-02T09:26:08.347Z" }, + { url = "https://files.pythonhosted.org/packages/dc/92/42bd3cefcf7687253fb86694b45f37b733c97f59af3724f356fa92b8c344/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265", size = 199239, upload-time = "2026-04-02T09:26:09.823Z" }, + { url = "https://files.pythonhosted.org/packages/4c/3d/069e7184e2aa3b3cddc700e3dd267413dc259854adc3380421c805c6a17d/charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4", size = 210173, upload-time = "2026-04-02T09:26:10.953Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/9d56feb5f2e7074c46f93e0ebdbe61f0848ee246e2f0d89f8e20b89ebb8f/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e", size = 209841, upload-time = "2026-04-02T09:26:12.142Z" }, + { url = "https://files.pythonhosted.org/packages/d2/59/893d8f99cc4c837dda1fe2f1139079703deb9f321aabcb032355de13b6c7/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38", size = 200304, upload-time = "2026-04-02T09:26:13.711Z" }, + { url = "https://files.pythonhosted.org/packages/7d/1d/ee6f3be3464247578d1ed5c46de545ccc3d3ff933695395c402c21fa6b77/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c", size = 229455, upload-time = "2026-04-02T09:26:14.941Z" }, + { url = "https://files.pythonhosted.org/packages/54/bb/8fb0a946296ea96a488928bdce8ef99023998c48e4713af533e9bb98ef07/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b", size = 210036, upload-time = "2026-04-02T09:26:16.478Z" }, + { url = "https://files.pythonhosted.org/packages/9a/bc/015b2387f913749f82afd4fcba07846d05b6d784dd16123cb66860e0237d/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c", size = 224739, upload-time = "2026-04-02T09:26:17.751Z" }, + { url = "https://files.pythonhosted.org/packages/17/ab/63133691f56baae417493cba6b7c641571a2130eb7bceba6773367ab9ec5/charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d", size = 216277, upload-time = "2026-04-02T09:26:18.981Z" }, + { url = "https://files.pythonhosted.org/packages/06/6d/3be70e827977f20db77c12a97e6a9f973631a45b8d186c084527e53e77a4/charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad", size = 147819, upload-time = "2026-04-02T09:26:20.295Z" }, + { url = "https://files.pythonhosted.org/packages/20/d9/5f67790f06b735d7c7637171bbfd89882ad67201891b7275e51116ed8207/charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00", size = 159281, upload-time = "2026-04-02T09:26:21.74Z" }, + { url = "https://files.pythonhosted.org/packages/ca/83/6413f36c5a34afead88ce6f66684d943d91f233d76dd083798f9602b75ae/charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1", size = 147843, upload-time = "2026-04-02T09:26:22.901Z" }, + { url = "https://files.pythonhosted.org/packages/0c/eb/4fc8d0a7110eb5fc9cc161723a34a8a6c200ce3b4fbf681bc86feee22308/charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46", size = 311328, upload-time = "2026-04-02T09:26:24.331Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e3/0fadc706008ac9d7b9b5be6dc767c05f9d3e5df51744ce4cc9605de7b9f4/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2", size = 208061, upload-time = "2026-04-02T09:26:25.568Z" }, + { url = "https://files.pythonhosted.org/packages/42/f0/3dd1045c47f4a4604df85ec18ad093912ae1344ac706993aff91d38773a2/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b", size = 229031, upload-time = "2026-04-02T09:26:26.865Z" }, + { url = "https://files.pythonhosted.org/packages/dc/67/675a46eb016118a2fbde5a277a5d15f4f69d5f3f5f338e5ee2f8948fcf43/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a", size = 225239, upload-time = "2026-04-02T09:26:28.044Z" }, + { url = "https://files.pythonhosted.org/packages/4b/f8/d0118a2f5f23b02cd166fa385c60f9b0d4f9194f574e2b31cef350ad7223/charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116", size = 216589, upload-time = "2026-04-02T09:26:29.239Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f1/6d2b0b261b6c4ceef0fcb0d17a01cc5bc53586c2d4796fa04b5c540bc13d/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb", size = 202733, upload-time = "2026-04-02T09:26:30.5Z" }, + { url = "https://files.pythonhosted.org/packages/6f/c0/7b1f943f7e87cc3db9626ba17807d042c38645f0a1d4415c7a14afb5591f/charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1", size = 212652, upload-time = "2026-04-02T09:26:31.709Z" }, + { url = "https://files.pythonhosted.org/packages/38/dd/5a9ab159fe45c6e72079398f277b7d2b523e7f716acc489726115a910097/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15", size = 211229, upload-time = "2026-04-02T09:26:33.282Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ff/531a1cad5ca855d1c1a8b69cb71abfd6d85c0291580146fda7c82857caa1/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5", size = 203552, upload-time = "2026-04-02T09:26:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/c1/4c/a5fb52d528a8ca41f7598cb619409ece30a169fbdf9cdce592e53b46c3a6/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d", size = 230806, upload-time = "2026-04-02T09:26:36.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/7a/071feed8124111a32b316b33ae4de83d36923039ef8cf48120266844285b/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7", size = 212316, upload-time = "2026-04-02T09:26:37.672Z" }, + { url = "https://files.pythonhosted.org/packages/fd/35/f7dba3994312d7ba508e041eaac39a36b120f32d4c8662b8814dab876431/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464", size = 227274, upload-time = "2026-04-02T09:26:38.93Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2d/a572df5c9204ab7688ec1edc895a73ebded3b023bb07364710b05dd1c9be/charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49", size = 218468, upload-time = "2026-04-02T09:26:40.17Z" }, + { url = "https://files.pythonhosted.org/packages/86/eb/890922a8b03a568ca2f336c36585a4713c55d4d67bf0f0c78924be6315ca/charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c", size = 148460, upload-time = "2026-04-02T09:26:41.416Z" }, + { url = "https://files.pythonhosted.org/packages/35/d9/0e7dffa06c5ab081f75b1b786f0aefc88365825dfcd0ac544bdb7b2b6853/charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6", size = 159330, upload-time = "2026-04-02T09:26:42.554Z" }, + { url = "https://files.pythonhosted.org/packages/9e/5d/481bcc2a7c88ea6b0878c299547843b2521ccbc40980cb406267088bc701/charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d", size = 147828, upload-time = "2026-04-02T09:26:44.075Z" }, + { url = "https://files.pythonhosted.org/packages/c1/3b/66777e39d3ae1ddc77ee606be4ec6d8cbd4c801f65e5a1b6f2b11b8346dd/charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063", size = 309627, upload-time = "2026-04-02T09:26:45.198Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4e/b7f84e617b4854ade48a1b7915c8ccfadeba444d2a18c291f696e37f0d3b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c", size = 207008, upload-time = "2026-04-02T09:26:46.824Z" }, + { url = "https://files.pythonhosted.org/packages/c4/bb/ec73c0257c9e11b268f018f068f5d00aa0ef8c8b09f7753ebd5f2880e248/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66", size = 228303, upload-time = "2026-04-02T09:26:48.397Z" }, + { url = "https://files.pythonhosted.org/packages/85/fb/32d1f5033484494619f701e719429c69b766bfc4dbc61aa9e9c8c166528b/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18", size = 224282, upload-time = "2026-04-02T09:26:49.684Z" }, + { url = "https://files.pythonhosted.org/packages/fa/07/330e3a0dda4c404d6da83b327270906e9654a24f6c546dc886a0eb0ffb23/charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd", size = 215595, upload-time = "2026-04-02T09:26:50.915Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7c/fc890655786e423f02556e0216d4b8c6bcb6bdfa890160dc66bf52dee468/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215", size = 201986, upload-time = "2026-04-02T09:26:52.197Z" }, + { url = "https://files.pythonhosted.org/packages/d8/97/bfb18b3db2aed3b90cf54dc292ad79fdd5ad65c4eae454099475cbeadd0d/charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859", size = 211711, upload-time = "2026-04-02T09:26:53.49Z" }, + { url = "https://files.pythonhosted.org/packages/6f/a5/a581c13798546a7fd557c82614a5c65a13df2157e9ad6373166d2a3e645d/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8", size = 210036, upload-time = "2026-04-02T09:26:54.975Z" }, + { url = "https://files.pythonhosted.org/packages/8c/bf/b3ab5bcb478e4193d517644b0fb2bf5497fbceeaa7a1bc0f4d5b50953861/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5", size = 202998, upload-time = "2026-04-02T09:26:56.303Z" }, + { url = "https://files.pythonhosted.org/packages/e7/4e/23efd79b65d314fa320ec6017b4b5834d5c12a58ba4610aa353af2e2f577/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832", size = 230056, upload-time = "2026-04-02T09:26:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9f/1e1941bc3f0e01df116e68dc37a55c4d249df5e6fa77f008841aef68264f/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6", size = 211537, upload-time = "2026-04-02T09:26:58.843Z" }, + { url = "https://files.pythonhosted.org/packages/80/0f/088cbb3020d44428964a6c97fe1edfb1b9550396bf6d278330281e8b709c/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48", size = 226176, upload-time = "2026-04-02T09:27:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9f/130394f9bbe06f4f63e22641d32fc9b202b7e251c9aef4db044324dac493/charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a", size = 217723, upload-time = "2026-04-02T09:27:02.021Z" }, + { url = "https://files.pythonhosted.org/packages/73/55/c469897448a06e49f8fa03f6caae97074fde823f432a98f979cc42b90e69/charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e", size = 148085, upload-time = "2026-04-02T09:27:03.192Z" }, + { url = "https://files.pythonhosted.org/packages/5d/78/1b74c5bbb3f99b77a1715c91b3e0b5bdb6fe302d95ace4f5b1bec37b0167/charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110", size = 158819, upload-time = "2026-04-02T09:27:04.454Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/46bd42279d323deb8687c4a5a811fd548cb7d1de10cf6535d099877a9a9f/charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b", size = 147915, upload-time = "2026-04-02T09:27:05.971Z" }, + { url = "https://files.pythonhosted.org/packages/97/c8/c67cb8c70e19ef1960b97b22ed2a1567711de46c4ddf19799923adc836c2/charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0", size = 309234, upload-time = "2026-04-02T09:27:07.194Z" }, + { url = "https://files.pythonhosted.org/packages/99/85/c091fdee33f20de70d6c8b522743b6f831a2f1cd3ff86de4c6a827c48a76/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a", size = 208042, upload-time = "2026-04-02T09:27:08.749Z" }, + { url = "https://files.pythonhosted.org/packages/87/1c/ab2ce611b984d2fd5d86a5a8a19c1ae26acac6bad967da4967562c75114d/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b", size = 228706, upload-time = "2026-04-02T09:27:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/a8/29/2b1d2cb00bf085f59d29eb773ce58ec2d325430f8c216804a0a5cd83cbca/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41", size = 224727, upload-time = "2026-04-02T09:27:11.175Z" }, + { url = "https://files.pythonhosted.org/packages/47/5c/032c2d5a07fe4d4855fea851209cca2b6f03ebeb6d4e3afdb3358386a684/charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e", size = 215882, upload-time = "2026-04-02T09:27:12.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c2/356065d5a8b78ed04499cae5f339f091946a6a74f91e03476c33f0ab7100/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae", size = 200860, upload-time = "2026-04-02T09:27:13.721Z" }, + { url = "https://files.pythonhosted.org/packages/0c/cd/a32a84217ced5039f53b29f460962abb2d4420def55afabe45b1c3c7483d/charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18", size = 211564, upload-time = "2026-04-02T09:27:15.272Z" }, + { url = "https://files.pythonhosted.org/packages/44/86/58e6f13ce26cc3b8f4a36b94a0f22ae2f00a72534520f4ae6857c4b81f89/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b", size = 211276, upload-time = "2026-04-02T09:27:16.834Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fe/d17c32dc72e17e155e06883efa84514ca375f8a528ba2546bee73fc4df81/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356", size = 201238, upload-time = "2026-04-02T09:27:18.229Z" }, + { url = "https://files.pythonhosted.org/packages/6a/29/f33daa50b06525a237451cdb6c69da366c381a3dadcd833fa5676bc468b3/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab", size = 230189, upload-time = "2026-04-02T09:27:19.445Z" }, + { url = "https://files.pythonhosted.org/packages/b6/6e/52c84015394a6a0bdcd435210a7e944c5f94ea1055f5cc5d56c5fe368e7b/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46", size = 211352, upload-time = "2026-04-02T09:27:20.79Z" }, + { url = "https://files.pythonhosted.org/packages/8c/d7/4353be581b373033fb9198bf1da3cf8f09c1082561e8e922aa7b39bf9fe8/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44", size = 227024, upload-time = "2026-04-02T09:27:22.063Z" }, + { url = "https://files.pythonhosted.org/packages/30/45/99d18aa925bd1740098ccd3060e238e21115fffbfdcb8f3ece837d0ace6c/charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72", size = 217869, upload-time = "2026-04-02T09:27:23.486Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/5ee478aa53f4bb7996482153d4bfe1b89e0f087f0ab6b294fcf92d595873/charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10", size = 148541, upload-time = "2026-04-02T09:27:25.146Z" }, + { url = "https://files.pythonhosted.org/packages/48/77/72dcb0921b2ce86420b2d79d454c7022bf5be40202a2a07906b9f2a35c97/charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f", size = 159634, upload-time = "2026-04-02T09:27:26.642Z" }, + { url = "https://files.pythonhosted.org/packages/c6/a3/c2369911cd72f02386e4e340770f6e158c7980267da16af8f668217abaa0/charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246", size = 148384, upload-time = "2026-04-02T09:27:28.271Z" }, + { url = "https://files.pythonhosted.org/packages/94/09/7e8a7f73d24dba1f0035fbbf014d2c36828fc1bf9c88f84093e57d315935/charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24", size = 330133, upload-time = "2026-04-02T09:27:29.474Z" }, + { url = "https://files.pythonhosted.org/packages/8d/da/96975ddb11f8e977f706f45cddd8540fd8242f71ecdb5d18a80723dcf62c/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79", size = 216257, upload-time = "2026-04-02T09:27:30.793Z" }, + { url = "https://files.pythonhosted.org/packages/e5/e8/1d63bf8ef2d388e95c64b2098f45f84758f6d102a087552da1485912637b/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960", size = 234851, upload-time = "2026-04-02T09:27:32.44Z" }, + { url = "https://files.pythonhosted.org/packages/9b/40/e5ff04233e70da2681fa43969ad6f66ca5611d7e669be0246c4c7aaf6dc8/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4", size = 233393, upload-time = "2026-04-02T09:27:34.03Z" }, + { url = "https://files.pythonhosted.org/packages/be/c1/06c6c49d5a5450f76899992f1ee40b41d076aee9279b49cf9974d2f313d5/charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e", size = 223251, upload-time = "2026-04-02T09:27:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f2ff16fb050946169e3e1f82134d107e5d4ae72647ec8a1b1446c148480f/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1", size = 206609, upload-time = "2026-04-02T09:27:36.661Z" }, + { url = "https://files.pythonhosted.org/packages/69/d5/a527c0cd8d64d2eab7459784fb4169a0ac76e5a6fc5237337982fd61347e/charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44", size = 220014, upload-time = "2026-04-02T09:27:38.019Z" }, + { url = "https://files.pythonhosted.org/packages/7e/80/8a7b8104a3e203074dc9aa2c613d4b726c0e136bad1cc734594b02867972/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e", size = 218979, upload-time = "2026-04-02T09:27:39.37Z" }, + { url = "https://files.pythonhosted.org/packages/02/9a/b759b503d507f375b2b5c153e4d2ee0a75aa215b7f2489cf314f4541f2c0/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3", size = 209238, upload-time = "2026-04-02T09:27:40.722Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/0f3f5d47b86bdb79256e7290b26ac847a2832d9a4033f7eb2cd4bcf4bb5b/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0", size = 236110, upload-time = "2026-04-02T09:27:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/96/23/bce28734eb3ed2c91dcf93abeb8a5cf393a7b2749725030bb630e554fdd8/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e", size = 219824, upload-time = "2026-04-02T09:27:43.924Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6f/6e897c6984cc4d41af319b077f2f600fc8214eb2fe2d6bcb79141b882400/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb", size = 233103, upload-time = "2026-04-02T09:27:45.348Z" }, + { url = "https://files.pythonhosted.org/packages/76/22/ef7bd0fe480a0ae9b656189ec00744b60933f68b4f42a7bb06589f6f576a/charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe", size = 225194, upload-time = "2026-04-02T09:27:46.706Z" }, + { url = "https://files.pythonhosted.org/packages/c5/a7/0e0ab3e0b5bc1219bd80a6a0d4d72ca74d9250cb2382b7c699c147e06017/charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0", size = 159827, upload-time = "2026-04-02T09:27:48.053Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1d/29d32e0fb40864b1f878c7f5a0b343ae676c6e2b271a2d55cc3a152391da/charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c", size = 174168, upload-time = "2026-04-02T09:27:49.795Z" }, + { url = "https://files.pythonhosted.org/packages/de/32/d92444ad05c7a6e41fb2036749777c163baf7a0301a040cb672d6b2b1ae9/charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d", size = 153018, upload-time = "2026-04-02T09:27:51.116Z" }, + { url = "https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d", size = 61958, upload-time = "2026-04-02T09:28:37.794Z" }, +] + +[[package]] +name = "click" +version = "8.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, +] + +[[package]] +name = "codecov" +version = "2.1.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/bb/594b26d2c85616be6195a64289c578662678afa4910cef2d3ce8417cf73e/codecov-2.1.13.tar.gz", hash = "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c", size = 21416, upload-time = "2023-04-17T23:11:39.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/02/18785edcdf6266cdd6c6dc7635f1cbeefd9a5b4c3bb8aff8bd681e9dd095/codecov-2.1.13-py2.py3-none-any.whl", hash = "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5", size = 16512, upload-time = "2023-04-17T23:11:37.344Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, +] + +[[package]] +name = "coverage" +version = "7.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/fd/0ab2772530e946e1be1abd0bc09e647ec9b02e88f0867857601fefca8953/coverage-7.14.1.tar.gz", hash = "sha256:30c08f7d90415aa98b3c990385dea2939b0da55f38515e5b369b83655f8523be", size = 920132, upload-time = "2026-05-26T20:41:36.783Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/69/0d2ef01ff4b8fcecd4cba920d11e92fa4f96ae412441d3b56a90a258e69b/coverage-7.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3e3680291c4a1d0dadfa84a2c459576a4af5133abb617905714339a0c73138cf", size = 219722, upload-time = "2026-05-26T20:38:14.002Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ae/9afdeaa31b9d9ce98124b6abf8bb49119bf71aecae04f8567c189d91299f/coverage-7.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5274669f37f2343635a347b91a60777621341ab3378e9c6ac9335eee704bddf", size = 220240, upload-time = "2026-05-26T20:38:17.424Z" }, + { url = "https://files.pythonhosted.org/packages/51/69/c998589871df7ea7dba865cc5ee32b5a3e1d47ba6c68ef91104c7c46fa5e/coverage-7.14.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cfe5a5fec635799ef33428f1e5e61bafa45a92a96190ba731561ba558ccc214d", size = 246981, upload-time = "2026-05-26T20:38:19.266Z" }, + { url = "https://files.pythonhosted.org/packages/fc/10/1c7d04c13040dac531d21b712bbe08f902e6dd9b58f5d77875c4d030f8f2/coverage-7.14.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:62a9f70b52e0b5a95cfef4a5c5641b06983cadc5e538a3feeb5c00211f523ac2", size = 248812, upload-time = "2026-05-26T20:38:20.75Z" }, + { url = "https://files.pythonhosted.org/packages/c1/65/2a38a4607ef27cadcfbcee034dba5830ae2569f90144a0f4c7dbf47d30b0/coverage-7.14.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c18ebc343e15be53049b3a2dce38fe82d58f37e20ab9094b3a39c0aa4f6bb47", size = 250675, upload-time = "2026-05-26T20:38:22.159Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a2/a446ed9752a4a59b79e0fb6cbb319f6facb2183045c0725462625e66f87e/coverage-7.14.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b84ffdf877644e7096aa936991efeed873f7f3df57b9cd001312b7668ab08550", size = 252590, upload-time = "2026-05-26T20:38:23.63Z" }, + { url = "https://files.pythonhosted.org/packages/9e/fd/e81fbd7ba752365546e9842b1cbdaad3d6919d2a522c590aef16a281ec5e/coverage-7.14.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e854312c4103f2ad4c0dc023b69b77ebfd2c89db5f86c4c94dc2353f9a92167e", size = 247691, upload-time = "2026-05-26T20:38:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/53/35/f3c26fdaae9ea937d154ca4d372e5ea0a4167ff70d36c6074ac2eacb2f83/coverage-7.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c643734307300234fafa36bf2a040a7235f8f177ea1fd6ec1423aea6fb7b929f", size = 248716, upload-time = "2026-05-26T20:38:26.406Z" }, + { url = "https://files.pythonhosted.org/packages/2e/14/940b6c49551fd343e8507ee2b0ba7af5d0aa04ed5bf768285cb7c72a9884/coverage-7.14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84ac9499e48700399a5dd0ea7085b5091961fec52c68d66b4ec0d3cf7f4441b1", size = 246721, upload-time = "2026-05-26T20:38:28.282Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2c/40fc0634186c28292a662dff578866b3913983d6c375a3c2a74020938719/coverage-7.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:7f02d09f70776579b926d889a4c9c235070a1f47c40458aeaca563fae5acfdb5", size = 250533, upload-time = "2026-05-26T20:38:29.753Z" }, + { url = "https://files.pythonhosted.org/packages/de/e3/2c26bf1e811f9df991ff2a9bdddebdd13ee0665d564df7d05979f9146297/coverage-7.14.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:ce66d8e46da2bb5ee313a745cbd2e391d319176c1f7a9451bfcd3a2fb920859b", size = 246990, upload-time = "2026-05-26T20:38:31.516Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b0/060260ef56bd92363ebdce0c7095ce422b06e69aae71828efeca473ab1ca/coverage-7.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c912c259304cfb5ee584481cfb7ce1ff932b4d61e6c9140b8f19cb7b5ed82332", size = 247593, upload-time = "2026-05-26T20:38:33.065Z" }, + { url = "https://files.pythonhosted.org/packages/63/f3/501502046efeb0d6d94b5ca54941d95f1184183dd6bdb7f283985783bb4a/coverage-7.14.1-cp310-cp310-win32.whl", hash = "sha256:1238cb94638e610e972c60dac68e813f868dc7d6e982535270558443058d9d59", size = 222330, upload-time = "2026-05-26T20:38:35.36Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5d/1bf99f2c558f128faf7906817ccbdb576ba815d3b41ce2ac1719b70a3663/coverage-7.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:fc459e5d73be2d6332fcfe8dbf3d8994671fe33c700f4565988ecfa511547253", size = 223261, upload-time = "2026-05-26T20:38:37.196Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d7/477ad149490e6cb849f28abea1dabb9c823cea72e7500c81b4240ce619c0/coverage-7.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:478b5bcd63c2e1357c5c7e16c070690df7b07f676b1c114d7b93e533c664309f", size = 219848, upload-time = "2026-05-26T20:38:38.715Z" }, + { url = "https://files.pythonhosted.org/packages/91/82/a5eb47257c50601bb7b9a9d2857c67b7a3a85ad74180eb2c98bb1fbe0ce5/coverage-7.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a24a81f9715ee42ef59a316cc11611c98fe23920f7c81861315c9f3ff4a230f4", size = 220354, upload-time = "2026-05-26T20:38:40.232Z" }, + { url = "https://files.pythonhosted.org/packages/43/8b/78419b5391a5cb706b6544390507e469d83ffc9a8248b02c4011aceb9365/coverage-7.14.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:196a13319ad88d6d8ef5ab489ec4f44ddde2143c0c7d5b27786f6c3ffd56a7e1", size = 250771, upload-time = "2026-05-26T20:38:41.782Z" }, + { url = "https://files.pythonhosted.org/packages/77/63/e77aaacd491182210d639636b7a8bba23ffffa9b82aa3762da9431855fa9/coverage-7.14.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3d452fd08b5c72c5167c93e6867b5c08500bd40f2a21e1e854a500550b6cc36f", size = 252683, upload-time = "2026-05-26T20:38:43.305Z" }, + { url = "https://files.pythonhosted.org/packages/65/1c/a022e3cfbec2ac241640003cb3a817e161d9c7f5aa9b49173756cdc03204/coverage-7.14.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23bf7fa51ac02e07fc7c96849b82946da47ae862dc8f86d183b2a4864fc38129", size = 254791, upload-time = "2026-05-26T20:38:45.361Z" }, + { url = "https://files.pythonhosted.org/packages/61/d6/967e408aca4c1ceb88cb0cc677169110ae7f5995fb5eaf5fb1f5a1bb8f5d/coverage-7.14.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bcaa50684dcaadfa599ac48f81103c756d791cfd85c97203d2217c593d48b860", size = 256748, upload-time = "2026-05-26T20:38:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/b8/be/869188f7fe28638078ec479331ace6dc5f7b40b7153eb616f47ab79404d8/coverage-7.14.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4ea1c034f95c9b056e856b794630b17f9fa3d57e4800ff1e503d3be0f9c9078c", size = 250907, upload-time = "2026-05-26T20:38:48.493Z" }, + { url = "https://files.pythonhosted.org/packages/07/aa/adb7d3b4278d690e68703abcd76ab1b948242e3668d921711551b78f9ddb/coverage-7.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c7e057326434e441306226fbeb5d1aaf14a2637efe97ba668306635835f32ad7", size = 252483, upload-time = "2026-05-26T20:38:50.074Z" }, + { url = "https://files.pythonhosted.org/packages/43/61/331c74103c62dcb0c4b9b3a0de9a61aca016208b0a90f109592a9f9ecc28/coverage-7.14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:59baf88468dbc8d63b1887afd92bda52e40bb1561696e5819670601403810cec", size = 250545, upload-time = "2026-05-26T20:38:51.613Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b6/c5dae3c104d89be04828f61810e6b3473825482e4c288cc4ed04553e08ae/coverage-7.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d34d75f892b3ab73ba11cab5442cce7b3e168fd64162b16f0e1e0d09c508edef", size = 254310, upload-time = "2026-05-26T20:38:53.503Z" }, + { url = "https://files.pythonhosted.org/packages/ad/a1/2b9d5863e3b83c01ad8199e3c597802fbb3a9dc90b058885804c20296d31/coverage-7.14.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3a56abc20a472baf0304c455721bc601477440d28ecfde8a03dde79ede07e0df", size = 250266, upload-time = "2026-05-26T20:38:55.414Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5e/0e511fbdb269359be26fe678a1c3fa1f2aa2a01573cc3f54268c8d6d4797/coverage-7.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6a3cb83d1552c0cd1b4906655b6a33fd4a8473229633a901c6b73bf86914dee9", size = 251174, upload-time = "2026-05-26T20:38:57.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/10/e55307b622b3dd9671cb321824502dc10f93e72f2802b9946159a8edadeb/coverage-7.14.1-cp311-cp311-win32.whl", hash = "sha256:10274a1fbeb8ec5d72966e17bb198a3104257aca4ac09d98667c5f8aca8c8548", size = 222354, upload-time = "2026-05-26T20:38:58.727Z" }, + { url = "https://files.pythonhosted.org/packages/71/cf/107421693cfb71e4f1ca5bf70443f64d4161878068d07a3e51c7ad21d17b/coverage-7.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:87ebdf787d4888e3f3f2d523eadc6e18c6d18c6d0eb173801a189641627fb37e", size = 223290, upload-time = "2026-05-26T20:39:00.413Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1d/3e3644585eb29e9dafefb19555078529a4d7cce12bd21929664eea989277/coverage-7.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:dd34767fa19848d35659ffc0a75314f58c7af3f1cd87ec521e8292a1238398a3", size = 221953, upload-time = "2026-05-26T20:39:02.159Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b7/bdbb725ba02c5b42825b200c940f38b7a54fcad24627b7192f78f8110d76/coverage-7.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a06c76364a9360e33d6d23769aefdf7f66f38e2ffb60ceb1baaa4989d83b695c", size = 220022, upload-time = "2026-05-26T20:39:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/72/81/fdc0898a55c6219223291ec1a1fe89966ef212ce82276aa0899df84b5de0/coverage-7.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fad54e871165f6ec2f536063ac74c3104508a12963e64072ba44bd822de52b0c", size = 220379, upload-time = "2026-05-26T20:39:05.381Z" }, + { url = "https://files.pythonhosted.org/packages/de/72/de048c4a25e13bce59ac6a339351c10bdf2515e07459afcdaf04dc3143a2/coverage-7.14.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:84b535f00655ecafe1d929d1fb00ed5d6fa3051ea643ab2c161a3887b86f294b", size = 251888, upload-time = "2026-05-26T20:39:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/28/30/300c343f68beb9d4cbb64ec81e58c5b6b80b56927f72d2b38654ac26e013/coverage-7.14.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6b6b0853b895fe0e98cbfc580d1ec3393d9302b4b1e96a77b3f5c91fdab899e6", size = 254624, upload-time = "2026-05-26T20:39:09.037Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ed/7b25642496e8170b6bac14adce00537c6e5fa2d586159401a4de3e8b49e6/coverage-7.14.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:442cc9c952b2df400cda54bb04ab87330cf2cd08a8692cbbea36773531eb6f37", size = 255739, upload-time = "2026-05-26T20:39:10.889Z" }, + { url = "https://files.pythonhosted.org/packages/7f/a2/abd210b8c4e29c24e4624916db97bb519097a91034aaeb767f937e7da794/coverage-7.14.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8270544c361ed405a27a060dbc9ed2c124b084d96dfdc2d9a2510482aef981ad", size = 257998, upload-time = "2026-05-26T20:39:12.722Z" }, + { url = "https://files.pythonhosted.org/packages/7f/24/7c50beed3792fe62f6ce0545c6686ce83379719e2c0276179333d97eae92/coverage-7.14.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:48b283b1dd6372e8de2a7a9a4c4d5dc06f4d4fd209b876f3c88a7a205a0c8f84", size = 252296, upload-time = "2026-05-26T20:39:14.259Z" }, + { url = "https://files.pythonhosted.org/packages/15/05/0f874628ebcbfc77ead559ff210281ef06a97db08481832e7dd39274a135/coverage-7.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5b0c99ba93a07d56f6df340bb79be53202a082b2fdb81bfe6190b741a3470d54", size = 253658, upload-time = "2026-05-26T20:39:15.923Z" }, + { url = "https://files.pythonhosted.org/packages/99/6f/ca6ad067364b337ef997802115e7ecad2abd2248b05471464b0dea02b4d4/coverage-7.14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e471bc5769ff073b058cfadb0d736b56ce067c8560eabeb0da88462df98c23e7", size = 251803, upload-time = "2026-05-26T20:39:17.537Z" }, + { url = "https://files.pythonhosted.org/packages/c0/30/b9b4d377cd9f40baf228068f5a81faf8450c6228503011bd499708483a50/coverage-7.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f497a1ea81d4cd7c10ddcaa685135b9aabd291af3d55775a9ddf3cb7a364cdd9", size = 255873, upload-time = "2026-05-26T20:39:19.414Z" }, + { url = "https://files.pythonhosted.org/packages/3c/21/7c721a9e5e6bb88547d30a787aefb97512d3f54c1324c7488d9b3743f7f9/coverage-7.14.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:2222be86d0b54f5dd5a38f45f17f315f737245e857bf0bdedc70734f84a13c02", size = 251372, upload-time = "2026-05-26T20:39:21.169Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f8ae5a2200130e1503cd7661a6cd3b2b7bacef98277fbf3571fb13f8b766/coverage-7.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:85e85586565842f6932abebd4c18bcb1074223dc0b3576e7d173ca710622813a", size = 253245, upload-time = "2026-05-26T20:39:23.097Z" }, + { url = "https://files.pythonhosted.org/packages/34/62/70a9024672a5f6910517d9628c52c9afbdd3cf8f46426af52bb148a56fff/coverage-7.14.1-cp312-cp312-win32.whl", hash = "sha256:4a28fd227808366b196a75476dced2eb35b351d6766ba9c858dc93319e87f4f1", size = 222567, upload-time = "2026-05-26T20:39:24.868Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/8b7cd386839b039ebe1855733b9f9449a8dec5d79564018234f185a7fa70/coverage-7.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:54acdb6674a4661768d7bf7db32dfb9f46ab1d764f8aba6df75ce1a6a088724e", size = 223372, upload-time = "2026-05-26T20:39:26.603Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ba/b44d472022f620d289d95fa830143235c0c36461c6f2437ea8d51e5481ed/coverage-7.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:99cd41ff91afd94896fea3bc002706b6ae4ce95727d06e4a0f39c0a8d8bd8b1a", size = 221989, upload-time = "2026-05-26T20:39:28.242Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/5f6d56327c62b185225d145191c607e07515294a0aa6338e58805cd4a5ac/coverage-7.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:be9f2c802dcfce3f71298303aa5dad0dce440a76c52f2f60dacd8656dab78793", size = 220044, upload-time = "2026-05-26T20:39:29.902Z" }, + { url = "https://files.pythonhosted.org/packages/75/92/e82aca356744cbbc0f77a0b623e38918c1872361963413a3bab5d0340393/coverage-7.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6223a72fd0e4c7156353ec0f08a5f93623e1d3034d0e2683b9bb8ea674131b1d", size = 220412, upload-time = "2026-05-26T20:39:31.561Z" }, + { url = "https://files.pythonhosted.org/packages/27/c9/385bde0bf7ed0f4bf3a7ee5367060a86b5d218718cfd6fb943c0f836b34f/coverage-7.14.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:7279d2110a28cebc738b6459ecda2771735a4c18465fbbd36b3288fe5ed92247", size = 251412, upload-time = "2026-05-26T20:39:33.337Z" }, + { url = "https://files.pythonhosted.org/packages/51/8c/23faf6a2343a0d17f960a4bd56c43bc7eb4cf312f774dd6ceebd82c7d8fc/coverage-7.14.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9eeb3fcbc13ba40dfbdb22d01d196a28e9cef9ed4c29b60061a1e0e823a9929d", size = 254008, upload-time = "2026-05-26T20:39:35.009Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/36f4aa9ca8a815e6036156e80706a67828bb97bd826948244f6996dda957/coverage-7.14.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f0cfc27c539f07cf5c0a4cfe211d0b6cae039f8f40526dbaa71944e64b50a7b", size = 255241, upload-time = "2026-05-26T20:39:36.71Z" }, + { url = "https://files.pythonhosted.org/packages/ca/79/95266316352f90f6b1c6736bb413302edfde2453fb32422d3911642691b3/coverage-7.14.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:221c70f316241a78e77e607c227cefc8808d4e08f28d99c04f35694690e940be", size = 257373, upload-time = "2026-05-26T20:39:38.412Z" }, + { url = "https://files.pythonhosted.org/packages/e3/9c/58316d1f66c488b5fca8a0eb3e98348807813efa8a0d0833b9021be27488/coverage-7.14.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:da028256b04ec30e5e0114b6f76172938c313991f0a2d3d894271315cf5d5e43", size = 251635, upload-time = "2026-05-26T20:39:40.268Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5a/ca2398a568e16fed7bb713e84ba3603a7164fb65779abe645c565ec890d5/coverage-7.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:76a085d7005236a767e3426148b2c407e53ad61695c562f8a81da2d373324901", size = 253373, upload-time = "2026-05-26T20:39:42.145Z" }, + { url = "https://files.pythonhosted.org/packages/6e/2c/0396562c32deaebe7be51d865b3a41e9a87d7561acafe1a28f53b07e019a/coverage-7.14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b553d04b5e778a8e56d57eb134aff42a92718ecba45e79c4764ecfa40efd92ff", size = 251341, upload-time = "2026-05-26T20:39:43.907Z" }, + { url = "https://files.pythonhosted.org/packages/fd/8f/a94f9221184c9cae1ee115820e3798e48b6b17777a9f19e46fb9a0c8dc74/coverage-7.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:46f714d2fb8ae2f4f29f23ada7f1e79b759fff5a70f94a1dac23af204c3ec9e4", size = 255497, upload-time = "2026-05-26T20:39:46.166Z" }, + { url = "https://files.pythonhosted.org/packages/71/69/505d70e47db1eaebcd002c39759707621ef184cd6b1ae084d9f41293f323/coverage-7.14.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1896f5e19ff3f0431c7ce2172adc54890fd97f86b59ced8ca1649145d9ffe35d", size = 251159, upload-time = "2026-05-26T20:39:48.03Z" }, + { url = "https://files.pythonhosted.org/packages/e0/aa/58681c383aa33a9d2ed40a02d7a22fbf780d1fa4d575396365777828198c/coverage-7.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:62fd185ef9df3c33d1c8178c5af105f762afbad96038de9a4ae100aa6297ca33", size = 252934, upload-time = "2026-05-26T20:39:49.872Z" }, + { url = "https://files.pythonhosted.org/packages/eb/fd/11c928cd6bdffc7074bb5965c173d9ebf517fb00205e1da524b98d29ef92/coverage-7.14.1-cp313-cp313-win32.whl", hash = "sha256:ab4af6352741a604c431c6072fce5bee33bf0f20dc7a56618d6bf6bb89e9810c", size = 222584, upload-time = "2026-05-26T20:39:51.68Z" }, + { url = "https://files.pythonhosted.org/packages/6f/92/fb416fc26d340dcba19518c418d6048e913186e17243982c5e435e41fa7a/coverage-7.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:7af486dabe8954d03b087f0021540897afe084f04e16ff5579e08cc46f871416", size = 223394, upload-time = "2026-05-26T20:39:53.472Z" }, + { url = "https://files.pythonhosted.org/packages/73/c6/02d56e3867972f77d5036de924643f26c056e848f00452cafb4dbc3c29b4/coverage-7.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:2224f89ffd0c5605ccce1ed7a584da162bc7c55f601ab1c946bc9de31a486b42", size = 222015, upload-time = "2026-05-26T20:39:55.374Z" }, + { url = "https://files.pythonhosted.org/packages/4d/9e/fcc77914050df73f7662fa1f00902774c79c075a8388ab334074574bf77e/coverage-7.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de286598cc65d2b489411174b1faec2f5a7775fb3201fd925db2a76b4030f37d", size = 220733, upload-time = "2026-05-26T20:39:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/f7/67/2963cbdaf5cbadec44efa3a1e39eaa1f02df4079585f05387607a221e126/coverage-7.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:042c46ded7c288aeb07cf14a28b6c1e10b78fcba40171c3fa1e939377eeef0b5", size = 221086, upload-time = "2026-05-26T20:39:59.019Z" }, + { url = "https://files.pythonhosted.org/packages/c8/c5/8701645574e11881f2f47d8930f98bc48b5d43b25eb5b4430dfc4a2f9f48/coverage-7.14.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f4ddbe407477f04c45115d1a4e5bc480f753553b534d338d4c3358b1cdd0ea52", size = 262381, upload-time = "2026-05-26T20:40:00.822Z" }, + { url = "https://files.pythonhosted.org/packages/7c/28/7a64d73598263e0c5abd5084211a8474488d31b3c552ff531c719dfcff62/coverage-7.14.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d13e6725992e2d2fd7d81d4f5241952d13740121dfd501da09201be39b2c003a", size = 264458, upload-time = "2026-05-26T20:40:02.506Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d8/4969179db9f7eb4df218e69540adf829d1c835f59452513d065d15446802/coverage-7.14.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f747dc8edcfe740130f28f32f3995e955494285717e86ee25af51db2219df08a", size = 266884, upload-time = "2026-05-26T20:40:04.421Z" }, + { url = "https://files.pythonhosted.org/packages/a6/78/a45d5794dbc9bafd97afc96a4377c86c7820d78b6cf51b89bc1d4e919275/coverage-7.14.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ced2f09ef276fd58611a1ef502164ad266d2b75174e5a40cabbdb4033f9f6cf2", size = 268022, upload-time = "2026-05-26T20:40:06.298Z" }, + { url = "https://files.pythonhosted.org/packages/21/cb/4f5e354e9e3e67af96bd4e57113e6db6b22298c7168b13eec408a549903d/coverage-7.14.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b84800013769a78ccb9ef4659402e26d06867e337b61ec365f77ad008adea80e", size = 261631, upload-time = "2026-05-26T20:40:08.226Z" }, + { url = "https://files.pythonhosted.org/packages/ec/49/eced49af4cb996d5d8b7e94e736175c513e4facd3398507b89892b4326d8/coverage-7.14.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ea8cd6ca0ee9f616aaef3afc6882e32c2cbf18b00d96313ffd76af650574034d", size = 264443, upload-time = "2026-05-26T20:40:10.137Z" }, + { url = "https://files.pythonhosted.org/packages/f1/d8/5603a88a7c5913a6b54f6cb1a8c46f7b39cbb30f27cd3f492908da09b2d7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:aa5e304a873fabddc11e484e9b6b738bd38bd7bed17b09aa84eecf5332e8b8bb", size = 262069, upload-time = "2026-05-26T20:40:11.999Z" }, + { url = "https://files.pythonhosted.org/packages/f0/59/2ae3cb79da554a06c8619d6c88ea19dd1e4aed4b834b6a83bb1fa243bdc5/coverage-7.14.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:5a1c5215be81035e629d5bc756650634d0bf31991038db7a0eccb90f025ce16d", size = 265780, upload-time = "2026-05-26T20:40:13.858Z" }, + { url = "https://files.pythonhosted.org/packages/af/5f/b130c1dc999031f2648bd25317fbce505ad8d5562079b4ed81e736a84967/coverage-7.14.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:79058c47dae6788504b5effb319961bcd72d7240551464b91d474bc0ed186d69", size = 260970, upload-time = "2026-05-26T20:40:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/87/d1/ec13ccddeb48ec963bdfa72a11224bac2584bd045ba13beca82f8113e9c7/coverage-7.14.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:370c5afae3fa0658e11694a32b24c2778f6bc2d17718121f94ee185e69f26b54", size = 263157, upload-time = "2026-05-26T20:40:18.382Z" }, + { url = "https://files.pythonhosted.org/packages/cf/c2/cd91ead503045161092d3845f7bb95ea2f25131ce96d3e314dd835d91b9c/coverage-7.14.1-cp313-cp313t-win32.whl", hash = "sha256:3758dd0a7f1fa57365ef2e781df0f0731d38b6e3772259d13dae4bd8a958d4b1", size = 223259, upload-time = "2026-05-26T20:40:20.381Z" }, + { url = "https://files.pythonhosted.org/packages/71/9f/1e28d97e6bd2c76b07f38b7c02870f1371255ff6717f54eca578fcbbdd0e/coverage-7.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:6ff665fb023a77386fe11685190cee1f60a7d635994a30d9b0a061533d470fce", size = 224320, upload-time = "2026-05-26T20:40:22.316Z" }, + { url = "https://files.pythonhosted.org/packages/a9/e0/d936e908f0e1efa55e52b91e01b52f1055cef5e1ab2718493390ed8e2fb8/coverage-7.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:17a5a241e5997621a956a7f402a7433ef4221e5152809b785bec79e2323799f1", size = 222577, upload-time = "2026-05-26T20:40:24.894Z" }, + { url = "https://files.pythonhosted.org/packages/d6/34/fc2f101b151af3799a101f0550b0454aa008afdc0add677394ec4aa8ea10/coverage-7.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d5ed429d0b8edaac649e889b4ffcedb6c80b06629a3f93050e3dddfb99235bee", size = 220091, upload-time = "2026-05-26T20:40:27.249Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a7/1ebae2ab5b961b5c79bb09fe7b3ac99edb190d8be4a8c510b2cf66f46468/coverage-7.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8011224a62280e50dab346960c03cf47aca1a1e09e608c0fb33fd6e0cc8e9500", size = 220421, upload-time = "2026-05-26T20:40:30.084Z" }, + { url = "https://files.pythonhosted.org/packages/5e/90/92aca9cf0acc95123c96cd1eb1f08917897a7f5dee01e15738922971ec31/coverage-7.14.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:12c42ec1e14f553c4f817e989365982e646e27211f10a0f717855b94a79c8906", size = 251466, upload-time = "2026-05-26T20:40:32.542Z" }, + { url = "https://files.pythonhosted.org/packages/26/2b/78048cbe3b999f6cbf9cc0d90abba6a88a3e0863a8c1c6cbc762f3f8802f/coverage-7.14.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:06144cd511cf2624873a035c5069cf297144f6e77a73ee3d7a55b605ec5efb42", size = 253973, upload-time = "2026-05-26T20:40:34.473Z" }, + { url = "https://files.pythonhosted.org/packages/8e/21/c2e33b29d1cfde484a19d437afc343c6cd30b08d78cbbf9f5aff14e57b2b/coverage-7.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a311d8e1da24be5c1ccf85cbfb06315dbaa1703d5a1eab3f6432c72b837917c8", size = 255318, upload-time = "2026-05-26T20:40:38.154Z" }, + { url = "https://files.pythonhosted.org/packages/8e/ee/aad2f108d63b769121005302f16bf66db8625c88ceaba466942e09a2607e/coverage-7.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c79cead5b5bc584d9c71451cb984d0e3a84e0c0937379c8efcbf27c8d661b851", size = 257633, upload-time = "2026-05-26T20:40:40.164Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f8/11a2c29b4fd76d9849f81d0bb812ec0017a9396df3217214e38934a8c837/coverage-7.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dcbf65f1f66a26cdd88c35cf68fb4729c5d1cd2e88added72420541dfb212034", size = 251488, upload-time = "2026-05-26T20:40:42.631Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b8/9a5820de4b8ac2b71d85e3b5fb49108d7469c665f0e2ad0dd7569023e305/coverage-7.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fd86572566fb40189a8260446158235159bc7a82dfbc87a3b39cf4fb57fcec1c", size = 253329, upload-time = "2026-05-26T20:40:45.208Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ff/f33e4823667e27548e8fd8df44217515303f9808d0ff29817db56f87d990/coverage-7.14.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:7771b601718fdde84832c3a434ca9bbf4ae9adbc49d84198b4110700c3c77c36", size = 251291, upload-time = "2026-05-26T20:40:47.502Z" }, + { url = "https://files.pythonhosted.org/packages/68/9b/489db0ebb209054766b90a9014a45f6d26eb724c02ec21311c3733b5a644/coverage-7.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:39b21e212c55af06fa375e3dbf90a8a8e38792f3a910c580066d23563830ddd5", size = 255564, upload-time = "2026-05-26T20:40:49.372Z" }, + { url = "https://files.pythonhosted.org/packages/27/b5/16bc2d4c2409b23c7737edb68c83bc89e345f378050549fe1d75ac7d34d5/coverage-7.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f2302660e32562a532b442480121aef8aa61a5bdb20b30bf0adab29f10a5a4b4", size = 251107, upload-time = "2026-05-26T20:40:51.677Z" }, + { url = "https://files.pythonhosted.org/packages/7d/0c/2629997469a00cd069d588a41c9dc887610f2775ae89d250c4791e65272a/coverage-7.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03a6f93c1ec3b7f2e77b5dbcc5573a2c21f12529a5c6bbe0f16f72303cc2fa4d", size = 252764, upload-time = "2026-05-26T20:40:54.267Z" }, + { url = "https://files.pythonhosted.org/packages/d2/ee/f78d63c8f079e0d7211c7e2401fa17e311514534ba61bae03e4b287ce4ab/coverage-7.14.1-cp314-cp314-win32.whl", hash = "sha256:8a3ce026d73290f42f08dafecbd82c193a74df280461fbf97300fec51fd133ee", size = 222837, upload-time = "2026-05-26T20:40:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b9/be539854f93a70dfbeec69117f33ec70dc42ff0b65b5b07ab8d40d04228e/coverage-7.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:114c95ef29302423b87d159075805f4ab973254a2638a5d7d046c94887cc87d7", size = 223650, upload-time = "2026-05-26T20:40:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9e/24e2842fef40f35ac82ba3a7719c8023d011bf3bf652d0675316a9d088a1/coverage-7.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:a07891c3f4805442b31b71e84ba3cf29ed1aa9a428284e06deeb4b23e5b46343", size = 222218, upload-time = "2026-05-26T20:41:00.321Z" }, + { url = "https://files.pythonhosted.org/packages/0a/1d/ac0a9df5fe31c1e8bdd658074905fc12844a05c1a7e3fdb8417e97c31e23/coverage-7.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1101a5ebb083aecb625ebb6209d4105b58f647b093cb2dc8122d7b33f743cfe1", size = 220822, upload-time = "2026-05-26T20:41:02.281Z" }, + { url = "https://files.pythonhosted.org/packages/32/cf/f964fd9aff20323f9f1a726c97135f8a76bcd87b92dad141a456a43f3c64/coverage-7.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:851b9e1e4e8a4608e77c79714b2e77c0970d2ed7202a05e92ae407817481887b", size = 221084, upload-time = "2026-05-26T20:41:04.593Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5e/7e5ef2aba844de2b80d678619fcf0841b42e3f37f16411226f3fe4c1016f/coverage-7.14.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d5b89cdfb2ee051b71e8c3c70bd81a9eff81100f736a269136fe1a68efe00474", size = 262454, upload-time = "2026-05-26T20:41:06.641Z" }, + { url = "https://files.pythonhosted.org/packages/64/62/75809bded87015cc4935524218a2a8ed8dd1a8498bfed30a2f4f7a4b4d34/coverage-7.14.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0177614a0370f227888b4e436a7c55686d6a9f90eb1ade2b624ba685a1686e86", size = 264578, upload-time = "2026-05-26T20:41:08.556Z" }, + { url = "https://files.pythonhosted.org/packages/f3/42/d33392dc14633525012d2d504fa1a33b05538bf535f5c1d64675e5754b78/coverage-7.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2d69af5dea2de76fc485a83032a630523f985198b7e25be901ec60181587b01e", size = 266981, upload-time = "2026-05-26T20:41:10.824Z" }, + { url = "https://files.pythonhosted.org/packages/2a/49/0157c4428c2aca7f1e09d5565930586fd5ae36f1655f08b0daa7cf1fcae1/coverage-7.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:35ab22d91de736e8966b980dc355cbcdd2c6dbbcfe275f9a2991bc8a91b3df65", size = 268112, upload-time = "2026-05-26T20:41:12.966Z" }, + { url = "https://files.pythonhosted.org/packages/96/26/86b9ce71f4092b1ed325ce1421698081df1286b833400b6836912834d6e0/coverage-7.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:357d4e32935c36588aaba057d734fa32428c360c9fc2e4442afbf1b646beee6e", size = 261558, upload-time = "2026-05-26T20:41:15Z" }, + { url = "https://files.pythonhosted.org/packages/20/4c/c311210c5472cf5401d8422b0d7812cdd520f24417673afabda6c323faca/coverage-7.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:51bd64741cc6fa065abd300ede1afe5a5291ece9c31da8b24884deda48bcc3f8", size = 264447, upload-time = "2026-05-26T20:41:17.369Z" }, + { url = "https://files.pythonhosted.org/packages/fb/71/59513f8710ed3e6b0ac0a050a5b7e977bb9c9e880354863b5d00d8809256/coverage-7.14.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:9132cd363a68a4c3daa7c8704a654b1e39d3360f6f5b8ddd470608a945236c07", size = 262048, upload-time = "2026-05-26T20:41:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/84/8d/bceed32dc494f5bbf50f775cd2e78ca814953942b5ea28d3c1c3ac316f14/coverage-7.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:07c6290b1697b862c0478eab545eec949a0d0e4d6d03497f446d706da3b4f2de", size = 265781, upload-time = "2026-05-26T20:41:21.559Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c5/9348fe40dbfd4991aaf78df2c6c3098bfb2cc834d1fd362a64b4efef855a/coverage-7.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5ea0c297e27133853b4d8a3eb799bff5a2dbd9f2f41537a240d337ac9b4df890", size = 260896, upload-time = "2026-05-26T20:41:23.428Z" }, + { url = "https://files.pythonhosted.org/packages/ca/92/1ea0f03929da7cf87206b1fa24f4c8e9c158be0455481af29ec0a1f3503f/coverage-7.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:01b7733daad0237daa01ef80fe2dfceffc911e6a17fa7b55d14aa8214eaaaecd", size = 263214, upload-time = "2026-05-26T20:41:25.419Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a9/b2493c054c0e01a643266742ab45e15744e60743f9260cd930c7142b1124/coverage-7.14.1-cp314-cp314t-win32.whl", hash = "sha256:6adc5a36984624a70bf11d7184e20fa0a49aa7c47ffab43804106a1a695ea22e", size = 223624, upload-time = "2026-05-26T20:41:27.795Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bd/3e1e6a57fccd2d7c83fcdf338e93ba98eb85c6e877dd34731ac585375490/coverage-7.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:ddf799247318f34dbcd2efa8c95a8d0642674e926bb1774cf9b63dfd2a389d1c", size = 224728, upload-time = "2026-05-26T20:41:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d7/31066cf1d2f0c6c797fce911bcfa01dd35642dc6da992a950256097c5860/coverage-7.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:145986fe66647eb489f18d9a997567a3fd358584c4b5a808769113abc07466af", size = 222752, upload-time = "2026-05-26T20:41:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3c/1a983b9a745d7f83d53f057bcc5bf79ba6a2bbc08266b3f0c7d6fe630c9b/coverage-7.14.1-py3-none-any.whl", hash = "sha256:a252f21c27e38347e60111a3266b03827422a7d5525951aceee313aa68bab1d2", size = 211815, upload-time = "2026-05-26T20:41:34.078Z" }, +] + +[package.optional-dependencies] +toml = [ + { name = "tomli", marker = "python_full_version <= '3.11'" }, +] + +[[package]] +name = "dependency-groups" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/55/f054de99871e7beb81935dea8a10b90cd5ce42122b1c3081d5282fdb3621/dependency_groups-1.3.1.tar.gz", hash = "sha256:78078301090517fd938c19f64a53ce98c32834dfe0dee6b88004a569a6adfefd", size = 10093, upload-time = "2025-05-02T00:34:29.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/c7/d1ec24fb280caa5a79b6b950db565dab30210a66259d17d5bb2b3a9f878d/dependency_groups-1.3.1-py3-none-any.whl", hash = "sha256:51aeaa0dfad72430fcfb7bcdbefbd75f3792e5919563077f30bc0d73f4493030", size = 8664, upload-time = "2025-05-02T00:34:27.085Z" }, +] + +[[package]] +name = "distlib" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/86/b2/d6fc3f2347f43dada79e5ff118493e8109c98400a0e29a1d5264a3aa479b/distlib-0.4.1.tar.gz", hash = "sha256:c3804d0d2d4b5fcd44036eb860cb6660485fcdf5c2aba53dc324d805837ea65b", size = 610526, upload-time = "2026-06-02T11:17:40.691Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/18/3497c4fa83a76dcb154923fd2075522e8dd6995ecee4093c00ae18160046/distlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:9c2c552c68cbadc619f2d0ed3a69e27c351a3f4c9baa9ffb7df9e9cdc3d19a97", size = 469216, upload-time = "2026-06-02T11:17:38.779Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "filelock" +version = "3.29.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/f9/f38573ed5844586db374d085911740a501ccfa373b455fc9413f09f85237/filelock-3.29.1.tar.gz", hash = "sha256:d97e6b1b9757569626c58caa07dc4beb1613f4a2938b1e8cc81afca398906c9e", size = 59335, upload-time = "2026-06-03T15:19:04.053Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/a0/614c5fe402fd88951df45f4dda2fa3b4e17a99ecd92340771929169b3b95/filelock-3.29.1-py3-none-any.whl", hash = "sha256:85199dfd706869641b72b2e8955d5416a4b2b7dc4b0e8e6d97b4cc1299a6983b", size = 40750, upload-time = "2026-06-03T15:19:02.959Z" }, +] + +[[package]] +name = "flake8" +version = "7.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mccabe" }, + { name = "pycodestyle" }, + { name = "pyflakes" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, +] + +[[package]] +name = "ghp-import" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/29/d40217cbe2f6b1359e00c6c307bb3fc876ba74068cbab3dde77f03ca0dc4/ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343", size = 10943, upload-time = "2022-05-02T15:47:16.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, +] + +[[package]] +name = "griffe" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffecli" }, + { name = "griffelib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/49/eb6d2935e27883af92c930ed40cc4c69bcd32c402be43b8ca4ab20510f67/griffe-2.0.2.tar.gz", hash = "sha256:c5d56326d159f274492e9bf93a9895cec101155d944caa66d0fc4e0c13751b92", size = 293757, upload-time = "2026-03-27T11:34:52.205Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/c0/2bb018eecf9a83c68db9cd9fffd9dab25f102ad30ed869451046e46d1187/griffe-2.0.2-py3-none-any.whl", hash = "sha256:2b31816460aee1996af26050a1fc6927a2e5936486856707f55508e4c9b5960b", size = 5141, upload-time = "2026-03-27T11:34:47.721Z" }, +] + +[[package]] +name = "griffecli" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, + { name = "griffelib" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/e0/6a7d661d71bb043656a109b91d84a42b5342752542074ec83b16a6eb97f0/griffecli-2.0.2.tar.gz", hash = "sha256:40a1ad4181fc39685d025e119ae2c5b669acdc1f19b705fb9bf971f4e6f6dffb", size = 56281, upload-time = "2026-03-27T11:34:50.087Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/e8/90d93356c88ac34c20cb5edffca68138df55ca9bbd1a06eccfbcec8fdbe5/griffecli-2.0.2-py3-none-any.whl", hash = "sha256:0d44d39e59afa81e288a3e1c3bf352cc4fa537483326ac06b8bb6a51fd8303a0", size = 9500, upload-time = "2026-03-27T11:34:48.81Z" }, +] + +[[package]] +name = "griffelib" +version = "2.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/82/74f4a3310cdabfbb10da554c3a672847f1ed33c6f61dd472681ce7f1fe67/griffelib-2.0.2.tar.gz", hash = "sha256:3cf20b3bc470e83763ffbf236e0076b1211bac1bc67de13daf494640f2de707e", size = 166461, upload-time = "2026-03-27T11:34:51.091Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/8c/c9138d881c79aa0ea9ed83cbd58d5ca75624378b38cee225dcf5c42cc91f/griffelib-2.0.2-py3-none-any.whl", hash = "sha256:925c857658fb1ba40c0772c37acbc2ab650bd794d9c1b9726922e36ea4117ea1", size = 142357, upload-time = "2026-03-27T11:34:46.275Z" }, +] + +[[package]] +name = "herepy" +version = "3.6.5" +source = { editable = "." } +dependencies = [ + { name = "requests" }, +] + +[package.dev-dependencies] +dev = [ + { name = "codecov" }, + { name = "flake8" }, + { name = "mypy" }, + { name = "nox" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-runner" }, + { name = "responses" }, + { name = "ruff" }, + { name = "tox" }, + { name = "tox-pyenv" }, +] +docs = [ + { name = "livereload" }, + { name = "markdown-include" }, + { name = "mkdocs" }, + { name = "mkdocs-material" }, + { name = "mkdocstrings" }, + { name = "mkdocstrings-python" }, +] + +[package.metadata] +requires-dist = [{ name = "requests", specifier = ">=2.25.1,<3" }] + +[package.metadata.requires-dev] +dev = [ + { name = "codecov", specifier = "==2.1.13" }, + { name = "flake8" }, + { name = "mypy", specifier = ">=2.1.0" }, + { name = "nox", specifier = ">=2026.4.10" }, + { name = "pytest", specifier = "==8.1.1" }, + { name = "pytest-cov", specifier = "==5.0.0" }, + { name = "pytest-runner", specifier = "==6.0.1" }, + { name = "responses", specifier = "==0.25.0" }, + { name = "ruff", specifier = ">=0.15.16" }, + { name = "tox", specifier = "==4.14.2" }, + { name = "tox-pyenv", specifier = "==1.1.0" }, +] +docs = [ + { name = "livereload" }, + { name = "markdown-include", specifier = "==0.8.1" }, + { name = "mkdocs", specifier = "==1.6.1" }, + { name = "mkdocs-material", specifier = "==9.5.42" }, + { name = "mkdocstrings", specifier = "==0.26.2" }, + { name = "mkdocstrings-python", specifier = "==1.12.2" }, +] + +[[package]] +name = "humanize" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/66/a3921783d54be8a6870ac4ccffcd15c4dc0dd7fcce51c6d63b8c63935276/humanize-4.15.0.tar.gz", hash = "sha256:1dd098483eb1c7ee8e32eb2e99ad1910baefa4b75c3aff3a82f4d78688993b10", size = 83599, upload-time = "2025-12-20T20:16:13.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/7b/bca5613a0c3b542420cf92bd5e5fb8ebd5435ce1011a091f66bb7693285e/humanize-4.15.0-py3-none-any.whl", hash = "sha256:b1186eb9f5a9749cd9cb8565aee77919dd7c8d076161cf44d70e59e3301e1769", size = 132203, upload-time = "2025-12-20T20:16:11.67Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "librt" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/08/9e7f6b5d2b5bed6ad055cdd5925f192bb403a51280f86b56554d9d0699a2/librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1", size = 200139, upload-time = "2026-05-10T18:17:25.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/10/37fd9e9ba96cb0bd742dfb20fc3d082e54bdbec759d7300df927f360ef07/librt-0.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6e94ebfcfa2d5e9926d6c3b9aa4617ffc42a845b4321fb84021b872358c82a0f", size = 141706, upload-time = "2026-05-10T18:15:16.129Z" }, + { url = "https://files.pythonhosted.org/packages/cf/72/1b1466f358e4a0b728051f69bc27e67b432c6eaa2e05b88db49d3785ae0d/librt-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae627397a2f351560440d872d6f7c8dbb4072e57868e7b2fc5b8b430fe489d45", size = 142605, upload-time = "2026-05-10T18:15:18.148Z" }, + { url = "https://files.pythonhosted.org/packages/ca/85/ed26dd2f6bc9a0baf48306433e579e8d354d70b2bcb78134ed950a5d0e1e/librt-0.11.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc329359321b67d24efdf4bc69012b0597001649544db662c001db5a0184794c", size = 476555, upload-time = "2026-05-10T18:15:19.569Z" }, + { url = "https://files.pythonhosted.org/packages/66/fe/11891191c0e0a3fd617724e891f6e67a71a7658974a892b9a9a97fdb2977/librt-0.11.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:7e82e642ab0f7608ce2fe53d76ca2280a9ee33a1b06556142c7c6fe80a86fc33", size = 468434, upload-time = "2026-05-10T18:15:20.87Z" }, + { url = "https://files.pythonhosted.org/packages/6f/50/5ec949d7f9ce1a07af903aa3e13abb98b717923bdead6e719b2f824ccc07/librt-0.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88145c15c67731d54283d135b03244028c750cc9edc334a96a4f5950ebdb2884", size = 496918, upload-time = "2026-05-10T18:15:22.616Z" }, + { url = "https://files.pythonhosted.org/packages/ea/c4/177336c7524e34875a38bf668e88b193a6723a4eb4045d07f74df6e1506c/librt-0.11.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d36a51b3d93320b686588e27123f4995804dbf1bce81df78c02fc3c6eea9280", size = 490334, upload-time = "2026-05-10T18:15:24.2Z" }, + { url = "https://files.pythonhosted.org/packages/13/1f/da3112f7569eda3b49f9a2629bae1fe059812b6085df16c885f6454dff49/librt-0.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3ac06a2a8b246327f11e186a53a100a4d5c7ed52346367e5ec751d51586c", size = 511287, upload-time = "2026-05-10T18:15:26.226Z" }, + { url = "https://files.pythonhosted.org/packages/fa/94/03fec301522e172d105581431223be56b27594ff46440ebfbb658a3735d5/librt-0.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:461bbceede621f1ffb8839755f8663e886087ee7af16294cab7fb4d782c62eeb", size = 517202, upload-time = "2026-05-10T18:15:27.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/6e/339f6e5a7b413ce014f1917a756dae630fe59cc99f34153205b1cb540901/librt-0.11.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0cad8a4d6a8ff03c9b76f9414caccd78e7cfbc8a2e12fa334d8e1d9932753783", size = 497517, upload-time = "2026-05-10T18:15:29.614Z" }, + { url = "https://files.pythonhosted.org/packages/cd/43/acdd5ce317cb46e8253ca9bfbdb8b12e68a24d745949336a7f3d5fb79ba0/librt-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f37aa505b3cf60701562eddb32df74b12a9e380c207fd8b06dd157a943ac7ea0", size = 538878, upload-time = "2026-05-10T18:15:30.928Z" }, + { url = "https://files.pythonhosted.org/packages/29/b5/7a25bb12e3172839f647f196b3e988318b7bb1ca7501732a225c4dce2ec0/librt-0.11.0-cp310-cp310-win32.whl", hash = "sha256:94663a21534637f0e787ec2a2a756022df6e5b7b2335a5cdd7d8e33d68a2af89", size = 100070, upload-time = "2026-05-10T18:15:32.551Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0d/ebbcf4d77999c02c937b05d2b90ff4cd4dcc7e9a365ba132329ac1fe7a0f/librt-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:dec7db73758c2b54953fd8b7fe348c45188fe26b39ee18446196edd08453a5d4", size = 117918, upload-time = "2026-05-10T18:15:33.678Z" }, + { url = "https://files.pythonhosted.org/packages/fe/87/2bf31fe17587b29e3f93ec31421e2b1e1c3e349b8bf6c7c313dbad1d5340/librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29", size = 141092, upload-time = "2026-05-10T18:15:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/cf/08/5c5bf772920b7ebac6e32bc91a643e0ab3870199c0b542356d3baa83970a/librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9", size = 142035, upload-time = "2026-05-10T18:15:36.242Z" }, + { url = "https://files.pythonhosted.org/packages/06/20/662a03d254e5b000d838e8b345d83303ddb768c080fd488e40634c0fa66b/librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5", size = 475022, upload-time = "2026-05-10T18:15:37.56Z" }, + { url = "https://files.pythonhosted.org/packages/de/f3/aa81523e45184c6ec23dc7f63263362ec55f80a09d424c012359ecbe7e35/librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b", size = 467273, upload-time = "2026-05-10T18:15:39.182Z" }, + { url = "https://files.pythonhosted.org/packages/6b/6f/59c74b560ca8853834d5501d589c8a2519f4184f273a085ffd0f37a1cc47/librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89", size = 497083, upload-time = "2026-05-10T18:15:40.634Z" }, + { url = "https://files.pythonhosted.org/packages/fe/7b/5aa4d2c9600a719401160bf7055417df0b2a47439b9d88286ce45e56b65f/librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc", size = 489139, upload-time = "2026-05-10T18:15:41.934Z" }, + { url = "https://files.pythonhosted.org/packages/d6/31/9143803d7da6856a69153785768c4936864430eec0fd9461c3ea527d9922/librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5", size = 508442, upload-time = "2026-05-10T18:15:43.206Z" }, + { url = "https://files.pythonhosted.org/packages/2f/5a/bce08184488426bda4ccc2c4964ac048c8f68ae89bd7120082eef4233cfd/librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7", size = 514230, upload-time = "2026-05-10T18:15:44.761Z" }, + { url = "https://files.pythonhosted.org/packages/89/8c/bb5e213d254b7505a0e658da199d8ab719086632ce09eef311ab27976523/librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d", size = 494231, upload-time = "2026-05-10T18:15:46.308Z" }, + { url = "https://files.pythonhosted.org/packages/9d/fb/541cdad5b1ab1300398c74c4c9a497b88e5074c21b1244c8f49731d3a284/librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412", size = 537585, upload-time = "2026-05-10T18:15:47.629Z" }, + { url = "https://files.pythonhosted.org/packages/8f/f2/464bb69295c320cb06bddb4f14a4ec67934ee14b2bffb12b19fb7ab287ba/librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d", size = 100509, upload-time = "2026-05-10T18:15:49.157Z" }, + { url = "https://files.pythonhosted.org/packages/6d/e7/a17ee1788f9e4fbf548c19f4afa07c92089b9e24fef6cb2410863781ef4c/librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73", size = 118628, upload-time = "2026-05-10T18:15:50.345Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c7/6c766214f9f9903bcfcfbef97d807af8d8f5aa3502d247858ab17582d212/librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c", size = 103122, upload-time = "2026-05-10T18:15:52.068Z" }, + { url = "https://files.pythonhosted.org/packages/8b/d0/07c77e067f0838949b43bd89232c29d72efebb9d2801a9750184eb706b71/librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46", size = 144147, upload-time = "2026-05-10T18:15:53.227Z" }, + { url = "https://files.pythonhosted.org/packages/7a/24/8493538fa4f62f982686398a5b8f68008138a75086abdea19ade64bf4255/librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3", size = 143614, upload-time = "2026-05-10T18:15:54.657Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1e/f8bad050810d9171f34a1648ed910e56814c2ba61639f2bd53c6377ae24b/librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67", size = 485538, upload-time = "2026-05-10T18:15:56.117Z" }, + { url = "https://files.pythonhosted.org/packages/c0/fe/3594ebfbaf03084ba4b120c9ba5c3183fd938a48725e9bbe6ff0a5159ad8/librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a", size = 479623, upload-time = "2026-05-10T18:15:57.544Z" }, + { url = "https://files.pythonhosted.org/packages/b0/da/5d1876984b3746c85dbd219dbfcb73c85f54ee263fd32e5b2a632ec14571/librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a", size = 513082, upload-time = "2026-05-10T18:15:58.805Z" }, + { url = "https://files.pythonhosted.org/packages/19/6e/55bdf5d5ca00c3e18430690bf2c953d8d3ffd3c337418173d33dec985dc9/librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f", size = 508105, upload-time = "2026-05-10T18:16:00.2Z" }, + { url = "https://files.pythonhosted.org/packages/07/10/f1f23a7c595ee90ece4d35c851e5d104b1311a887ed1b4ac4c35bbd13da8/librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b", size = 522268, upload-time = "2026-05-10T18:16:01.708Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/5720f5697a7f54b78b3aefbe20df3a48cedcff1276618c4aa481177942ed/librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766", size = 527348, upload-time = "2026-05-10T18:16:03.496Z" }, + { url = "https://files.pythonhosted.org/packages/50/db/b4a47c6f91db4ff76348a0b3dd0cc65e090a078b765a810a62ff9434c3d3/librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d", size = 516294, upload-time = "2026-05-10T18:16:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/9e/58/9384b2f4eb1ed1d273d40948a7c5c4b2360213b402ef3be4641c06299f9c/librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8", size = 553608, upload-time = "2026-05-10T18:16:06.839Z" }, + { url = "https://files.pythonhosted.org/packages/21/7b/5aa8848a7c6a9278c79375146da1812e695754ceec5f005e6043461a7315/librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a", size = 101879, upload-time = "2026-05-10T18:16:08.103Z" }, + { url = "https://files.pythonhosted.org/packages/37/33/8a745436944947575b584231750a41417de1a38cf6a2e9251d1065651c09/librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9", size = 119831, upload-time = "2026-05-10T18:16:09.174Z" }, + { url = "https://files.pythonhosted.org/packages/59/67/a6739ac96e28b7855808bdb0370e250606104a859750d209e5a0716fe7ab/librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c", size = 103470, upload-time = "2026-05-10T18:16:10.369Z" }, + { url = "https://files.pythonhosted.org/packages/82/61/e59168d4d0bf2bf90f4f0caf7a001bfc60254c3af4586013b04dc3ef517b/librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894", size = 144119, upload-time = "2026-05-10T18:16:11.771Z" }, + { url = "https://files.pythonhosted.org/packages/61/fd/caa1d60b12f7dd79ccea23054e06eeaebe266a5f52c40a6b651069200ce5/librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c", size = 143565, upload-time = "2026-05-10T18:16:13.334Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/dc744f5c2b4978d48db970be29f22716d3413d28b14ad99740817315cf2c/librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea", size = 485395, upload-time = "2026-05-10T18:16:14.729Z" }, + { url = "https://files.pythonhosted.org/packages/8f/21/7f8e97a1e4dae952a5a95948f6f8507a173bc1e669f54340bba6ca1ca31b/librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230", size = 479383, upload-time = "2026-05-10T18:16:16.321Z" }, + { url = "https://files.pythonhosted.org/packages/a6/6d/d8ee9c114bebf2c50e29ec2aa940826fccb62a645c3e4c18760987d0e16d/librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2", size = 513010, upload-time = "2026-05-10T18:16:17.647Z" }, + { url = "https://files.pythonhosted.org/packages/f0/43/0b5708af2bd30a46400e72ba6bdaa8f066f15fb9a688527e34220e8d6c06/librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3", size = 508433, upload-time = "2026-05-10T18:16:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/4a/50/356187247d09013490481033183b3532b58acf8028bcb34b2b56a375c9b2/librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21", size = 522595, upload-time = "2026-05-10T18:16:20.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/c6ac4240899c7f3248079d5a9900debe0dadb3fdeaf856684c987105ba47/librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930", size = 527255, upload-time = "2026-05-10T18:16:22.352Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b5/a81322dbeedeeaf9c1ee6f001734d28a09d8383ac9e6779bc24bbd0743c6/librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be", size = 516847, upload-time = "2026-05-10T18:16:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/66/6e6323787d592b55204a42595ff1102da5115601b53a7e9ddebc889a6da5/librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e", size = 553920, upload-time = "2026-05-10T18:16:25.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/21/623f8ca230857102066d9ca8c6c1734995908c4d0d1bee7bb2ef0021cb33/librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e", size = 101898, upload-time = "2026-05-10T18:16:26.649Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1d/b4ebd44dd723f768469007515cb92251e0ae286c94c140f374801140fa74/librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47", size = 119812, upload-time = "2026-05-10T18:16:27.859Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e4/b2f4ca7965ca373b491cdb4bc25cdb30c1649ca81a8782056a83850292a9/librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44", size = 103448, upload-time = "2026-05-10T18:16:29.066Z" }, + { url = "https://files.pythonhosted.org/packages/29/eb/dbce197da4e227779e56b5735f2decc3eb36e55a1cdbf1bd65d6639d76c1/librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd", size = 143345, upload-time = "2026-05-10T18:16:30.674Z" }, + { url = "https://files.pythonhosted.org/packages/76/a3/254bebd0c11c8ba684018efb8006ff22e466abce445215cca6c778e7d9de/librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4", size = 143131, upload-time = "2026-05-10T18:16:32.037Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3f/f77d6122d21ac7bf6ae8a7dfced1bd2a7ac545d3273ebdcaf8042f6d619f/librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8", size = 477024, upload-time = "2026-05-10T18:16:33.493Z" }, + { url = "https://files.pythonhosted.org/packages/ac/0a/2c996dadebaa7d9bbbd43ef2d4f3e66b6da545f838a41694ef6172cebec8/librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b", size = 474221, upload-time = "2026-05-10T18:16:34.864Z" }, + { url = "https://files.pythonhosted.org/packages/0a/7e/f5d92af8486b8272c23b3e686b46ff72d89c8169585eb61eef01a2ac7147/librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175", size = 505174, upload-time = "2026-05-10T18:16:36.705Z" }, + { url = "https://files.pythonhosted.org/packages/af/1a/cb0734fe86398eb33193ab753b7326255c74cac5eb09e76b9b16536e7adb/librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03", size = 497216, upload-time = "2026-05-10T18:16:38.418Z" }, + { url = "https://files.pythonhosted.org/packages/18/06/094820f91558b66e29943c0ec41c9914f460f48dd51fc503c3101e10842d/librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c", size = 513921, upload-time = "2026-05-10T18:16:39.848Z" }, + { url = "https://files.pythonhosted.org/packages/0b/c2/00de9018871a282f530cacb457d5ec0428f6ac7e6fedde9aff7468d9fb04/librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3", size = 520850, upload-time = "2026-05-10T18:16:41.471Z" }, + { url = "https://files.pythonhosted.org/packages/51/9d/64631832348fd1834fb3a61b996434edddaaf25a31d03b0a76273159d2cf/librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96", size = 504237, upload-time = "2026-05-10T18:16:43.15Z" }, + { url = "https://files.pythonhosted.org/packages/a5/ec/ae5525eb16edc827a044e7bb8777a455ff95d4bca9379e7e6bddd7383647/librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe", size = 546261, upload-time = "2026-05-10T18:16:44.408Z" }, + { url = "https://files.pythonhosted.org/packages/5a/09/adce371f27ca039411da9659f7430fcc2ba6cd0c7b3e4467a0f091be7fa9/librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f", size = 96965, upload-time = "2026-05-10T18:16:46.039Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ee/8ac720d98548f173c7ce2e632a7ca94673f74cacd5c8162a84af5b35958a/librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7", size = 115151, upload-time = "2026-05-10T18:16:47.133Z" }, + { url = "https://files.pythonhosted.org/packages/94/20/c900cf14efeb09b6bef2b2dff20779f73464b97fd58d1c6bccc379588ae3/librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1", size = 98850, upload-time = "2026-05-10T18:16:48.597Z" }, + { url = "https://files.pythonhosted.org/packages/0c/71/944bfe4b64e12abffcd3c15e1cce07f72f3d55655083786285f4dedeb532/librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72", size = 151138, upload-time = "2026-05-10T18:16:49.839Z" }, + { url = "https://files.pythonhosted.org/packages/b6/10/99e64a5c86989357fda078c8143c533389585f6473b7439172dd8f3b3b2d/librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa", size = 151976, upload-time = "2026-05-10T18:16:51.062Z" }, + { url = "https://files.pythonhosted.org/packages/21/31/5072ad880946d83e5ea4147d6d018c78eefce85b77819b19bdd0ee229435/librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548", size = 557927, upload-time = "2026-05-10T18:16:52.632Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8d/70b5fb7cfbab60edbe7381614ab985da58e144fbf465c86d44c95f43cdca/librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2", size = 539698, upload-time = "2026-05-10T18:16:53.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a3/ba3495a0b3edbd24a4cae0d1d3c64f39a9fc45d06e812101289b50c1a619/librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f", size = 577162, upload-time = "2026-05-10T18:16:55.589Z" }, + { url = "https://files.pythonhosted.org/packages/f7/db/36e25fb81f99937ff1b96612a1dc9fd66f039cb9cc3aee12c01fac31aab9/librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51", size = 566494, upload-time = "2026-05-10T18:16:56.975Z" }, + { url = "https://files.pythonhosted.org/packages/33/0d/3f622b47f0b013eeb9cf4cc07ae9bfe378d832a4eec998b2b209fe84244d/librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2", size = 596858, upload-time = "2026-05-10T18:16:58.374Z" }, + { url = "https://files.pythonhosted.org/packages/a9/02/71b90bc93039c46a2000651f6ad60122b114c8f54c4ad306e0e96f5b75ad/librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085", size = 590318, upload-time = "2026-05-10T18:16:59.676Z" }, + { url = "https://files.pythonhosted.org/packages/04/04/418cb3f75621e2b761fb1ab0f017f4d70a1a72a6e7c74ee4f7e8d198c2f3/librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3", size = 575115, upload-time = "2026-05-10T18:17:01.007Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2c/5a2183ac58dd911f26b5d7e7d7d8f1d87fcecdddd99d6c12169a258ff62c/librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd", size = 617918, upload-time = "2026-05-10T18:17:02.682Z" }, + { url = "https://files.pythonhosted.org/packages/15/1f/dc6771a52592a4451be6effa200cbfc9cec61e4393d3033d81a9d307961d/librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8", size = 103562, upload-time = "2026-05-10T18:17:03.99Z" }, + { url = "https://files.pythonhosted.org/packages/62/4a/7d1415567027286a75ba1093ec4aca11f073e0f559c530cf3e0a757ad55c/librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c", size = 124327, upload-time = "2026-05-10T18:17:05.465Z" }, + { url = "https://files.pythonhosted.org/packages/ce/62/b40b382fa0c66fee1478073eb8db352a4a6beda4a1adccf1df911d8c289c/librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253", size = 102572, upload-time = "2026-05-10T18:17:06.809Z" }, +] + +[[package]] +name = "livereload" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tornado" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/6e/f2748665839812a9bbe5c75d3f983edbf3ab05fa5cd2f7c2f36fffdf65bd/livereload-2.7.1.tar.gz", hash = "sha256:3d9bf7c05673df06e32bea23b494b8d36ca6d10f7d5c3c8a6989608c09c986a9", size = 22255, upload-time = "2024-12-18T13:42:01.461Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/3e/de54dc7f199e85e6ca37e2e5dae2ec3bce2151e9e28f8eb9076d71e83d56/livereload-2.7.1-py3-none-any.whl", hash = "sha256:5201740078c1b9433f4b2ba22cd2729a39b9d0ec0a2cc6b4d3df257df5ad0564", size = 22657, upload-time = "2024-12-18T13:41:56.35Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", size = 368805, upload-time = "2026-02-09T14:57:26.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36", size = 108180, upload-time = "2026-02-09T14:57:25.787Z" }, +] + +[[package]] +name = "markdown-include" +version = "0.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/d8/66bf162fe6c1adb619f94a6da599323eecacf15b6d57469d0fd0421c10df/markdown-include-0.8.1.tar.gz", hash = "sha256:1d0623e0fc2757c38d35df53752768356162284259d259c486b4ab6285cdbbe3", size = 21873, upload-time = "2023-02-07T09:47:26.608Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/e2/c4d20b21a05fe0fee571649cebc05f7f72e80b1a743f932e7326125e6c9e/markdown_include-0.8.1-py3-none-any.whl", hash = "sha256:32f0635b9cfef46997b307e2430022852529f7a5b87c0075c504283e7cc7db53", size = 18837, upload-time = "2023-02-07T09:47:25.03Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/08/db/fefacb2136439fc8dd20e797950e749aa1f4997ed584c62cfb8ef7c2be0e/markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad", size = 11631, upload-time = "2025-09-27T18:36:18.185Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2e/5898933336b61975ce9dc04decbc0a7f2fee78c30353c5efba7f2d6ff27a/markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a", size = 12058, upload-time = "2025-09-27T18:36:19.444Z" }, + { url = "https://files.pythonhosted.org/packages/1d/09/adf2df3699d87d1d8184038df46a9c80d78c0148492323f4693df54e17bb/markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50", size = 24287, upload-time = "2025-09-27T18:36:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/30/ac/0273f6fcb5f42e314c6d8cd99effae6a5354604d461b8d392b5ec9530a54/markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf", size = 22940, upload-time = "2025-09-27T18:36:22.249Z" }, + { url = "https://files.pythonhosted.org/packages/19/ae/31c1be199ef767124c042c6c3e904da327a2f7f0cd63a0337e1eca2967a8/markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f", size = 21887, upload-time = "2025-09-27T18:36:23.535Z" }, + { url = "https://files.pythonhosted.org/packages/b2/76/7edcab99d5349a4532a459e1fe64f0b0467a3365056ae550d3bcf3f79e1e/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a", size = 23692, upload-time = "2025-09-27T18:36:24.823Z" }, + { url = "https://files.pythonhosted.org/packages/a4/28/6e74cdd26d7514849143d69f0bf2399f929c37dc2b31e6829fd2045b2765/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115", size = 21471, upload-time = "2025-09-27T18:36:25.95Z" }, + { url = "https://files.pythonhosted.org/packages/62/7e/a145f36a5c2945673e590850a6f8014318d5577ed7e5920a4b3448e0865d/markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a", size = 22923, upload-time = "2025-09-27T18:36:27.109Z" }, + { url = "https://files.pythonhosted.org/packages/0f/62/d9c46a7f5c9adbeeeda52f5b8d802e1094e9717705a645efc71b0913a0a8/markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19", size = 14572, upload-time = "2025-09-27T18:36:28.045Z" }, + { url = "https://files.pythonhosted.org/packages/83/8a/4414c03d3f891739326e1783338e48fb49781cc915b2e0ee052aa490d586/markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01", size = 15077, upload-time = "2025-09-27T18:36:29.025Z" }, + { url = "https://files.pythonhosted.org/packages/35/73/893072b42e6862f319b5207adc9ae06070f095b358655f077f69a35601f0/markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c", size = 13876, upload-time = "2025-09-27T18:36:29.954Z" }, + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/41/580bb4006e3ed0361b8151a01d324fb03f420815446c7def45d02f74c270/mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8", size = 4661, upload-time = "2021-02-05T18:55:30.623Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/19/04f9b178c2d8a15b076c8b5140708fa6ffc5601fb6f1e975537072df5b2a/mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307", size = 6354, upload-time = "2021-02-05T18:55:29.583Z" }, +] + +[[package]] +name = "mkdocs" +version = "1.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "ghp-import" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mergedeep" }, + { name = "mkdocs-get-deps" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "pyyaml" }, + { name = "pyyaml-env-tag" }, + { name = "watchdog" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/c6/bbd4f061bd16b378247f12953ffcb04786a618ce5e904b8c5a01a0309061/mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2", size = 3889159, upload-time = "2024-08-30T12:24:06.899Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/5b/dbc6a8cddc9cfa9c4971d59fb12bb8d42e161b7e7f8cc89e49137c5b279c/mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e", size = 3864451, upload-time = "2024-08-30T12:24:05.054Z" }, +] + +[[package]] +name = "mkdocs-autorefs" +version = "1.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/c0/f641843de3f612a6b48253f39244165acff36657a91cc903633d456ae1ac/mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197", size = 56588, upload-time = "2026-02-10T15:23:55.105Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/de/a3e710469772c6a89595fc52816da05c1e164b4c866a89e3cb82fb1b67c5/mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089", size = 25530, upload-time = "2026-02-10T15:23:53.817Z" }, +] + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mergedeep" }, + { name = "platformdirs" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/25/b3cccb187655b9393572bde9b09261d267c3bf2f2cdabe347673be5976a6/mkdocs_get_deps-0.2.2.tar.gz", hash = "sha256:8ee8d5f316cdbbb2834bc1df6e69c08fe769a83e040060de26d3c19fad3599a1", size = 11047, upload-time = "2026-03-10T02:46:33.632Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/29/744136411e785c4b0b744d5413e56555265939ab3a104c6a4b719dad33fd/mkdocs_get_deps-0.2.2-py3-none-any.whl", hash = "sha256:e7878cbeac04860b8b5e0ca31d3abad3df9411a75a32cde82f8e44b6c16ff650", size = 9555, upload-time = "2026-03-10T02:46:32.256Z" }, +] + +[[package]] +name = "mkdocs-material" +version = "9.5.42" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "colorama" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "mkdocs" }, + { name = "mkdocs-material-extensions" }, + { name = "paginate" }, + { name = "pygments" }, + { name = "pymdown-extensions" }, + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/33/b3343ed975fbbd6798b8d8a7c4f1bf8489cc321fc8fd426eba3d87b0242e/mkdocs_material-9.5.42.tar.gz", hash = "sha256:92779b5e9b5934540c574c11647131d217dc540dce72b05feeda088c8eb1b8f2", size = 3963891, upload-time = "2024-10-20T08:27:17.404Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/55/ad3e6a60ac1e8e76025543c49c1f24ecd80fb38e8a57000403bf2f0a4293/mkdocs_material-9.5.42-py3-none-any.whl", hash = "sha256:452a7c5d21284b373f36b981a2cbebfff59263feebeede1bc28652e9c5bbe316", size = 8672619, upload-time = "2024-10-20T08:27:14.199Z" }, +] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/9b/9b4c96d6593b2a541e1cb8b34899a6d021d208bb357042823d4d2cabdbe7/mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443", size = 11847, upload-time = "2023-11-22T19:09:45.208Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/54/662a4743aa81d9582ee9339d4ffa3c8fd40a4965e033d77b9da9774d3960/mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31", size = 8728, upload-time = "2023-11-22T19:09:43.465Z" }, +] + +[[package]] +name = "mkdocstrings" +version = "0.26.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "markupsafe" }, + { name = "mkdocs" }, + { name = "mkdocs-autorefs" }, + { name = "platformdirs" }, + { name = "pymdown-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/76/0475d10d27f3384df3a6ddfdf4a4fdfef83766f77cd4e327d905dc956c15/mkdocstrings-0.26.2.tar.gz", hash = "sha256:34a8b50f1e6cfd29546c6c09fbe02154adfb0b361bb758834bf56aa284ba876e", size = 92512, upload-time = "2024-10-12T16:56:52.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/b6/4ee320d7c313da3774eff225875eb278f7e6bb26a9cd8e680b8dbc38fdea/mkdocstrings-0.26.2-py3-none-any.whl", hash = "sha256:1248f3228464f3b8d1a15bd91249ce1701fe3104ac517a5f167a0e01ca850ba5", size = 29716, upload-time = "2024-10-12T16:56:49.746Z" }, +] + +[[package]] +name = "mkdocstrings-python" +version = "1.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mkdocs-autorefs" }, + { name = "mkdocstrings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/23/ec/cb6debe2db77f1ef42b25b21d93b5021474de3037cd82385e586aee72545/mkdocstrings_python-1.12.2.tar.gz", hash = "sha256:7a1760941c0b52a2cd87b960a9e21112ffe52e7df9d0b9583d04d47ed2e186f3", size = 168207, upload-time = "2024-10-19T17:54:41.672Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/c1/ac524e1026d9580cbc654b5d19f5843c8b364a66d30f956372cd09fd2f92/mkdocstrings_python-1.12.2-py3-none-any.whl", hash = "sha256:7f7d40d6db3cb1f5d19dbcd80e3efe4d0ba32b073272c0c0de9de2e604eda62a", size = 111759, upload-time = "2024-10-19T17:54:39.338Z" }, +] + +[[package]] +name = "mypy" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ast-serialize" }, + { name = "librt", marker = "platform_python_implementation != 'PyPy'" }, + { name = "mypy-extensions" }, + { name = "pathspec" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/82/15/cca9d88503549ed6fedeaa1d448cdddd542ee8a490232d732e278036fbf2/mypy-2.1.0.tar.gz", hash = "sha256:81e76ad12c2d804512e9b13240d1588316531bfba07558286078bfbce9613633", size = 3898359, upload-time = "2026-05-11T18:37:36.237Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/71/d351dca3e9b30da2328ee9d445c88b8388072808ebfbc49eb69d30b67749/mypy-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:11a6beb180257a805961aea9ec591bbd0bd17f1e18d35b8456d57aee5bedfedc", size = 14778792, upload-time = "2026-05-11T18:36:23.605Z" }, + { url = "https://files.pythonhosted.org/packages/2f/45/7d51594b644c17c0bcf74ed8cd5fc33b324276d708e8506f220b70dab9d9/mypy-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8ef78c1d306bbf9a8a12f526c44902c9c28dffd6c52c52bf6a72641ce18d3849", size = 13645739, upload-time = "2026-05-11T18:37:22.752Z" }, + { url = "https://files.pythonhosted.org/packages/65/01/455c31b170e9468265074840bf18863a8482a24103fdaabe4e199392aa5f/mypy-2.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c209a90853081ff01d01ee895cafe10f7db1474e0d95beaeef0f6c1db9119bbd", size = 14074199, upload-time = "2026-05-11T18:35:09.292Z" }, + { url = "https://files.pythonhosted.org/packages/41/5a/93093f0b29a9e982deafde698f740a2eb2e05886e79ccf0594c7fd5413a3/mypy-2.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47cebf61abde7c088a4e27718a8b13a81655686b2e9c251f5c0915a802248166", size = 14953128, upload-time = "2026-05-11T18:31:57.678Z" }, + { url = "https://files.pythonhosted.org/packages/7f/2f/a196f5331d96170ad3d28f144d2aba690d4b2911381f68d51e489c7ab82a/mypy-2.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d57a90ae5e872138a425ec328edbc9b235d1934c4377881a33ec05b341acc9a8", size = 15249378, upload-time = "2026-05-11T18:33:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/54/de/94d321cc12da9f71341ac0c270efbed5c725750c7b4c334d957de9a087d9/mypy-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:aea7f7a8a55b459c34275fc468ada6ca7c173a5e43a68f5dbe588a563d8a06b8", size = 11060994, upload-time = "2026-05-11T18:33:18.848Z" }, + { url = "https://files.pythonhosted.org/packages/e1/62/0c27ca55219a7c764a7fb88c7bb2b7b2f9780ade8bbf16bc8ed8400eef6b/mypy-2.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:c989640253f0d76843e9c6c1bbf4bd48c5e85ada61bde4beb37cb3eca035685e", size = 9976743, upload-time = "2026-05-11T18:31:25.554Z" }, + { url = "https://files.pythonhosted.org/packages/0a/a1/639f3024794a2a15899cb90707fe02e044c4412794c39c5769fd3df2e2ef/mypy-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a683016b16fe2f572dc04c72be7ee0504ac1605a265d0200f5cea695fb788f41", size = 14691685, upload-time = "2026-05-11T18:33:27.973Z" }, + { url = "https://files.pythonhosted.org/packages/3b/08/9a585dea4325f20d8b80dc78623fa50d1fd2173b710f6237afd6ba6ab39b/mypy-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a293c534adb55271fef24a26da04b855540a8c13cc07bc5917b9fd2c394f2ca", size = 13555165, upload-time = "2026-05-11T18:32:16.107Z" }, + { url = "https://files.pythonhosted.org/packages/81/dc/7c42cc9c6cb01e8eb09961f1f738741d3e9c7e9d5c5b30ec69222625cd5f/mypy-2.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7406f4d048e71e576f5356d317e5b0a9e666dfd966bd99f9d14ca06e1a341538", size = 13994376, upload-time = "2026-05-11T18:32:39.256Z" }, + { url = "https://files.pythonhosted.org/packages/d4/fa/285946c33bce716e082c11dfeee9ee196eaf1f5042efb3581a31f9f205e4/mypy-2.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e0210d626fc8b31ccc90233754c7bc90e1f43205e85d96387f7db1285b55c398", size = 14864618, upload-time = "2026-05-11T18:34:49.765Z" }, + { url = "https://files.pythonhosted.org/packages/2b/83/82397f48af6c27e295d57979ded8490c9829040152cf7571b2f026aeb9a0/mypy-2.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3712c20deed54e814eaaa825603bada8ea1c390670a397c95b98405347acc563", size = 15102063, upload-time = "2026-05-11T18:34:05.855Z" }, + { url = "https://files.pythonhosted.org/packages/40/68/b02dec39057b88eb03dc0aa854732e26e8361f34f9d0e20c7614967d1eba/mypy-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fcaa0e479066e31f7cceb6a3bea39cb22b2ff51a6b2f24f193d19179ba17c389", size = 11060564, upload-time = "2026-05-11T18:35:36.494Z" }, + { url = "https://files.pythonhosted.org/packages/cf/a8/ea3dcbef31f99b634f2ee23bb0321cbc8c1b388b76a861eb849f13c347dc/mypy-2.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:0b1a5260c95aa443083f9ed3592662941951bca3d4ca224a5dc517c38b7cf666", size = 9966983, upload-time = "2026-05-11T18:37:14.139Z" }, + { url = "https://files.pythonhosted.org/packages/95/b1/55861beb5c339b44f9a2ba92df9e2cb1eeb4ae1eee674cdf7772c797778b/mypy-2.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:244358bf1c0da7722230bce60683d52e8e9fd030554926f15b747a84efb5b3af", size = 14874381, upload-time = "2026-05-11T18:37:31.784Z" }, + { url = "https://files.pythonhosted.org/packages/0b/b3/b7f770114b7d0ac92d0f76e8d93c2780844a70488a90e91821927850da86/mypy-2.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4ec7c57657493c7a75534df2751c8ae2cda383c16ecc55d2106c54476b1b16f6", size = 13665501, upload-time = "2026-05-11T18:34:23.063Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f3/8ae2037967e2126689a0c11d99e2b707134a565191e92c60ca2572aec60a/mypy-2.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8161b6ff4392410023224f0969d17db93e1e154bc3e4ba62598e720723ae211", size = 14045750, upload-time = "2026-05-11T18:31:48.151Z" }, + { url = "https://files.pythonhosted.org/packages/a0/32/615eb5911859e43d054941b0d0a7d06cfa2870eba86529cf385b052b111c/mypy-2.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf03e12003084a67395184d3eb8cbd6a489dc3655b5664b28c210a9e2403ab0b", size = 15061630, upload-time = "2026-05-11T18:37:06.898Z" }, + { url = "https://files.pythonhosted.org/packages/d4/03/4eafbfff8bfab1b87082741eae6e6a624028c984e6708b73bce2a8570c9d/mypy-2.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:20509760fd791c51579d573153407d226385ec1f8bcce55d730b354f3336bc22", size = 15288831, upload-time = "2026-05-11T18:31:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/99/ee/919661478e5891a3c96e549c036e467e64563ab85995b10c53c8358e16a3/mypy-2.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:6753d0c1fdd6b1a23b9e4f283ce80b2153b724adcb2653b20b85a8a28ac6436b", size = 11135228, upload-time = "2026-05-11T18:34:31.23Z" }, + { url = "https://files.pythonhosted.org/packages/24/0a/6a12b9782ca0831a553192f351679f4548abc9d19a7cc93bb7feb02084c7/mypy-2.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:98ebb6589bb3b6d0c6f0c459d53ca55b8091fbc13d277c4041c885392e8195e8", size = 10040684, upload-time = "2026-05-11T18:36:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/6e/dd/c7191469c777f07689c032a8f7326e393ea34c92d6d76eb7ce5ba57ea66d/mypy-2.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35aac3bb114e03888f535d5eb51b8bafbb3266586b599da1940f9b1be3ec5bd5", size = 14852174, upload-time = "2026-05-11T18:31:38.929Z" }, + { url = "https://files.pythonhosted.org/packages/55/8c/aed55408879043d72bb9135f4d0d19a02b886dd569631e113e3d2706cb8d/mypy-2.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de55a8c861f2a49331f807be98d90caeceeef520bde13d43a160207f8af613e", size = 13651542, upload-time = "2026-05-11T18:36:04.636Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8e/f371a824b1f1fa8ea6e3dbb8703d232977d572be2329554a3bc4d960302f/mypy-2.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5fdf2941a07434af755837d9880f7d7d25f1dacb1af9dcd4b9b66f2220a3024e", size = 14033929, upload-time = "2026-05-11T18:35:55.742Z" }, + { url = "https://files.pythonhosted.org/packages/94/21/f54be870d6dd53a82c674407e0f8eed7174b05ec78d42e5abd7b42e84fd5/mypy-2.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e195b817c13f02352a9c124301f9f30f078405444679b6753c1b96b6eed37285", size = 15039200, upload-time = "2026-05-11T18:33:10.281Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/bf21748626a40ce59fd29a39386ab46afec88b7bd2f0fa6c3a97c995523f/mypy-2.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5431d42af987ebd92ba2f71d45c85ed41d8e6ca9f5fd209a69f68f707d2469e5", size = 15272690, upload-time = "2026-05-11T18:32:07.205Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d7/9e90d2cf47100bea550ed2bc7b0d4de3a62181d84d5e37da0003e8462637/mypy-2.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:767fe8c66dc3e01e19e1737d4c38ebefead16125e1b8e58ad421903b376f5c65", size = 11147435, upload-time = "2026-05-11T18:33:56.477Z" }, + { url = "https://files.pythonhosted.org/packages/ec/46/e5c449e858798e35ffc90946282a27c62a77be743fe17480e4977374eb91/mypy-2.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:ecfe70d43775ab99562ab128ce49854a362044c9f894961f68f898c23cb7429d", size = 10035052, upload-time = "2026-05-11T18:32:30.049Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ca/b279a672e874aedd5498ae25f722dacc8aa86bbffb939b3f97cbb1cf6686/mypy-2.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7354c5a7f69d9345c3d6e69921d57088eea3ddeeb6b20d34c1b3855b02c36ec2", size = 14848422, upload-time = "2026-05-11T18:35:45.984Z" }, + { url = "https://files.pythonhosted.org/packages/27/e6/3efe56c631d959b9b4454e208b0ac4b7f4f58b404c89f8bec7b49efdfc21/mypy-2.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:49890d4f76ac9e06ec117f9e09f3174da70a620a0c300953d8595c926e80947f", size = 13677374, upload-time = "2026-05-11T18:36:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/84/7f/8107ea87a44fd1f1b59882442f033c9c3488c127201b1d1d15f1cbd6022e/mypy-2.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:761be68e023ef5d94678772396a8af1220030f80837a3afd8d0aef3b419666f4", size = 14055743, upload-time = "2026-05-11T18:35:18.361Z" }, + { url = "https://files.pythonhosted.org/packages/51/4d/b6d34db183133b83761b9199a82d31557cdbb70a380d8c3b3438e11882a3/mypy-2.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c90345fc182dc363b891350457ec69c35140858538f38b4540845afcc32b1aef", size = 15020937, upload-time = "2026-05-11T18:34:59.618Z" }, + { url = "https://files.pythonhosted.org/packages/ff/d7/f08360c691d758acb02f45022c34d98b92892f4ea756644e1000d4b9f3d8/mypy-2.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b84802e7b5a6daf1f5e15bc9fcd7ddae77be13981ffab037f1c67bb84d67d135", size = 15253371, upload-time = "2026-05-11T18:36:41.081Z" }, + { url = "https://files.pythonhosted.org/packages/67/1b/09460a13719530a19bce27bd3bc8449e83569dd2ba7faf51c9c3c30c0b61/mypy-2.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:022c771234936ceac541ebaf836fe9e2abeb3f5e09aff21588fe543ff006fe21", size = 11326429, upload-time = "2026-05-11T18:34:13.526Z" }, + { url = "https://files.pythonhosted.org/packages/40/62/75dbf0f82f7b6680340efc614af29dd0b3c17b8a4f1cd09b8bd2fd6bc814/mypy-2.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:498207db725cec88829a6a5c2fc771205fd043719ef98bc49aba8fb9fc4e6d57", size = 10218799, upload-time = "2026-05-11T18:32:23.491Z" }, + { url = "https://files.pythonhosted.org/packages/b2/66/caca04ed7d972fb6eb6dd1ccd6df1de5c38fae8c5b3dc1c4e8e0d85ee6b9/mypy-2.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7d5e5cad0efeba72b93cd17490cc0d69c5ac9ca132994fe3fb0314808aeeb83e", size = 15923458, upload-time = "2026-05-11T18:35:28.64Z" }, + { url = "https://files.pythonhosted.org/packages/ed/52/2d90cbe49d014b13ed7ff337930c30bad35893fe38a1e4641e756bb62191/mypy-2.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ff715050c127d724fd260a2e666e7747fdd83511c0c47d449d98238970aef780", size = 14757697, upload-time = "2026-05-11T18:36:14.208Z" }, + { url = "https://files.pythonhosted.org/packages/ac/37/d98f4a14e081b238992d0ed96b6d39c7cc0148c9699eb71eaa68629665ea/mypy-2.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:82208da9e09414d520e912d3e462d454854bed0810b71540bb016dcbca7308fd", size = 15405638, upload-time = "2026-05-11T18:33:48.249Z" }, + { url = "https://files.pythonhosted.org/packages/a3/c2/15c46613b24a84fad2aea1248bf9619b99c2767ae9071fe224c179a0b7d4/mypy-2.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e79ebc1b904b84f0310dff7469655a9c36c7a68bddb37bdd42b67a332df61d08", size = 16215852, upload-time = "2026-05-11T18:32:50.296Z" }, + { url = "https://files.pythonhosted.org/packages/5c/90/9c16a57f482c76d25f6379762b56bbf65c711d8158cf271fb2802cfb0640/mypy-2.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e583edc957cfb0deb142079162ae826f58449b116c1d442f2d91c69d9fced081", size = 16452695, upload-time = "2026-05-11T18:33:38.182Z" }, + { url = "https://files.pythonhosted.org/packages/0f/4c/215a4eeb63cacc5f17f516691ea7285d11e249802b942476bff15922a314/mypy-2.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b33b6cd332695bba180d55e717a79d3038e479a2c49cc5eb3d53603409b9a5d7", size = 12866622, upload-time = "2026-05-11T18:34:39.945Z" }, + { url = "https://files.pythonhosted.org/packages/4b/50/1043e1db5f455ffe4c9ab22747cd8ca2bc492b1e4f4e21b130a44ee2b217/mypy-2.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4f910fe825376a7b66ef7ca8c98e5a149e8cd64c19ae71d84047a74ee060d4e6", size = 10610798, upload-time = "2026-05-11T18:36:31.444Z" }, + { url = "https://files.pythonhosted.org/packages/0d/2a/13ca1f292f6db1b98ff495ef3467736b331621c5917cad984b7043e7348d/mypy-2.1.0-py3-none-any.whl", hash = "sha256:a663814603a5c563fb87a4f96fb473eeb30d1f5a4885afcf44f9db000a366289", size = 2693302, upload-time = "2026-05-11T18:31:29.246Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nox" +version = "2026.4.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "attrs" }, + { name = "colorlog" }, + { name = "dependency-groups" }, + { name = "humanize" }, + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/6b/e672c862a43cfca704d32359221fa3780226daa1e5db5dfc401bcc8be9c9/nox-2026.4.10.tar.gz", hash = "sha256:2d0af5374f3f37a295428c927d1b04a8182aa01762897d172446dda2f1ce9692", size = 4034839, upload-time = "2026-04-10T17:42:42.209Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/95/4df134a100b5a9a12378d5301b934366686ef6fbdaffcd21211d5654970e/nox-2026.4.10-py3-none-any.whl", hash = "sha256:082c117627590d9b90aa21f86df89b310b07c5842539524203bcb3c719f116c1", size = 75536, upload-time = "2026-04-10T17:42:40.664Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "paginate" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/46/68dde5b6bc00c1296ec6466ab27dddede6aec9af1b99090e1107091b3b84/paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945", size = 19252, upload-time = "2024-08-25T14:17:24.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/90/96/04b8e52da071d28f5e21a805b19cb9390aa17a47462ac87f5e2696b9566d/paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591", size = 13746, upload-time = "2024-08-25T14:17:22.55Z" }, +] + +[[package]] +name = "pathspec" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz", hash = "sha256:17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a", size = 135180, upload-time = "2026-04-27T01:46:08.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl", hash = "sha256:a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189", size = 57328, upload-time = "2026-04-27T01:46:07.06Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/47/e4501f49c178ae1d9f4a75073fda4204f52647993f075a9db4d14930e0c5/platformdirs-4.10.0.tar.gz", hash = "sha256:31e761a6a0ca04faf7353ea759bdba55652be214725111e5aac52dfa29d4bef7", size = 31224, upload-time = "2026-05-28T03:32:53.587Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/e6/cd9575ac904136b3cbf7aa7ee819ef86eedb7274e46f230e94ea4342e729/platformdirs-4.10.0-py3-none-any.whl", hash = "sha256:fb516cdb12eb0d857d0cd85a7c57cea4d060bee4578d6cf5a14dfdf8cbf8784a", size = 22743, upload-time = "2026-05-28T03:32:52.175Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pycodestyle" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" }, +] + +[[package]] +name = "pyflakes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58", size = 64669, upload-time = "2025-06-20T18:45:27.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pymdown-extensions" +version = "10.21.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/26/d1015444da4d952a1ca487a236b522eb979766f0295a0bd0c5fc089989a9/pymdown_extensions-10.21.3.tar.gz", hash = "sha256:72cfcf55f07aea0d4af2c4f11dd4e52466ddfb1bb819673146398e0bd3a77354", size = 854140, upload-time = "2026-05-13T12:57:32.267Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/85/545a951eecc270fcd688288c600017e2050a1aacb56c711d208586d3e470/pymdown_extensions-10.21.3-py3-none-any.whl", hash = "sha256:d7a5d08014fc571e80ca21dd6f854e31f94c489800350564d55d15b3c41e76b6", size = 269002, upload-time = "2026-05-13T12:57:30.296Z" }, +] + +[[package]] +name = "pyproject-api" +version = "1.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/62/0fe346fe380b1aafaf819c8cb195d3241bb4f355f908e6339814131a830b/pyproject_api-1.10.1.tar.gz", hash = "sha256:c2b2726bd7aa9217b6c50b621fef5b2ae5def4d55b779c9e0694c15e0a8517ba", size = 23477, upload-time = "2026-05-28T14:22:14.049Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/d7/29e1e5e882f79133631f7bcace42d23db493f616463c157a1ab614bf69dd/pyproject_api-1.10.1-py3-none-any.whl", hash = "sha256:fa9e6f66c35b5017e909825d8f2b5d5482ea699d7be809d21c03bd1f7317f36a", size = 12992, upload-time = "2026-05-28T14:22:12.711Z" }, +] + +[[package]] +name = "pytest" +version = "8.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/b7/7d44bbc04c531dcc753056920e0988032e5871ac674b5a84cb979de6e7af/pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044", size = 1409703, upload-time = "2024-03-09T11:51:08.012Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/7e/c79cecfdb6aa85c6c2e3cf63afc56d0f165f24f5c66c03c695c4d9b84756/pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7", size = 337359, upload-time = "2024-03-09T11:51:04.858Z" }, +] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage", extra = ["toml"] }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042, upload-time = "2024-03-24T20:16:34.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990, upload-time = "2024-03-24T20:16:32.444Z" }, +] + +[[package]] +name = "pytest-runner" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/7d/60976d532519c3a0b41e06a59ad60949e2be1af937cf02738fec91bfd808/pytest-runner-6.0.1.tar.gz", hash = "sha256:70d4739585a7008f37bf4933c013fdb327b8878a5a69fcbb3316c88882f0f49b", size = 16056, upload-time = "2023-12-04T01:03:30.835Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/2b/73982c02d28538b6a1182c0a2faf764ca6a76a6dbe89a69288184051a67b/pytest_runner-6.0.1-py3-none-any.whl", hash = "sha256:ea326ed6f6613992746062362efab70212089a4209c08d67177b3df1c52cd9f2", size = 7186, upload-time = "2023-12-04T01:03:28.706Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/12/38c1a0b1e64806780c9563e3fc9f6e472251839662587cfbe9bfaf2ae10a/python_discovery-1.4.0.tar.gz", hash = "sha256:eb8bc7daad3c226c147e45bb4e970a1feb1bf4048ee178e6db59e197b8010ce3", size = 68455, upload-time = "2026-05-28T01:15:37.639Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/8d/3d316429f65029532bb1e28ff77b797d86b5ac3915bb44ca4e19aa283d43/python_discovery-1.4.0-py3-none-any.whl", hash = "sha256:26ed78d703e234879a66244c7d4114563fb13ec5cd30a2d1357e5fb4850782da", size = 33217, upload-time = "2026-05-28T01:15:36.573Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, + { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, + { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, + { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, + { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, + { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, + { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, + { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, + { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, + { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, + { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, + { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, +] + +[[package]] +name = "pyyaml-env-tag" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/2e/79c822141bfd05a853236b504869ebc6b70159afc570e1d5a20641782eaa/pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff", size = 5737, upload-time = "2025-05-13T15:24:01.64Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/11/432f32f8097b03e3cd5fe57e88efb685d964e2e5178a48ed61e841f7fdce/pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04", size = 4722, upload-time = "2025-05-13T15:23:59.629Z" }, +] + +[[package]] +name = "regex" +version = "2026.5.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/0e/49aee608ad09480e7fd276898c99ec6192985fa331abe4eb3a986094490b/regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270", size = 416074, upload-time = "2026-05-09T23:15:19.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ed/0ad2c8edf634918eb4484365d3819fa7bd7f58daf807fe7fb21812c316e5/regex-2026.5.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a9e1328e17c84c1a5d22ec9f785ecef4a967fab9a42b6a8dc3bcbebd0a0c9e44", size = 489438, upload-time = "2026-05-09T23:11:29.374Z" }, + { url = "https://files.pythonhosted.org/packages/89/a9/4ed972ad263963b860b7c3e86e0e1bcc791def47b43b8c8efe57e710f139/regex-2026.5.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfe1ce50cbfb569d74e1e4337da6468961f31dbea55fd85aa5de59c0947a805a", size = 291270, upload-time = "2026-05-09T23:11:33.254Z" }, + { url = "https://files.pythonhosted.org/packages/16/81/075930d9fa28c4ea1f53398dd015ee7c882f623539759113cda1257f4b82/regex-2026.5.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15ee42209947f4ca045412eae98416317238163618ace2a8e54f99586a466733", size = 289198, upload-time = "2026-05-09T23:11:35.769Z" }, + { url = "https://files.pythonhosted.org/packages/d4/c8/5cdfbf0b5dc6599e1b6131eff43262e5275d4ec3469ce10216061659aadb/regex-2026.5.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4bb445ff3f725f59df8f6014edb547ee928ec7023a774f6a39a3f953038cbb2", size = 784765, upload-time = "2026-05-09T23:11:37.689Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ca/ae5fd6edc59b7f84b904b31d6ec39a860cbcecd10f64bd5a062ca83a4864/regex-2026.5.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:446ddd671e43ab535810c4b21cff7104945c701d4a14d1e6d1cd6f4e445a8bea", size = 852115, upload-time = "2026-05-09T23:11:39.973Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ce/a91cf555afb51f3b74a182e24ba073b91ea7bb64592fc4b315c111bb19fd/regex-2026.5.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b92817338591505f282cf3864c145244b1edcf5381d237038df955001091538", size = 899503, upload-time = "2026-05-09T23:11:42.48Z" }, + { url = "https://files.pythonhosted.org/packages/55/7f/725a0a2b245a4cf0c4bab29d0e97c74285d94136a65d1b55a6459a583502/regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6b8a143aca6c39b446ea8092cde25cc8fe9304d4f5fecfbc1a9dbb0282703c2", size = 794093, upload-time = "2026-05-09T23:11:44.681Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2a/996efbd59ce6b5d4a09e3af6180ceb62af171f4a9a6fb557d2f0ae0d462b/regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0f03aa6898aaaac4592479821df16e68e8d0e29e903e65d8f2dfb2f19028a989", size = 786234, upload-time = "2026-05-09T23:11:46.882Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/8731e8b8806174c9cdd5903f80a14990331c1f42fc4209b540952e9e010d/regex-2026.5.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ed457d8e98ae812ed7732bef7bf78de78e834eae0372a74e23ca90ef21d910f9", size = 769895, upload-time = "2026-05-09T23:11:49.324Z" }, + { url = "https://files.pythonhosted.org/packages/9a/0b/932473194bd563f342a412ae2ffbbd6da608306a2bc4e99249a41c2b0b92/regex-2026.5.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71b61c5bfe1c806332defc42ad6c780b3c55f661986d7f40283a3a88274b4c00", size = 774991, upload-time = "2026-05-09T23:11:51.261Z" }, + { url = "https://files.pythonhosted.org/packages/98/80/9523d196010031df25f7177ee0a467efbee436324038e5d99def17a57515/regex-2026.5.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3b1e39888c5e0c7d92cea4fc777396c4a90363b05de75d02eb459a4752200808", size = 848790, upload-time = "2026-05-09T23:11:53.232Z" }, + { url = "https://files.pythonhosted.org/packages/3c/07/56987b35e89edf47e4a38cf2845aeee476bfa688a6bdbd3e820cda461dc1/regex-2026.5.9-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6ba42b2e7e7f46cf68cc6a5ca36fa07959f9bbd9c6bdcc47b6ee76549a590248", size = 757679, upload-time = "2026-05-09T23:11:55.82Z" }, + { url = "https://files.pythonhosted.org/packages/04/2a/ff713fff0c566507c06a4ce2dc0ae8e7eeebc88811a95fc81cf1e7d534dd/regex-2026.5.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c010eb8caca74bdb40c07498d7ece26b4428fd3f04aa8a72c9ac6f79e8faaac6", size = 837116, upload-time = "2026-05-09T23:11:57.934Z" }, + { url = "https://files.pythonhosted.org/packages/77/90/df6d982b03e3614785c6937ba51b57f6733d97d2ee1c9bc7531dbfab3a54/regex-2026.5.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a6a563446a41adc451393dc6b8e6ad87979efaee3c8738690a8d1b08ebead1b4", size = 782081, upload-time = "2026-05-09T23:11:59.607Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/4e88a5f7c3e98489aac4dd23142723d907b2a595b4a6abcbacabefeded09/regex-2026.5.9-cp310-cp310-win32.whl", hash = "sha256:954cc214c04663ee6d266fc61739cad83054683048de65c5bd1d640ad28098ac", size = 266247, upload-time = "2026-05-09T23:12:01.116Z" }, + { url = "https://files.pythonhosted.org/packages/6a/40/4b224cb0582b2dca1786726e6cdabe26abbf757d7f6718332f186da155d2/regex-2026.5.9-cp310-cp310-win_amd64.whl", hash = "sha256:b310768746dd314ea6e2ff4cc89ef215426813396ff4e94ee8e6f7096c8b6e03", size = 278416, upload-time = "2026-05-09T23:12:03.2Z" }, + { url = "https://files.pythonhosted.org/packages/12/4d/014fbe803204cab0947ee428f09f658a29632053dde1d3c6176bb4f0fd4c/regex-2026.5.9-cp310-cp310-win_arm64.whl", hash = "sha256:19c16ceb4a267a8789e25733e583983eeab9f0f8664e66b0bd1c5d21f14c2d4b", size = 270413, upload-time = "2026-05-09T23:12:04.649Z" }, + { url = "https://files.pythonhosted.org/packages/c2/dc/c1f2df4027e82fc54b5a473e4b250f5139faca49a0fbe29a48668d228f34/regex-2026.5.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ccf5249114cc3e772ecdd88a98a86eca0fd74c61ce32a94743758c083fc05d48", size = 489445, upload-time = "2026-05-09T23:12:06.111Z" }, + { url = "https://files.pythonhosted.org/packages/03/d2/59f01110660081cce9c0bc30ebd0b5ee250dacf658e3248ed92f01e0e8ee/regex-2026.5.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46f1326ca6e65b0879d23ca302c0f2415aad42ff0309b9c818e7949fe19a41d8", size = 291271, upload-time = "2026-05-09T23:12:07.731Z" }, + { url = "https://files.pythonhosted.org/packages/58/b6/14b2c84ff90ddb370c81d27503f4a0fcf071496416f4855f6cc8c5d81c35/regex-2026.5.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef31cbfe458e21c6122ba8150ff060e0c7789ed0d26eb423f25472584920b555", size = 289212, upload-time = "2026-05-09T23:12:09.266Z" }, + { url = "https://files.pythonhosted.org/packages/03/d0/4db86529117320de0c84afd90e70bb47434625875e34fcef9d8c127c5b16/regex-2026.5.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:992604d02e6d9c6d786c24a706a71ecffe1020fc1ef264044474cd81fa2c3919", size = 792310, upload-time = "2026-05-09T23:12:11.416Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/fe4800cd322f862ecffd2d553409b20d80650e5ed71b9d178f853d020b82/regex-2026.5.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9411dd64ca95477225734a93dfc8583b51916b8d5942f99d6cac21e09965451", size = 861721, upload-time = "2026-05-09T23:12:13.681Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d0/b3618a895dd8feb897c61bb2954edd265e1767d82a01d53065d5871127a3/regex-2026.5.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4a3ff360dfb836fecdb93a4598f9d6e2ac81e3e397125145c6221bf58cf4c", size = 906460, upload-time = "2026-05-09T23:12:15.443Z" }, + { url = "https://files.pythonhosted.org/packages/33/6f/1481597e859ef19508b345eec4afd1416ed6e6b459c75a64026ef193aecf/regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc", size = 799843, upload-time = "2026-05-09T23:12:16.892Z" }, + { url = "https://files.pythonhosted.org/packages/73/59/955734c803f59108deccba3597ae440c76b62a652733c0006e6243758420/regex-2026.5.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f079e50a0d3cc3cd5091fa9ff45869a2e6b2cd35895731edafb0327901a8d86d", size = 773610, upload-time = "2026-05-09T23:12:19.127Z" }, + { url = "https://files.pythonhosted.org/packages/68/8f/70c04a236d651c81881dac42ef8538bddda6121434509d0a22d9e601503b/regex-2026.5.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ebe8f0b5ec5a5024dc4a4c59f444c4e9afc5f2abdbb8962065b75d27fb971f9", size = 781645, upload-time = "2026-05-09T23:12:20.806Z" }, + { url = "https://files.pythonhosted.org/packages/1d/96/05c7434d88185e5d27fe54aeb74df86bd77cd79f52f0b4eae54faa8fea70/regex-2026.5.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:97cf3bc1b7d7d2306772ec07366c80d9df00ff79e79cea32898883a646d2fae2", size = 854473, upload-time = "2026-05-09T23:12:22.465Z" }, + { url = "https://files.pythonhosted.org/packages/4e/c1/6e3d8202d981f3117004bf341ee74893ba4ba8a9fbaf4b94615846550a08/regex-2026.5.9-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0f9eede6a5cbdc02d4978090186390936e1776a7d1359b21e41014c609880bcf", size = 763311, upload-time = "2026-05-09T23:12:24.351Z" }, + { url = "https://files.pythonhosted.org/packages/93/c7/e7737f1526b3fb32bd4c337fd6c71c3ebb5c8296fc34d11197e0955d2e35/regex-2026.5.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:01f0f5f55f4b64dacec85dc116d3c05fd23ad3ff037bbc73a2085775953c2611", size = 844593, upload-time = "2026-05-09T23:12:26.341Z" }, + { url = "https://files.pythonhosted.org/packages/a5/27/0daffb1a535bb39f422c3d200f4ab023c71110ad66a32b366bee708baba0/regex-2026.5.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1268eddd8486dc561d08eee1156e40aa3a8fe10f4bdec8fa653b455fcbffd12c", size = 789167, upload-time = "2026-05-09T23:12:27.975Z" }, + { url = "https://files.pythonhosted.org/packages/ce/fc/294fe4fac4f2ed67207b17471815870c1c45b3a489e08e0ac96daea16ef6/regex-2026.5.9-cp311-cp311-win32.whl", hash = "sha256:8676474c07469d6f33dd1085ca2cd45f65785f32518f2b20e36d9953ca07f994", size = 266249, upload-time = "2026-05-09T23:12:30.141Z" }, + { url = "https://files.pythonhosted.org/packages/d0/b0/8dce459f6245bcf8f6e9f23ac9569f1a0f15c131cc0745e82b43226204cf/regex-2026.5.9-cp311-cp311-win_amd64.whl", hash = "sha256:246de9d60aa3f8538b519834dd95cbf276ea263d6a7bd5a3666dc3fa0230505b", size = 278423, upload-time = "2026-05-09T23:12:31.676Z" }, + { url = "https://files.pythonhosted.org/packages/db/8d/f9aeff6ad63a3ef720386f2907e6d34a35a510a6e498ebad28b0fb3f6ab6/regex-2026.5.9-cp311-cp311-win_arm64.whl", hash = "sha256:d726ca3f0d76969bf1e8e477d160d3d666bbf999f6860bd314889e5345782046", size = 270420, upload-time = "2026-05-09T23:12:33.194Z" }, + { url = "https://files.pythonhosted.org/packages/50/9b/6550044bc44e17c84d312c031c2ec42fbdb6a4ec4e29093be3a172d08772/regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06", size = 490451, upload-time = "2026-05-09T23:12:34.72Z" }, + { url = "https://files.pythonhosted.org/packages/1e/95/fc7ba4303b5a0f92446a12ee6778ef2c6c799233f5060042a31bf390cfe9/regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6", size = 292112, upload-time = "2026-05-09T23:12:36.285Z" }, + { url = "https://files.pythonhosted.org/packages/54/4b/ee27938d1b2c443e89a9a10e00d2d19aa5ee300cd3d61140644e93bb083e/regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225", size = 289599, upload-time = "2026-05-09T23:12:38.089Z" }, + { url = "https://files.pythonhosted.org/packages/d8/dd/ba103dc19614e25f3880800ca67ce093d6e21b325d72b8383c7bf906e9fa/regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0", size = 796732, upload-time = "2026-05-09T23:12:40.062Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e7/f035b4fd858b050b0080bf302968dc0f59ba34e391872d54936758e6844e/regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107", size = 865440, upload-time = "2026-05-09T23:12:42.059Z" }, + { url = "https://files.pythonhosted.org/packages/0a/51/8cd301ecc899aea28124357f729f4272f44de7806fc7ca02490bfbe253e8/regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309", size = 912329, upload-time = "2026-05-09T23:12:44.373Z" }, + { url = "https://files.pythonhosted.org/packages/cc/1e/3fbe2fa1e8cebd62f3bb7d3321cff1640aca2e240b51d9bd624aad949260/regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8", size = 801239, upload-time = "2026-05-09T23:12:46.268Z" }, + { url = "https://files.pythonhosted.org/packages/17/2f/6f6008682bf2cf98040a0d3153a8e557b6ab728d7713d045cee4ce544ab8/regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66", size = 777054, upload-time = "2026-05-09T23:12:48.051Z" }, + { url = "https://files.pythonhosted.org/packages/19/2b/eee0d20a6842ba04df4b8847a920b57ef56853f14ef85405473e586b605a/regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026", size = 785098, upload-time = "2026-05-09T23:12:49.851Z" }, + { url = "https://files.pythonhosted.org/packages/4a/98/6fc1e6410feefb92159edaed5041992bfe390e8d26c721865434acbca558/regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962", size = 860095, upload-time = "2026-05-09T23:12:51.666Z" }, + { url = "https://files.pythonhosted.org/packages/18/a3/bd855e0f2cb1a978ecf6fa6bb69632dd9c3f6ea3b81cde62fde14c9daec7/regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621", size = 765762, upload-time = "2026-05-09T23:12:53.413Z" }, + { url = "https://files.pythonhosted.org/packages/dc/66/0ae8c092e60b14c79d24f8e0b7f0aea5bfbffdcab00b5483d13404d3c3a5/regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d", size = 852100, upload-time = "2026-05-09T23:12:55.256Z" }, + { url = "https://files.pythonhosted.org/packages/21/de/8dfde60fc1b21c946a893ba273403b72617edb261370cb1087099a83f088/regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce", size = 789479, upload-time = "2026-05-09T23:12:57.573Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1c/bdcc98f9a4af4fdd166c74941174619ccff4726d3ce32faa8e9a2ecd38dd/regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e", size = 266699, upload-time = "2026-05-09T23:12:59.14Z" }, + { url = "https://files.pythonhosted.org/packages/78/87/240d36864f9e48ace85f72e79ced97ceb7f27ce87739a947dcb834b4e6bc/regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e", size = 277783, upload-time = "2026-05-09T23:13:00.789Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b5/7b30f312b0669dff5beebe5b0989dc2d1a312b1a44fab852199c387a5b96/regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070", size = 270513, upload-time = "2026-05-09T23:13:02.426Z" }, + { url = "https://files.pythonhosted.org/packages/aa/da/797e91ecec6f84135da778ddce78c20e0af5d2a15c26f87a81bc3eadb6db/regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb", size = 490303, upload-time = "2026-05-09T23:13:04.382Z" }, + { url = "https://files.pythonhosted.org/packages/44/da/bf30abaaa737b58f4a4b8c4a03659e02fd92092c822e0197ed9e0daab917/regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f", size = 292019, upload-time = "2026-05-09T23:13:06.022Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e7/d0eaf5713828417b9e5648cf81fa9bacd4961f6ab98c380c2034f8716e35/regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c", size = 289468, upload-time = "2026-05-09T23:13:08.214Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9b/b3fdd62b003baa1a9b593cd8c8699c9651c2e80cc21a5c715707983c42d7/regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed", size = 796749, upload-time = "2026-05-09T23:13:10.573Z" }, + { url = "https://files.pythonhosted.org/packages/d4/30/66ab84588765f5b4b271a9ca09ef7ce2b87caa95176ec3d2ad65d7bc4902/regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020", size = 865445, upload-time = "2026-05-09T23:13:12.523Z" }, + { url = "https://files.pythonhosted.org/packages/1a/89/f05169e8588aac365f35ffc7f3bc3184f095ef4cfded7cfaa3c7fd5dbd89/regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2", size = 912322, upload-time = "2026-05-09T23:13:14.281Z" }, + { url = "https://files.pythonhosted.org/packages/30/e1/c93444052cf41581f3c884ab3fb5823daf0992f11cd4388d4275ca610558/regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2", size = 801269, upload-time = "2026-05-09T23:13:16.569Z" }, + { url = "https://files.pythonhosted.org/packages/50/fe/0cf96b882f540e62e8b9956599798203d599c44cf4c77917ca27400ff69b/regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04", size = 777085, upload-time = "2026-05-09T23:13:18.675Z" }, + { url = "https://files.pythonhosted.org/packages/23/5c/d78d4924e7fc875557b9e9b768423925fdfaac5549d06da7810019a9bd26/regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c", size = 785153, upload-time = "2026-05-09T23:13:20.525Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e0/5214774090e7b4524dcea3e3c4aa74141d43043f8beb49c1599db1c8b53a/regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f", size = 860164, upload-time = "2026-05-09T23:13:22.263Z" }, + { url = "https://files.pythonhosted.org/packages/6e/e1/4a57a83350319b1271f0d7a249b8672513ed928b237a741631270de6caea/regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8", size = 765731, upload-time = "2026-05-09T23:13:24.277Z" }, + { url = "https://files.pythonhosted.org/packages/12/f4/499e74a20c156fc75836ee04a72a38d1a063978f600937f9760467beb1b0/regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6", size = 852062, upload-time = "2026-05-09T23:13:26.125Z" }, + { url = "https://files.pythonhosted.org/packages/5b/92/7eebc0d0a01e78629695f342ba17e0deaff8fb45e79cc0d7b98287da6e3e/regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21", size = 789577, upload-time = "2026-05-09T23:13:27.814Z" }, + { url = "https://files.pythonhosted.org/packages/05/a4/018e71f7d2ad48c1ebe6d3ae0026f9b7cb4802fd15c7cc02fdf724355102/regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127", size = 266691, upload-time = "2026-05-09T23:13:29.549Z" }, + { url = "https://files.pythonhosted.org/packages/e6/1d/861a93719fb9ee7dbfc3761b3797b7a3e112a5d42c6129459d2d741be9b5/regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca", size = 277747, upload-time = "2026-05-09T23:13:31.859Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c6/0a2436ae4da1ba76e51cb98943c6838a9a721faa40ebe2dce07694ae34e3/regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6", size = 270500, upload-time = "2026-05-09T23:13:33.525Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e9/d21346f7b60ed58789371358ed66b09d00f832e1bd7c06e55d9da5679882/regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3", size = 494172, upload-time = "2026-05-09T23:13:35.935Z" }, + { url = "https://files.pythonhosted.org/packages/c4/43/fd1177a2032037c681baecdb3422ee4e1424aec4e4f470ef47793d325274/regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6", size = 293952, upload-time = "2026-05-09T23:13:38.307Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7d/9fbf919768368d3f8a4f6c692cf2aa61e482b2b81ec6a298ace4cbf02480/regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff", size = 292314, upload-time = "2026-05-09T23:13:40.353Z" }, + { url = "https://files.pythonhosted.org/packages/e2/6c/e41bfeecb589716843e7c4df09ba46ff2a42961457afece19059d85caeef/regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88", size = 811681, upload-time = "2026-05-09T23:13:42.543Z" }, + { url = "https://files.pythonhosted.org/packages/87/83/a5c1c525fba0aa656e88ad0face0b1829788ef4c2fb6b26df58aa1151b84/regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178", size = 871135, upload-time = "2026-05-09T23:13:44.326Z" }, + { url = "https://files.pythonhosted.org/packages/18/d4/80882e799e440dd878b0979cbebf8fa4d54624a332c83037c7a701649e3f/regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100", size = 917265, upload-time = "2026-05-09T23:13:47.295Z" }, + { url = "https://files.pythonhosted.org/packages/ae/ff/8db60211e2286e396aad7dc7725356c502bff0901ea05bd6cdc2e1a042b9/regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e", size = 816311, upload-time = "2026-05-09T23:13:49.885Z" }, + { url = "https://files.pythonhosted.org/packages/4c/47/742ef579c61730f8d268e5cf1f9ce0e37e2ea041ad0f5644724f2378e463/regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2", size = 785498, upload-time = "2026-05-09T23:13:52.25Z" }, + { url = "https://files.pythonhosted.org/packages/7f/ab/cb0999802dcb0fb95b1ab005e8d4163d8afdd67efc2cb6b6630ac13f8cb1/regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b", size = 801348, upload-time = "2026-05-09T23:13:54.127Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/8ca59a24c55bc34d166eefaf3717bd77772f329fdbf984d86581e0a3571c/regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e", size = 866493, upload-time = "2026-05-09T23:13:56.067Z" }, + { url = "https://files.pythonhosted.org/packages/8d/3d/30f2ae62cef3278bb5bb821f467277a55fb73f01032cf85997e15e8289a8/regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041", size = 772811, upload-time = "2026-05-09T23:13:57.867Z" }, + { url = "https://files.pythonhosted.org/packages/d8/ae/7d2089bcd78ad0c0161bc684339df50032acb438a7bd3305e7ddb1193cec/regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0", size = 856584, upload-time = "2026-05-09T23:13:59.679Z" }, + { url = "https://files.pythonhosted.org/packages/a9/29/92ff47f75990131ea4f24ba17819e5a9d141e10819807e09addd73409af6/regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081", size = 803453, upload-time = "2026-05-09T23:14:01.978Z" }, + { url = "https://files.pythonhosted.org/packages/04/99/eff29f1037dcab36702c9ee5d6858cf1ce2336ea8ea2987f64245b99ea5e/regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5", size = 269951, upload-time = "2026-05-09T23:14:03.661Z" }, + { url = "https://files.pythonhosted.org/packages/0e/9d/8870b8981d27b22cda77bb26a5ac7ebfa9c7d9e0dea195a834a82380e748/regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4", size = 281240, upload-time = "2026-05-09T23:14:05.56Z" }, + { url = "https://files.pythonhosted.org/packages/72/b1/3379415e8f135c13ac551353397cc4fe97b4978f3cac73c5fcbcded548b8/regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de", size = 272383, upload-time = "2026-05-09T23:14:07.843Z" }, + { url = "https://files.pythonhosted.org/packages/13/3e/9c3cd292d8808b3645a2ce517e200179b6d0e903f176300bd8b542e14de5/regex-2026.5.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:1bd7587a2948b4085195d5a3374eaf4a425dc3e55784c038175355ecf3bbbf8a", size = 490376, upload-time = "2026-05-09T23:14:09.64Z" }, + { url = "https://files.pythonhosted.org/packages/60/70/d43ee8a2ca0a8b68d167f21658b85520ac0574617c7f320367c5047f7556/regex-2026.5.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dea2e88e1cce4522496cce630e11e67b98b7076620bc4336c3f674bc21a375f4", size = 291964, upload-time = "2026-05-09T23:14:11.424Z" }, + { url = "https://files.pythonhosted.org/packages/21/91/9d50b433828d8e74196904e168a43abf1e6e88b2a15d47ed742456720c37/regex-2026.5.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2099f7e7ff7b6aa3192312650a56e91cc091e49d50b04e4f6f8b6e28b3b27f1c", size = 289682, upload-time = "2026-05-09T23:14:13.123Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d2/b835e3cafbb9d977736912436259ff551d60919f7d7b3d37d46659c63564/regex-2026.5.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd353045824e4477562a2ac718c25799cdaaa41f7aa925a806a8a3e6848a5b9", size = 796996, upload-time = "2026-05-09T23:14:14.923Z" }, + { url = "https://files.pythonhosted.org/packages/2c/a6/9f992d00019166b9de01c546dd4549bc679f2a68df11b877740b0760b7c2/regex-2026.5.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65c8c8c37377794bd5b2f3ebe51919042bf17aec802e23c833d89782ed0c78af", size = 866089, upload-time = "2026-05-09T23:14:17.757Z" }, + { url = "https://files.pythonhosted.org/packages/e0/08/4d32af657e049b19cb62b02e46e38fe1518797bfb2203ee93a510b21b0dc/regex-2026.5.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b73ab8afcf66c622db143d1c6fda4e58e4d537ee4f125229ad47b1ab80f34c0", size = 911530, upload-time = "2026-05-09T23:14:20.353Z" }, + { url = "https://files.pythonhosted.org/packages/d9/27/2af43dd1dc201d1fecefda64a45f4ad0995855b92724f795a777b402ee69/regex-2026.5.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de5cf193997384ed2ca6f1cd4f78055b255d93d82d5a8cd6ba0d11c10b167e4", size = 800643, upload-time = "2026-05-09T23:14:22.265Z" }, + { url = "https://files.pythonhosted.org/packages/a4/dd/23a249047013b5321d4a60c4d2437462086f601b061776a525e5fba2a59f/regex-2026.5.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d641a8c9a61618047796d572a39a79b26167b0411d2c3031937b2fe2d081e2cf", size = 777223, upload-time = "2026-05-09T23:14:24.179Z" }, + { url = "https://files.pythonhosted.org/packages/94/6a/e85ed9538cd19586d0465076a4578a12e093ce776d15f3f8ce92733a8dd6/regex-2026.5.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24b2355ef5cc9aa5b8f07d17704face1c166fdcc2290fa7bd6e6c925655a8346", size = 785760, upload-time = "2026-05-09T23:14:26.065Z" }, + { url = "https://files.pythonhosted.org/packages/2a/c4/f25473209438638e947c55f9156fd8f236f74169229028cc99116380868e/regex-2026.5.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a24852d3c29ad9e47593593d8a247c44ccc3d0548ef12c822d6ed0810affe676", size = 860891, upload-time = "2026-05-09T23:14:28.17Z" }, + { url = "https://files.pythonhosted.org/packages/f9/f7/f4f86e3c74419c37370e91f150ae0c2ef7d34b2e0e4cdd5da046a02e4022/regex-2026.5.9-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:916714069da19329ef7de197dcbc77bb3104145c7c2c864dbfbe318f46b88b14", size = 765891, upload-time = "2026-05-09T23:14:30.06Z" }, + { url = "https://files.pythonhosted.org/packages/26/70/704d8e13765939146b1cd0ef4e2feb71d7929727d2290f026eed10095955/regex-2026.5.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fa411799ca8da32a8d38d020a88faa5b6f91657d284761352940ecf9f7c3bbdd", size = 851380, upload-time = "2026-05-09T23:14:32.123Z" }, + { url = "https://files.pythonhosted.org/packages/26/29/1a13582a8460038edc38e49f64ceb0dd7c60f5caba77571f4bf6601965d9/regex-2026.5.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e6da47d679b7010ef27556b6e0f99771b744936db1792a10ceac6547ae1503e", size = 789350, upload-time = "2026-05-09T23:14:34.799Z" }, + { url = "https://files.pythonhosted.org/packages/73/56/3dcafe34fc72e271d62ad9a291801e88a1457bb251c132f15fcc2e5aad1a/regex-2026.5.9-cp314-cp314-win32.whl", hash = "sha256:98bd73080e8756255137e1bd3f3f00295bbc5aa383c0e0f973920e9134d7c4ad", size = 272130, upload-time = "2026-05-09T23:14:36.729Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9c/02eebf0be95efe416c664db7fb8b6b05b7a0b06a7544f2884f2558b0526f/regex-2026.5.9-cp314-cp314-win_amd64.whl", hash = "sha256:ff8d372ac2acdc048d1c19916f27ee61bc5722728458ba6ca5052f2c72d51763", size = 280999, upload-time = "2026-05-09T23:14:39.126Z" }, + { url = "https://files.pythonhosted.org/packages/70/5a/1dd1abee76cb7a846a0bcf42fdc87e5720c3c33c24f3e37814310a513d9f/regex-2026.5.9-cp314-cp314-win_arm64.whl", hash = "sha256:e1d93bf647916292e8edcec150c07ddf3dc50179ccaf770c04a7f9e452155372", size = 273500, upload-time = "2026-05-09T23:14:41.059Z" }, + { url = "https://files.pythonhosted.org/packages/86/c1/c5f619b0057a7965cb78ec559c1d7a45ce8c99a35bea95483d64959a93d9/regex-2026.5.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:83d0ee4a57d1c87cb549e195ec300b8f0ec3a82eba66d835e4e2ed8634fe4499", size = 494269, upload-time = "2026-05-09T23:14:42.869Z" }, + { url = "https://files.pythonhosted.org/packages/05/2c/5d01f1aee33de4bbe60c8452945bfc8477ca7c5ae4450f6bfe711036cb36/regex-2026.5.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d3d7eb5c9a7f6df82ed3cfac9beb93882a5cbcb5b8b157b56cb2b3b276574ac1", size = 293954, upload-time = "2026-05-09T23:14:44.822Z" }, + { url = "https://files.pythonhosted.org/packages/7a/fe/e8988b2ae2108c6ef71bd4aa8d87fbe257976dd0810e826cd75f701c68b6/regex-2026.5.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:075160bf16658e16d35233300b8453aac25de4cbea808d22348b6979668e924d", size = 292405, upload-time = "2026-05-09T23:14:47.211Z" }, + { url = "https://files.pythonhosted.org/packages/79/34/d2b0937faa7859263f7f0a3c6b103a1296306be6952dc173d0154e9a2f49/regex-2026.5.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45375819235558a4ff1c4971dc32881f022613abdb180128f5cb4768c1765a1c", size = 811855, upload-time = "2026-05-09T23:14:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/80/fe/daf53a47457a8486db66c66c01ceb9c2303eecee3f87197f1e77eb1a736d/regex-2026.5.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ead4b163ac30a29574510cd4b3e2e985ac5290c05fc7095557d6a5f403fc31b5", size = 871189, upload-time = "2026-05-09T23:14:51.555Z" }, + { url = "https://files.pythonhosted.org/packages/1c/75/058fc4470cbfbf57d800aff1a0022b929a3f9fa553ee10a0cdf2070eb31f/regex-2026.5.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c6e4218fbdfbcd4f6c19efca40930d24a621bf4b48cb76bc6640543bd28ef20", size = 917485, upload-time = "2026-05-09T23:14:53.633Z" }, + { url = "https://files.pythonhosted.org/packages/88/e7/179cfda3a28bc843b5c6cfe7f79f23489c791ed95f151083803660878432/regex-2026.5.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6351571c8a42b505eb555c0dc47d740d0fb66977dc142919eea6f4325b7c56a0", size = 816369, upload-time = "2026-05-09T23:14:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/41/90/6f0cc422071688266d344fca8462d787cba0a2c144acb25721f9a61ec265/regex-2026.5.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:002205cafd2a9e78c6290c7d1df277bf3277b3b7a30e0b4bb0dac2e2e3f7cb2d", size = 785869, upload-time = "2026-05-09T23:14:58.602Z" }, + { url = "https://files.pythonhosted.org/packages/02/67/a31f1760f09c27b251ef39e9beb541f462cf977381d067faa764c2c0e393/regex-2026.5.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8abd33fef90b2a9efac5557d6033ca82d1195ed3a15fea5af15ba7b463c6a63b", size = 801427, upload-time = "2026-05-09T23:15:00.642Z" }, + { url = "https://files.pythonhosted.org/packages/e3/c4/1a80654597b6bc1e1ea0494824c31200e8a956abe290afae9b19a166a148/regex-2026.5.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:31037c82eccb44b7ea2e9e221d7c01429430e989a1f4b91ea5a855f6017b509a", size = 866482, upload-time = "2026-05-09T23:15:03.384Z" }, + { url = "https://files.pythonhosted.org/packages/d1/11/960724e06482c08466ff5611e242e86f80062949cdf6b4b9cc317b9dd93d/regex-2026.5.9-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5604dfd046dc37eca90250fc3be938b076c8059fa772ac0ed6f499b0f0fb0415", size = 773022, upload-time = "2026-05-09T23:15:05.625Z" }, + { url = "https://files.pythonhosted.org/packages/50/a8/a9979c3e7918280e93159ebcab5ef1a65116dd4f3bd6091be0eae4a126e8/regex-2026.5.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e1b1b4e496afbb24f4a62aba855ee4f88f25578927697b340702e48c9ee6bc2", size = 856642, upload-time = "2026-05-09T23:15:07.966Z" }, + { url = "https://files.pythonhosted.org/packages/fe/d4/a9b732f2f0072c0ab12227483abb24fffcb9f73f8a2b203df0a6d0434735/regex-2026.5.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be3372b9df6ddecff6486d37e19095a7b4973137caf5512407a89f4455361f41", size = 803552, upload-time = "2026-05-09T23:15:10.215Z" }, + { url = "https://files.pythonhosted.org/packages/d5/fe/1b3113817447a1d4155e4ac76d2e072f42c0bcba2f43fa8a0e756ea2cd91/regex-2026.5.9-cp314-cp314t-win32.whl", hash = "sha256:3ddd90103f9e5c471c49c7852ecc1fe27c7e45eb99e977aefe7caa4e779f4f58", size = 275746, upload-time = "2026-05-09T23:15:12.609Z" }, + { url = "https://files.pythonhosted.org/packages/92/73/93d42045302636c91f2e5ef588b65b84b01428f28ec77de256b1dfdfbe5c/regex-2026.5.9-cp314-cp314t-win_amd64.whl", hash = "sha256:ca518ed29c46eecba6010b15f1b9a479314d2de409536e71b6a13aa04e3b8a77", size = 285685, upload-time = "2026-05-09T23:15:15.086Z" }, + { url = "https://files.pythonhosted.org/packages/da/80/35b4c33c804a165a7f55289afda3ea9e3eb6d15800341a2d66455c0f1f30/regex-2026.5.9-cp314-cp314t-win_arm64.whl", hash = "sha256:5e41809d2683fcde7d5a8c87a6567ba1fb1ce0de9f31bff578de00a4b2d76daa", size = 275713, upload-time = "2026-05-09T23:15:16.98Z" }, +] + +[[package]] +name = "requests" +version = "2.34.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" }, +] + +[[package]] +name = "responses" +version = "0.25.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/d5/a7300764f8350420815b2c1abf30ebb78a7edd6eea586af784babdc2e9b0/responses-0.25.0.tar.gz", hash = "sha256:01ae6a02b4f34e39bffceb0fc6786b67a25eae919c6368d05eabc8d9576c2a66", size = 77681, upload-time = "2024-02-13T21:15:42.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/0b/bff1e6a5b646e6ff770deb6a292a96bd844ea13fb523ccbd9209fc4b90b8/responses-0.25.0-py3-none-any.whl", hash = "sha256:2f0b9c2b6437db4b528619a77e5d565e4ec2a9532162ac1a131a83529db7be1a", size = 55196, upload-time = "2024-02-13T21:15:42.978Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" }, + { url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" }, + { url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" }, + { url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" }, + { url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" }, + { url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" }, + { url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" }, + { url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" }, + { url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" }, + { url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" }, + { url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" }, + { url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" }, + { url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" }, + { url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" }, + { url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/07/06/b823a7e818c756d9a7123ba2cda7d07bc2dd32835648d1a7b7b7a05d848d/tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54", size = 155866, upload-time = "2026-03-25T20:21:31.65Z" }, + { url = "https://files.pythonhosted.org/packages/14/6f/12645cf7f08e1a20c7eb8c297c6f11d31c1b50f316a7e7e1e1de6e2e7b7e/tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a", size = 149887, upload-time = "2026-03-25T20:21:33.028Z" }, + { url = "https://files.pythonhosted.org/packages/5c/e0/90637574e5e7212c09099c67ad349b04ec4d6020324539297b634a0192b0/tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897", size = 243704, upload-time = "2026-03-25T20:21:34.51Z" }, + { url = "https://files.pythonhosted.org/packages/10/8f/d3ddb16c5a4befdf31a23307f72828686ab2096f068eaf56631e136c1fdd/tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f", size = 251628, upload-time = "2026-03-25T20:21:36.012Z" }, + { url = "https://files.pythonhosted.org/packages/e3/f1/dbeeb9116715abee2485bf0a12d07a8f31af94d71608c171c45f64c0469d/tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d", size = 247180, upload-time = "2026-03-25T20:21:37.136Z" }, + { url = "https://files.pythonhosted.org/packages/d3/74/16336ffd19ed4da28a70959f92f506233bd7cfc2332b20bdb01591e8b1d1/tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5", size = 251674, upload-time = "2026-03-25T20:21:38.298Z" }, + { url = "https://files.pythonhosted.org/packages/16/f9/229fa3434c590ddf6c0aa9af64d3af4b752540686cace29e6281e3458469/tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd", size = 97976, upload-time = "2026-03-25T20:21:39.316Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/71dfd96bcc1c775420cb8befe7a9d35f2e5b1309798f009dca17b7708c1e/tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36", size = 108755, upload-time = "2026-03-25T20:21:40.248Z" }, + { url = "https://files.pythonhosted.org/packages/83/7a/d34f422a021d62420b78f5c538e5b102f62bea616d1d75a13f0a88acb04a/tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd", size = 95265, upload-time = "2026-03-25T20:21:41.219Z" }, + { url = "https://files.pythonhosted.org/packages/3c/fb/9a5c8d27dbab540869f7c1f8eb0abb3244189ce780ba9cd73f3770662072/tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf", size = 155726, upload-time = "2026-03-25T20:21:42.23Z" }, + { url = "https://files.pythonhosted.org/packages/62/05/d2f816630cc771ad836af54f5001f47a6f611d2d39535364f148b6a92d6b/tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac", size = 149859, upload-time = "2026-03-25T20:21:43.386Z" }, + { url = "https://files.pythonhosted.org/packages/ce/48/66341bdb858ad9bd0ceab5a86f90eddab127cf8b046418009f2125630ecb/tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662", size = 244713, upload-time = "2026-03-25T20:21:44.474Z" }, + { url = "https://files.pythonhosted.org/packages/df/6d/c5fad00d82b3c7a3ab6189bd4b10e60466f22cfe8a08a9394185c8a8111c/tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853", size = 252084, upload-time = "2026-03-25T20:21:45.62Z" }, + { url = "https://files.pythonhosted.org/packages/00/71/3a69e86f3eafe8c7a59d008d245888051005bd657760e96d5fbfb0b740c2/tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15", size = 247973, upload-time = "2026-03-25T20:21:46.937Z" }, + { url = "https://files.pythonhosted.org/packages/67/50/361e986652847fec4bd5e4a0208752fbe64689c603c7ae5ea7cb16b1c0ca/tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba", size = 256223, upload-time = "2026-03-25T20:21:48.467Z" }, + { url = "https://files.pythonhosted.org/packages/8c/9a/b4173689a9203472e5467217e0154b00e260621caa227b6fa01feab16998/tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6", size = 98973, upload-time = "2026-03-25T20:21:49.526Z" }, + { url = "https://files.pythonhosted.org/packages/14/58/640ac93bf230cd27d002462c9af0d837779f8773bc03dee06b5835208214/tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7", size = 109082, upload-time = "2026-03-25T20:21:50.506Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2f/702d5e05b227401c1068f0d386d79a589bb12bf64c3d2c72ce0631e3bc49/tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232", size = 96490, upload-time = "2026-03-25T20:21:51.474Z" }, + { url = "https://files.pythonhosted.org/packages/45/4b/b877b05c8ba62927d9865dd980e34a755de541eb65fffba52b4cc495d4d2/tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4", size = 164263, upload-time = "2026-03-25T20:21:52.543Z" }, + { url = "https://files.pythonhosted.org/packages/24/79/6ab420d37a270b89f7195dec5448f79400d9e9c1826df982f3f8e97b24fd/tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c", size = 160736, upload-time = "2026-03-25T20:21:53.674Z" }, + { url = "https://files.pythonhosted.org/packages/02/e0/3630057d8eb170310785723ed5adcdfb7d50cb7e6455f85ba8a3deed642b/tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d", size = 270717, upload-time = "2026-03-25T20:21:55.129Z" }, + { url = "https://files.pythonhosted.org/packages/7a/b4/1613716072e544d1a7891f548d8f9ec6ce2faf42ca65acae01d76ea06bb0/tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41", size = 278461, upload-time = "2026-03-25T20:21:56.228Z" }, + { url = "https://files.pythonhosted.org/packages/05/38/30f541baf6a3f6df77b3df16b01ba319221389e2da59427e221ef417ac0c/tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c", size = 274855, upload-time = "2026-03-25T20:21:57.653Z" }, + { url = "https://files.pythonhosted.org/packages/77/a3/ec9dd4fd2c38e98de34223b995a3b34813e6bdadf86c75314c928350ed14/tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f", size = 283144, upload-time = "2026-03-25T20:21:59.089Z" }, + { url = "https://files.pythonhosted.org/packages/ef/be/605a6261cac79fba2ec0c9827e986e00323a1945700969b8ee0b30d85453/tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8", size = 108683, upload-time = "2026-03-25T20:22:00.214Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/da524626d3b9cc40c168a13da8335fe1c51be12c0a63685cc6db7308daae/tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26", size = 121196, upload-time = "2026-03-25T20:22:01.169Z" }, + { url = "https://files.pythonhosted.org/packages/5a/cd/e80b62269fc78fc36c9af5a6b89c835baa8af28ff5ad28c7028d60860320/tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396", size = 100393, upload-time = "2026-03-25T20:22:02.137Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/57/6d7303a77ae439d9189108f76c0c4fd89ee5e2cc8387bffb55232565c4ed/tornado-6.5.6.tar.gz", hash = "sha256:9a365179fe8ff6b8766f602c0f67c185d778193e9bdd828b19f0b6ed7764177d", size = 518139, upload-time = "2026-05-27T15:35:54.646Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/0d/b4f481e18c5a51864e6d12b9a05ecf72919696680b747c958c3fc1f4fbae/tornado-6.5.6-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:65fcfaafb079435c2c19dc9e07c0f1cf0fa9051759ed0a7d0a3ba7ea7f64919c", size = 447737, upload-time = "2026-05-27T15:35:38.122Z" }, + { url = "https://files.pythonhosted.org/packages/9e/9c/5430c39fcab1144d35860f457b15e9c08b4bc7ac86764354204e983d6183/tornado-6.5.6-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:38bc01b4acacded2de63ae78023548e41ebe6fbed3ec05a796d7ae3ad893887e", size = 445899, upload-time = "2026-05-27T15:35:40.519Z" }, + { url = "https://files.pythonhosted.org/packages/8b/79/fa7e14a2f939c807a8d30619b4eb604eab219601b78792516ebe22d40cf9/tornado-6.5.6-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b942e6a137fda31ff54bf8e6e2c8d1c37f1f50583f3ed53fb840b53b9601d104", size = 448964, upload-time = "2026-05-27T15:35:42.106Z" }, + { url = "https://files.pythonhosted.org/packages/a7/71/bd67d5f5199f937dafe03a49a37989f60f600ff6fef34c79412a829d97bd/tornado-6.5.6-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8666946e70171b8c3f1fc9b7876fac492e84822c4c7f3746f4e8f8bc9ac92a79", size = 449935, upload-time = "2026-05-27T15:35:43.906Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a4/c24388c9cf5b3c3a513b56a158af9f23092c9a2810d789e294310797df21/tornado-6.5.6-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1c34cfab7ad6d104f052f55de06d39bbafc5885cfeb4da688803308dbcfa90b7", size = 449767, upload-time = "2026-05-27T15:35:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/a5/eb/6a07ad550c3f7b37244bd0becdf293ec3d3e961783d8b720a97df50de1b2/tornado-6.5.6-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:385f35e4e22fb52551dfcda4cdc8c30c61c2c001aef5ddad99cdfe116952efd3", size = 449174, upload-time = "2026-05-27T15:35:47.485Z" }, + { url = "https://files.pythonhosted.org/packages/bb/84/3469e098dccdb6763130e06aacd786bb4363fca7b590a55c101ddf34ed30/tornado-6.5.6-cp39-abi3-win32.whl", hash = "sha256:db475f1b67b2809b10bb16264829087724ca8d24fe4ed47f7b8675cae453ef86", size = 450230, upload-time = "2026-05-27T15:35:49.322Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3c/273a04e0b9dd9016f1685cca0c1c8795a71ac88a34a8c889a0b443483226/tornado-6.5.6-cp39-abi3-win_amd64.whl", hash = "sha256:6739bf1e8eb09230f1280ddbd3236f0309db70f2c551a8dbc40f62babdf82f79", size = 450667, upload-time = "2026-05-27T15:35:51.194Z" }, + { url = "https://files.pythonhosted.org/packages/02/98/0cffe22a224f60c5fb1e3aa0b76f9da2e1ca78b0e9545e3d077c68ce60a7/tornado-6.5.6-cp39-abi3-win_arm64.whl", hash = "sha256:2543597b24a695d72338a9a77818362d72387c03ae173f1f169eadc5c91466ac", size = 449690, upload-time = "2026-05-27T15:35:52.902Z" }, +] + +[[package]] +name = "tox" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "chardet" }, + { name = "colorama" }, + { name = "filelock" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "pluggy" }, + { name = "pyproject-api" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "virtualenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8f/e2/98cbdadaa14d53b0f37ffcf4cbb1652ffb21f8b2f300e43f17167136af1c/tox-4.14.2.tar.gz", hash = "sha256:0defb44f6dafd911b61788325741cc6b2e12ea71f987ac025ad4d649f1f1a104", size = 178515, upload-time = "2024-03-22T15:44:45.756Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/7e/496c1b338a9ef244a03a654fcb9e922c37a9c547d00e73f99f3a94ac838e/tox-4.14.2-py3-none-any.whl", hash = "sha256:2900c4eb7b716af4a928a7fdc2ed248ad6575294ed7cfae2ea41203937422847", size = 155382, upload-time = "2024-03-22T15:44:43.079Z" }, +] + +[[package]] +name = "tox-pyenv" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tox" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/0e/0208374ee677ccb9dbb4e9bc23f6d304bef6b881cc6ccb8bec2ae81b1e99/tox-pyenv-1.1.0.tar.gz", hash = "sha256:916c2213577aec0b3b5452c5bfb32fd077f3a3196f50a81ad57d7ef3fc2599e4", size = 4925, upload-time = "2017-08-29T23:13:22.524Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/56/ee1b984fbfb745cc637009dcb054b5fc9399c838b465c634846fd1550511/tox_pyenv-1.1.0-py2.py3-none-any.whl", hash = "sha256:e470c18af115fe52eeff95e7e3cdd0793613eca19709966fc2724b79d55246cb", size = 6824, upload-time = "2017-08-29T23:13:20.508Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "virtualenv" +version = "21.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "platformdirs" }, + { name = "python-discovery" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e1/0d/4e93c8e6d1001a75763f87d8f5ecda8ebc7f4aa2153dddfaf4ae8892821a/virtualenv-21.4.2.tar.gz", hash = "sha256:38e6ee0a555615c0ea9da2ac7e9998fe8dc3b911dd33ad8eaad2020957653b0c", size = 7613326, upload-time = "2026-05-31T17:01:22.827Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/c4/557dc082be035381b85fdb2b74e21d3d21b57750b74f2b47a32f3a639ff9/virtualenv-21.4.2-py3-none-any.whl", hash = "sha256:854210ca524a1a4d0d744734f4acbc721c3ffe163b85bbf5d56d14d5ae2f0fae", size = 7594079, upload-time = "2026-05-31T17:01:20.735Z" }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390, upload-time = "2024-11-01T14:06:24.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389, upload-time = "2024-11-01T14:06:27.112Z" }, + { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020, upload-time = "2024-11-01T14:06:29.876Z" }, + { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393, upload-time = "2024-11-01T14:06:31.756Z" }, + { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392, upload-time = "2024-11-01T14:06:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019, upload-time = "2024-11-01T14:06:34.963Z" }, + { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471, upload-time = "2024-11-01T14:06:37.745Z" }, + { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449, upload-time = "2024-11-01T14:06:39.748Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054, upload-time = "2024-11-01T14:06:41.009Z" }, + { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480, upload-time = "2024-11-01T14:06:42.952Z" }, + { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451, upload-time = "2024-11-01T14:06:45.084Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057, upload-time = "2024-11-01T14:06:47.324Z" }, + { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902, upload-time = "2024-11-01T14:06:53.119Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380, upload-time = "2024-11-01T14:06:55.19Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, +]