pax_global_header                                                                                   0000666 0000000 0000000 00000000064 15000473553 0014514 g                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        52 comment=3eae1c74e06a59a4d04147146be1bafbd53fd1c1
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            aioxmlrpc-0.10.0/                                                                                   0000775 0000000 0000000 00000000000 15000473553 0013570 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/.editorconfig                                                                      0000664 0000000 0000000 00000000267 15000473553 0016252 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        [*.py]
indent_style = space
indent_size = 4
[*.rst]
indent_style = space
indent_size = 3
[*.toml]
indent_style = space
indent_size = 2
[*.yml]
indent_style = space
indent_size = 2
                                                                                                                                                                                                                                                                                                                                         aioxmlrpc-0.10.0/.github/                                                                           0000775 0000000 0000000 00000000000 15000473553 0015130 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/.github/workflows/                                                                 0000775 0000000 0000000 00000000000 15000473553 0017165 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/.github/workflows/build-artifacts.yml                                              0000664 0000000 0000000 00000002323 15000473553 0022765 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        # Build envsub tarballs for supported python.
name: "Build artifact"
on:
  workflow_call:
    inputs:
      release-version:
        required: true
        type: string
      dry-run:
        required: true
        type: boolean
      python-version:
        required: true
        type: string
  pull_request:
    paths:
      # When we change pyproject.toml, we want to ensure that the maturin builds still work.
      - pyproject.toml
      # And when we change this workflow itself...
      - .github/workflows/build-artifacts.yml
concurrency:
  group: sdist-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
jobs:
  sdist:
    name: Build artifact for ${{ inputs.release-version }} ${{ inputs.dry-run && '(dry-run)' || '' }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ inputs.python-version }}
      - name: Install uv
        uses: astral-sh/setup-uv@v3
      - name: Install the project
        run: uv sync
      - name: Build tarball
        run: uv build
      - name: "Upload sdist"
        uses: actions/upload-artifact@v4
        with:
          name: pypi_files
          path: dist/*
                                                                                                                                                                                                                                                                                                             aioxmlrpc-0.10.0/.github/workflows/publish-pypi.yml                                                 0000664 0000000 0000000 00000001616 15000473553 0022341 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        # Publish a release to PyPI.
#
name: "Publish to PyPI"
on:
  workflow_call:
    inputs:
      release-version:
        required: true
        type: string
      dry-run:
        required: true
        type: boolean
jobs:
  pypi-publish:
    name: Upload to PyPI ${{ inputs.release-version }} ${{ inputs.dry-run && '(dry-run)' || '' }}
    runs-on: ubuntu-latest
    if: ${{ !inputs.dry-run }}
    permissions:
      # This permission is needed for private repositories.
      contents: read
      # IMPORTANT: this permission is mandatory for trusted publishing
      id-token: write
    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: pypi_files
          path: dist
          merge-multiple: true
      - uses: pdm-project/setup-pdm@v4
        with:
          python-version: 3.12
      - name: Publish package distributions to PyPI
        run: pdm publish --no-build
                                                                                                                  aioxmlrpc-0.10.0/.github/workflows/release.yml                                                      0000664 0000000 0000000 00000004403 15000473553 0021331 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        name: Release
on:
  push:
    tags:
      - 'v*'       # Automatically trigger on version tags
      - 'dry-run'
  workflow_dispatch:
    inputs:
      tag:
        description: "Release Tag"
        required: true
        default: "dry-run"
        type: string
env:
  PYTHON_VERSION: "3.12"
jobs:
  plan:
    runs-on: ubuntu-latest
    outputs:
      release_version: ${{ steps.release-version.outputs.release_version }}
      dry-run: ${{ steps.release-version.outputs.dry_run }}
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4
    - name: Set Release Version
      id: release-version
      run: |
        if [ "${{ github.event_name }}" == "push" ]; then
          echo "release_version=${{ github.ref_name }}" >> $GITHUB_OUTPUT
          if [ "${{ github.ref_name }}" == "dry-run" ]; then
            echo "dry_run=true" >> $GITHUB_OUTPUT
          else
            echo "dry_run=false" >> $GITHUB_OUTPUT
          fi
        else
          version="${{ github.event.inputs.tag || 'dry-run' }}"
          if [ "${version}" == "dry-run" ]; then
            echo "release_version=latest" >> $GITHUB_OUTPUT
            echo "dry_run=true" >> $GITHUB_OUTPUT
          else
            echo "release_version=${version}" >> $GITHUB_OUTPUT
            echo "dry_run=false" >> $GITHUB_OUTPUT
          fi
        fi
    - name: Display Release Version
      run: echo "The release version is ${{ steps.release-version.outputs.release_version }}"
  unit-tests:
    uses: ./.github/workflows/tests.yml
  build-artifacts:
    needs:
      - plan
      - unit-tests
    uses: ./.github/workflows/build-artifacts.yml
    with:
      release-version: ${{ needs.plan.outputs.release_version }}
      dry-run: ${{ needs.plan.outputs.dry-run == 'true' }}
      python-version: '3.12'
  tests-artifacts:
    needs:
      - plan
      - build-artifacts
    uses: ./.github/workflows/tests-artifacts.yml
    with:
      release-version: ${{ needs.plan.outputs.release_version }}
      dry-run: ${{ needs.plan.outputs.dry-run == 'true' }}
  publish-pypi:
    needs:
      - plan
      - tests-artifacts
    uses: ./.github/workflows/publish-pypi.yml
    with:
      release-version: ${{ needs.plan.outputs.release_version }}
      dry-run: ${{ needs.plan.outputs.dry-run == 'true' }}
                                                                                                                                                                                                                                                             aioxmlrpc-0.10.0/.github/workflows/tests-artifacts.yml                                              0000664 0000000 0000000 00000002155 15000473553 0023033 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        name: tests artifacts
# Controls when the workflow will run
on:
  # Allows you to run this workflow manually from the Actions tab
  workflow_call:
    inputs:
      release-version:
        required: true
        type: string
        description: "release number"
      dry-run:
        required: true
        type: boolean
        description: "blank run means that the release will not be pushed"
jobs:
  test-sdist:
    name: test tarball archive of ${{ inputs.release-version }} ${{ inputs.dry-run && '(dry-run)' || '' }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
    steps:
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - uses: actions/download-artifact@v4
        with:
          pattern: pypi_files
          path: dist
          merge-multiple: true
      - name: "Install"
        run: |
          pip install dist/aioxmlrpc-*.whl --force-reinstall
      - name: "Test sdist"
        run: |
          python -c "from aioxmlrpc import __version__; print(__version__, end='')"
                                                                                                                                                                                                                                                                                                                                                                                                                   aioxmlrpc-0.10.0/.github/workflows/tests.yml                                                        0000664 0000000 0000000 00000003051 15000473553 0021051 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        name: tests
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:
  workflow_call:
jobs:
  tests:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4
      - uses: chartboost/ruff-action@v1
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - name: Install uv
        uses: astral-sh/setup-uv@v3
      - name: Install the project
        run: uv sync --group dev
      - name: Check types
        run: |
          uv run mypy src/aioxmlrpc/
      - name: Run tests
        run: |
          uv run pytest tests  --junitxml=junit/test-results-${{ matrix.python-version }}.xml --cov=aioxmlrpc --cov-report=xml --cov-report=html
      - name: Upload pytest test results
        uses: actions/upload-artifact@v4
        with:
          name: pytest-results-${{ matrix.python-version }}
          path: junit/test-results-${{ matrix.python-version }}.xml
      - name: Upload test results to Codecov
        if: ${{ !cancelled() }} && matrix.python-version == '3.12' && github.event_name != 'workflow_dispatch'
        uses: codecov/test-results-action@v1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
      - name: Codecov
        if: matrix.python-version == '3.12' && github.event_name != 'workflow_dispatch'
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: coverage.xml
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       aioxmlrpc-0.10.0/.gitignore                                                                         0000664 0000000 0000000 00000001015 15000473553 0015555 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
venv*
*.log
# Sphinx documentation
docs/_build/
# pycharm
.idea/
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   aioxmlrpc-0.10.0/CHANGELOG.rst                                                                      0000664 0000000 0000000 00000003772 15000473553 0015622 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        0.10.0  - Released on 2025-04-18
--------------------------------
* Add support of aioxmlrpc.server
* Add support of MultiCall
* Fix httpx warning
0.9.1  - Released on 2024-12-06
-------------------------------
* Fix for httpx 0.28 (Ondra Geršl)
0.9.0  - Released on 2024-11-06
-------------------------------
* Add typing.
* Breaking change: drop support of python 3.7 and python 3.8.
* Switch packaging to uv / pdm.
* CI update
* Update LICENSE to MIT
0.8.1  - Released on 2024-04-25
-------------------------------
* Add PEP-517 metadata in python package
0.8.0  - Released on 2024-04-09
-------------------------------
* Update dependencies
0.7.0 - Released on 2023-05-08
------------------------------
* New feature: Add missing context kwargs argument for ServerProxy compatibility.
* Breaking change: Argument headers must be a kwargs like in the standard library.
* Breaking change: Non standard arguments timeout and session must be kwargs too.
* Update dependencies
0.6.5 - Released on 2023-04-27
------------------------------
* Update dependencies
0.6.4 - Released on 2022-06-02
------------------------------
* Update dependencies
0.6.3 released on 2021-12-15
----------------------------
* Fix ProtocolError
0.6.2 released on 2021-12-13
----------------------------
* Update httpx to ^0.21.1
* Switch CI to github action
0.6.1 released on 2021-10-06
----------------------------
* Switch to httpx
0.5 released on 2017-09-10
--------------------------
* Remove compatibility with aiohttp < 1.0 (Ovv)
0.4 released on 2017-03-30
--------------------------
* Fix NXDOMAIN Exception handling (Vladimir Rutsky)
* Fix cancel of futures handling (Gustavo Tavares Cabral)
0.3 released on 2016-06-16
--------------------------
* Fix socket closing issue
0.2 released on 2016-05-26
--------------------------
* Update compatibility for aiohttp >= 0.20
.. important::
   This break the compatibility of python 3.3
0.1 released on 2014-05-17
--------------------------
* Initial version implementing ``aioxmlrpc.client``
      aioxmlrpc-0.10.0/CONTRIBUTORS.rst                                                                   0000664 0000000 0000000 00000000224 15000473553 0016255 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        Contributors
============
A. Jesse Jiryu Davis
Gustavo Tavares Cabral
Vladimir Rutsky
nibrag
sayoun
Ondra Geršl
Romuald Brunet
Sylvain Peyrefitte
                                                                                                                                                                                                                                                                                                                                                                            aioxmlrpc-0.10.0/Justfile                                                                           0000664 0000000 0000000 00000002635 15000473553 0015306 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        package := 'aioxmlrpc'
default_unittest_suite := 'tests/unittests'
default_functest_suite := 'tests/functionals'
install:
    uv sync --group dev
test: lint typecheck unittest
lint:
    uv run ruff check .
typecheck:
    uv run mypy src/ tests/
unittest test_suite=default_unittest_suite:
    uv run pytest -sxv {{test_suite}}
lf:
    uv run pytest -sxvvv --lf
cov test_suite=default_unittest_suite:
    rm -f .coverage
    rm -rf htmlcov
    uv run pytest --cov-report=html --cov={{package}} {{test_suite}}
    xdg-open htmlcov/index.html
fmt:
    uv run ruff check --fix .
    uv run ruff format src tests
release major_minor_patch: test && changelog
    #! /bin/bash
    # Try to bump the version first
    if ! uvx pdm bump {{major_minor_patch}}; then
        # If it fails, check if pdm-bump is installed
        if ! uvx pdm self list | grep -q pdm-bump; then
            # If not installed, add pdm-bump
            uvx pdm self add pdm-bump
        fi
        # Attempt to bump the version again
        uvx pdm bump {{major_minor_patch}}
    fi
    uv sync
changelog:
    uv run python scripts/write_changelog.py
    cat CHANGELOG.rst >> CHANGELOG.rst.new
    rm CHANGELOG.rst
    mv CHANGELOG.rst.new CHANGELOG.rst
    $EDITOR CHANGELOG.rst
publish:
    git commit -am "Release $(uv run scripts/get_version.py)"
    git tag "v$(uv run scripts/get_version.py)"
    git push origin "v$(uv run scripts/get_version.py)"
                                                                                                   aioxmlrpc-0.10.0/LICENSE                                                                            0000664 0000000 0000000 00000002110 15000473553 0014567 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        MIT License
Copyright (c) 2014-2024, Guillaume Gauvrit and Contibutors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
                                                                                                                                                                                                                                                                                                                                                                                                                                                        aioxmlrpc-0.10.0/README.rst                                                                         0000664 0000000 0000000 00000004352 15000473553 0015263 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        =========
aioxmlrpc
=========
.. image:: https://github.com/mardiros/aioxmlrpc/actions/workflows/tests.yml/badge.svg
   :target: https://github.com/mardiros/aioxmlrpc/actions/workflows/tests.yml
.. image:: https://codecov.io/gh/mardiros/aioxmlrpc/branch/master/graph/badge.svg?token=BR3KttC9uJ
   :target: https://codecov.io/gh/mardiros/aioxmlrpc
Asyncio version of the standard lib ``xmlrpc``
``aioxmlrpc.client``, which works like ``xmlrpc.client`` but uses coroutines,
has been implemented.
``aioxmlrpc.client`` is based on ``httpx`` for the transport, and just patch
the necessary from the python standard library to get it working.
``aioxmlrpc.server``, which works much like ``xmlrpc.server``, but runs on the asyncio
event loop and handles remote procedure calls (RPC) using both regular functions and coroutines.
``aioxmlrpc.server`` is based on ``starlette`` and ``uvicorn`` for handling HTTP.
Installation
------------
aioxmlrpc is available on PyPI, it can simply be installed with your favorite
tool, example with pip here.
::
    pip install aioxmlrpc
The server dependencies is installed using the extra syntax.
::
   pip install "aioxmlrpc[server]"
Getting Started
---------------
Client
~~~~~~
This example show how to print the current version of the Gandi XML-RPC api.
::
    import asyncio
    from aioxmlrpc.client import ServerProxy
    async def print_gandi_api_version():
        api = ServerProxy('https://rpc.gandi.net/xmlrpc/')
        result = await api.version.info()
        print(result)
    if __name__ == '__main__':
        loop = asyncio.get_event_loop()
        loop.run_until_complete(print_gandi_api_version())
        loop.stop()
Run the example
::
    uv run examples/gandi_api_version.py
Server
~~~~~~
This example show an exemple of the server side.
::
   import asyncio
   from aioxmlrpc.server import SimpleXMLRPCServer
   class Api:
      def info(self):
         return "1.0.0"
      async def sleep(self):
         await asyncio.sleep(1)
         return "done"
   async def main():
      server = SimpleXMLRPCServer(("0.0.0.0", 8080))
      server.register_instance(Api(), allow_dotted_names=True)
      await server.serve_forever()
   if __name__ == "__main__":
      asyncio.run(main())
                                                                                                                                                                                                                                                                                      aioxmlrpc-0.10.0/examples/                                                                          0000775 0000000 0000000 00000000000 15000473553 0015406 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/examples/gandi_api_version.py                                                      0000775 0000000 0000000 00000000516 15000473553 0021445 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        #!/usr/bin/env python
import asyncio
from aioxmlrpc.client import ServerProxy
ENDPOINT = "https://rpc.gandi.net/xmlrpc/"
async def main():
    client = ServerProxy(ENDPOINT, allow_none=True)
    for _ in range(5):
        data = await client.version.info()
        print(data)
if __name__ == "__main__":
    asyncio.run(main())
                                                                                                                                                                                  aioxmlrpc-0.10.0/examples/server.py                                                                 0000664 0000000 0000000 00000000642 15000473553 0017270 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        import asyncio
from aioxmlrpc.server import SimpleXMLRPCServer
class Api:
    def info(self):
        return "1.0.0"
    async def sleep(self):
        await asyncio.sleep(1)
        return "done"
async def main():
    server = SimpleXMLRPCServer(("0.0.0.0", 8080))
    server.register_instance(Api(), allow_dotted_names=True)
    await server.serve_forever()
if __name__ == "__main__":
    asyncio.run(main())
                                                                                              aioxmlrpc-0.10.0/pyproject.toml                                                                     0000664 0000000 0000000 00000004264 15000473553 0016512 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        [project]
name = "aioxmlrpc"
description = "XML-RPC client for asyncio"
classifiers = [
  "Development Status :: 5 - Production/Stable",
  "Framework :: AsyncIO",
  "Intended Audience :: Developers",
  "Intended Audience :: Information Technology",
  "License :: OSI Approved :: MIT License",
  "Topic :: Internet :: WWW/HTTP",
  "Topic :: Software Development :: Libraries",
  "Topic :: System :: Networking",
  "Typing :: Typed",
  "Programming Language :: Python :: 3.9",
  "Programming Language :: Python :: 3.10",
  "Programming Language :: Python :: 3.11",
  "Programming Language :: Python :: 3.12",
  "Programming Language :: Python :: 3.13",
]
version = "0.10.0"
readme = "README.rst"
license = { text = "MIT License" }
authors = [{ name = "Guillaume Gauvrit", email = "guillaume@gauvr.it" }]
requires-python = ">=3.9"
dependencies = ["httpx >=0.24, <1"]
[project.optional-dependencies]
server = ["starlette>=0.46.2", "uvicorn>=0.34.1"]
[dependency-groups]
dev = [
  "mypy>=1.13.0,<2",
  "pytest >=8.3.3,<9",
  "pytest-asyncio >=0.24.0",
  "pytest-cov >=6.0.0,<7",
  "starlette>=0.46.2",
  "uvicorn>=0.34.1",
]
[tool.pdm.build]
includes = ["src", "CHANGELOG.rst", "CONTRIBUTORS.rst"]
excludes = ["tests"]
[project.urls]
Homepage = "https://github.com/mardiros/aioxmlrpc"
Documentation = "https://github.com/mardiros/aioxmlrpc/blob/main/README.rst"
Repository = "https://github.com/mardiros/aioxmlrpc.git"
Issues = "https://github.com/mardiros/aioxmlrpc/issues"
Changelog = "https://mardiros.github.io/aioxmlrpc/user/changelog.html"
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
[[tool.mypy.overrides]]
disallow_any_generics = true
disallow_untyped_defs = true
module = "aioxmlrpc.*"
[tool.pyright]
ignore = ["examples"]
include = ["src", "tests"]
reportPrivateUsage = false
reportUnknownMemberType = false
reportUnknownParameterType = false
reportUnknownVariableType = false
reportShadowedImports = false
typeCheckingMode = "strict"
venvPath = ".venv"
[tool.coverage.report]
exclude_lines = [
  "if TYPE_CHECKING:",
  "except ImportError:",
  "\\s+\\.\\.\\.$",
  "# coverage: ignore",
]
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"
                                                                                                                                                                                                                                                                                                                                            aioxmlrpc-0.10.0/scripts/                                                                           0000775 0000000 0000000 00000000000 15000473553 0015257 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/scripts/get_version.py                                                             0000664 0000000 0000000 00000000161 15000473553 0020153 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        import aioxmlrpc
__version__ = aioxmlrpc.__version__
if __name__ == "__main__":
    print(__version__, end="")
                                                                                                                                                                                                                                                                                                                                                                                                               aioxmlrpc-0.10.0/scripts/write_changelog.py                                                         0000664 0000000 0000000 00000000627 15000473553 0020777 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        #!/usr/bin/env python3
import datetime
from importlib.metadata import version
header = (
    f"{version('aioxmlrpc')}  - "
    f"Released on {datetime.datetime.now().date().isoformat()}"
)
with open("CHANGELOG.rst.new", "w") as changelog:
    changelog.write(header)
    changelog.write("\n")
    changelog.write("-" * len(header))
    changelog.write("\n")
    changelog.write("* please write here \n\n")
                                                                                                         aioxmlrpc-0.10.0/src/                                                                               0000775 0000000 0000000 00000000000 15000473553 0014357 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/src/aioxmlrpc/                                                                     0000775 0000000 0000000 00000000000 15000473553 0016355 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/src/aioxmlrpc/__init__.py                                                          0000664 0000000 0000000 00000000166 15000473553 0020471 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        """
XML-RPC Protocol for ``asyncio``
"""
from importlib import metadata
__version__ = metadata.version("aioxmlrpc")
                                                                                                                                                                                                                                                                                                                                                                                                          aioxmlrpc-0.10.0/src/aioxmlrpc/client.py                                                            0000664 0000000 0000000 00000014347 15000473553 0020216 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        """
XML-RPC Client with asyncio.
This module adapt the ``xmlrpc.client`` module of the standard library to
work with asyncio.
"""
import asyncio
import logging
import ssl
from typing import (
    Any,
    Awaitable,
    Callable,
    Optional,
    Union,
    cast,
)
from xmlrpc import client as xmlrpc
import httpx
__ALL__ = ["ServerProxy", "Fault", "ProtocolError", "MultiCall"]
RPCResult = Any
RPCParameters = Any
# you don't have to import xmlrpc.client from your code
Fault = xmlrpc.Fault
ProtocolError = xmlrpc.ProtocolError
log = logging.getLogger(__name__)
class _Method:
    # some magic to bind an XML-RPC method to an RPC server.
    # supports "nested" methods (e.g. examples.getStateName)
    def __init__(
        self, send: Callable[[str, RPCParameters], Awaitable[RPCResult]], name: str
    ) -> None:
        self.__send = send
        self.__name = name
    def __getattr__(self, name: str) -> "_Method":
        return _Method(self.__send, "%s.%s" % (self.__name, name))
    async def __call__(self, *args: RPCParameters) -> RPCResult:
        ret = await self.__send(self.__name, args)
        return ret
class AioTransport(xmlrpc.Transport):
    """
    ``xmlrpc.Transport`` subclass for asyncio support
    """
    def __init__(
        self,
        session: httpx.AsyncClient,
        use_https: bool,
        *,
        use_datetime: bool = False,
        use_builtin_types: bool = False,
        auth: Optional[httpx._types.AuthTypes] = None,
        timeout: Optional[httpx._types.TimeoutTypes] = None,
    ):
        super().__init__(use_datetime, use_builtin_types)
        self.use_https = use_https
        self._session = session
        self.auth = auth or httpx.USE_CLIENT_DEFAULT
        self.timeout = timeout
    async def request(  # type: ignore
        self,
        host: str,
        handler: str,
        request_body: bytes,
        verbose: bool = False,
    ) -> RPCResult:
        """
        Send the XML-RPC request, return the response.
        This method is a coroutine.
        """
        url = self._build_url(host, handler)
        response = None
        try:
            response = await self._session.post(
                url,
                content=request_body,
                auth=self.auth,
                timeout=self.timeout,
            )
            body = response.text
            if response.status_code != 200:
                raise ProtocolError(
                    url,
                    response.status_code,
                    body,
                    # response.headers is a case insensitive dict from httpx,
                    # the ProtocolError is typed as simple dict
                    cast(dict[str, str], response.headers),
                )
        except asyncio.CancelledError:
            raise
        except ProtocolError:
            raise
        except Exception as exc:
            log.error("Unexpected error", exc_info=True)
            if response is not None:
                errcode = response.status_code
                headers = cast(dict[str, str], response.headers)  # coverage: ignore
            else:
                errcode = 0
                headers = {}
            raise ProtocolError(url, errcode, str(exc), headers)
        return self.parse_response(body)
    def parse_response(  # type: ignore
        self,
        body: str,
    ) -> RPCResult:
        """
        Parse the xmlrpc response.
        """
        p, u = self.getparser()
        p.feed(body)
        p.close()
        return u.close()
    def _build_url(self, host: str, handler: str) -> str:
        """
        Build a url for our request based on the host, handler and use_http
        property
        """
        scheme = "https" if self.use_https else "http"
        return f"{scheme}://{host}{handler}"
class ServerProxy(xmlrpc.ServerProxy):
    """
    ``xmlrpc.ServerProxy`` subclass for asyncio support
    """
    def __init__(
        self,
        uri: str,
        encoding: Optional[str] = None,
        verbose: bool = False,
        allow_none: bool = False,
        use_datetime: bool = False,
        use_builtin_types: bool = False,
        auth: Optional[httpx._types.AuthTypes] = None,
        *,
        headers: Optional[dict[str, Any]] = None,
        context: Optional[Union[bool, ssl.SSLContext]] = None,
        timeout: httpx._types.TimeoutTypes = 5.0,
        session: Optional[httpx.AsyncClient] = None,
    ) -> None:
        if not headers:
            headers = {
                "User-Agent": "python/aioxmlrpc",
                "Accept": "text/xml",
                "Content-Type": "text/xml",
            }
        if context is None:
            context = True
        self._session = session or httpx.AsyncClient(headers=headers, verify=context)
        transport = AioTransport(
            use_https=uri.startswith("https://"),
            session=self._session,
            auth=auth,
            timeout=timeout,
            use_datetime=use_datetime,
            use_builtin_types=use_builtin_types,
        )
        super().__init__(
            uri,
            transport,
            encoding,
            verbose,
            allow_none,
            use_datetime,
            use_builtin_types,
        )
    async def __request(  # type: ignore
        self,
        methodname: str,
        params: RPCParameters,
    ) -> RPCResult:
        # call a method on the remote server
        request = xmlrpc.dumps(
            params, methodname, encoding=self.__encoding, allow_none=self.__allow_none
        ).encode(self.__encoding)
        response = await self.__transport.request(  # type: ignore
            self.__host, self.__handler, request, verbose=self.__verbose
        )
        if len(response) == 1:  # type: ignore
            response = response[0]
        return response
    def __getattr__(self, name: str) -> _Method:  # type: ignore
        return _Method(self.__request, name)
class MultiCall(xmlrpc.MultiCall):
    __server: ServerProxy
    async def __call__(self) -> xmlrpc.MultiCallIterator:  # type: ignore
        marshalled_list = []
        for name, args in self.__call_list:
            marshalled_list.append({"methodName": name, "params": args})
        return xmlrpc.MultiCallIterator(
            await self.__server.system.multicall(marshalled_list)
        )
                                                                                                                                                                                                                                                                                         aioxmlrpc-0.10.0/src/aioxmlrpc/py.typed                                                             0000664 0000000 0000000 00000000000 15000473553 0020042 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/src/aioxmlrpc/server.py                                                            0000664 0000000 0000000 00000014323 15000473553 0020240 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        """
XML-RPC Server with asyncio.
This module adapt the ``xmlrpc.server`` module of the standard library to
work with asyncio.
Handle RPC of classic and coroutine functions
"""
import asyncio
import inspect
from types import TracebackType
from typing import (
    Any,
    Awaitable,
    Callable,
    Coroutine,
    Iterable,
    Optional,
    Tuple,
    overload,
)
from xmlrpc import server
from xmlrpc.client import loads, dumps, Fault
import uvicorn
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import Response
from starlette.routing import Route
__all__ = ["SimpleXMLRPCDispatcher", "SimpleXMLRPCServer"]
_Marshallable = Any
class SimpleXMLRPCDispatcher(server.SimpleXMLRPCDispatcher):
    async def _marshaled_dispatch(self, data: str) -> bytes:  # type: ignore
        """
        Override function from SimpleXMLRPCDispatcher to handle coroutines RPC case
        """
        try:
            params, method = loads(data, use_builtin_types=self.use_builtin_types)
            if method is None:
                raise ValueError("Invalid")
            response = await self._dispatch(method, params)
            # wrap response in a singleton tuple
            response = (response,)
            response = dumps(
                response,
                methodresponse=True,
                allow_none=self.allow_none,
                encoding=self.encoding,
            )
        except Fault as fault:
            response = dumps(fault, allow_none=self.allow_none, encoding=self.encoding)
        except Exception as exc:
            # report exception back to server
            response = dumps(
                Fault(1, "%s:%s" % (type(exc), exc)),
                encoding=self.encoding,
                allow_none=self.allow_none,
            )
        return response.encode(self.encoding, "xmlcharrefreplace")
    async def _dispatch(  # type: ignore
        self, method: str, params: Iterable[_Marshallable]
    ) -> _Marshallable:  # type: ignore
        """
        Override function from SimpleXMLRPCDispatcher to handle coroutine
        RPC call
        """
        func = None
        try:
            # check to see if a matching function has been registered
            func = self.funcs[method]
        except KeyError:
            if self.instance is not None:
                # check for a _dispatch method
                if hasattr(self.instance, "_dispatch"):
                    resp = await self.instance._dispatch(method, params)
                    if inspect.iscoroutine(self.instance._dispatch):
                        return await resp
                    else:
                        return resp
                else:
                    # call instance method directly
                    try:
                        func = server.resolve_dotted_attribute(
                            self.instance,
                            method,
                            getattr(self, "allow_dotted_names", True),
                        )
                    except AttributeError:
                        pass
        if func is not None:
            result = func(*params)
            if inspect.iscoroutine(result):
                return await result
            else:
                return result
        else:
            raise Exception('method "%s" is not supported' % method)
    async def system_multicall(self, call_list: list[dict[str, _Marshallable]]):  # type: ignore
        async def handle_call(call: dict[str, _Marshallable]) -> _Marshallable:
            method_name = call["methodName"]
            params = call["params"]
            try:
                result = await self._dispatch(method_name, params)
                return [result]
            except Fault as fault:
                return {"faultCode": fault.faultCode, "faultString": fault.faultString}
            except BaseException as exc:
                return {"faultCode": 1, "faultString": f"{type(exc).__name__}:{exc}"}
        return await asyncio.gather(*(handle_call(call) for call in call_list))
class SimpleXMLRPCServer(SimpleXMLRPCDispatcher):
    rpc_paths = ["/", "/RPC2", "/xmlrpc"]
    def __init__(
        self,
        addr: Tuple[str, int],
        logRequests: bool = True,
        allow_none: bool = False,
        encoding: Optional[str] = None,
        use_builtin_types: bool = False,
    ) -> None:
        super().__init__(allow_none, encoding, use_builtin_types)
        self.host, self.port = addr
        self.logRequests = logRequests
        self.app = Starlette(
            routes=[
                Route(route, self.handle_xmlrpc, methods=["POST"])
                for route in self.rpc_paths
            ],
        )
    async def handle_xmlrpc(self, request: Request) -> Response:
        body = await request.body()
        response = await self._marshaled_dispatch(body.decode())
        return Response(response, media_type="text/xml")
    def serve_forever(self) -> asyncio.Task[Any]:
        config = uvicorn.Config(
            self.app, host=self.host, port=self.port, log_level="error", loop="asyncio"
        )
        self.server = uvicorn.Server(config)
        return asyncio.create_task(self.server.serve())
    @overload  # type: ignore
    def register_function(
        self, function: Callable[..., _Marshallable], name: Optional[str] = None
    ) -> Callable[..., _Marshallable]: ...
    @overload
    def register_function(
        self,
        function: Coroutine[Awaitable[_Marshallable], Any, Any],
        name: Optional[str] = None,
    ) -> Coroutine[Awaitable[_Marshallable], Any, Any]: ...
    def register_function(  # type: ignore
        self,
        function: Any,
        name: Optional[str] = None,
    ) -> Any:
        super().register_function(function, name)
    async def __aenter__(self) -> "SimpleXMLRPCServer":
        return self
    def __enter__(self) -> "SimpleXMLRPCServer":
        return self
    def __exit__(
        self,
        exc_type: Optional[type[BaseException]],
        exc: Optional[BaseException],
        tb: Optional[TracebackType],
    ) -> None: ...
    async def __aexit__(
        self,
        exc_type: Optional[type[BaseException]],
        exc: Optional[BaseException],
        tb: Optional[TracebackType],
    ) -> None: ...
                                                                                                                                                                                                                                                                                                             aioxmlrpc-0.10.0/tests/                                                                             0000775 0000000 0000000 00000000000 15000473553 0014732 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/tests/functionals/                                                                 0000775 0000000 0000000 00000000000 15000473553 0017257 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/tests/functionals/conftest.py                                                      0000664 0000000 0000000 00000003301 15000473553 0021453 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        import asyncio
from datetime import datetime
import socket
from math import pow
import pytest
from aioxmlrpc.client import ServerProxy
from aioxmlrpc.server import SimpleXMLRPCServer
async def wait_for_socket(
    host: str, port: int, timeout: int = 5, poll_time: float = 0.1
):
    """Wait until the socket is open, or raise an error if the timeout is exceeded."""
    for _ in range(timeout * int(1 / poll_time)):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            if sock.connect_ex((host, port)) == 0:
                break
        await asyncio.sleep(poll_time)
    else:
        raise RuntimeError(f"Server on {host}:{port} did not start in time.")
async def multiply(a: int, b: int) -> int:
    await asyncio.sleep(0)
    return a * b
class ExampleService:
    def get_data(self):
        return "42"
    class dt:
        @staticmethod
        def now():
            return datetime.today()
@pytest.fixture
async def server():
    addr = ("localhost", 8000)
    async with SimpleXMLRPCServer(addr) as server:
        server.register_function(pow)
        server.register_function(multiply)
        server.register_function(lambda x, y: x + y, "add")  # type: ignore
        @server.register_function
        async def substract(x: int, y: int) -> int:
            return x - y
        server.register_instance(ExampleService(), allow_dotted_names=True)
        server.register_multicall_functions()
        task = server.serve_forever()
        await wait_for_socket(*addr)
        yield "http://localhost:8000/RPC2"
        server.server.should_exit = True
        await task
@pytest.fixture
async def client(server: str) -> ServerProxy:
    return ServerProxy(server)
                                                                                                                                                                                                                                                                                                                               aioxmlrpc-0.10.0/tests/functionals/test_functionals.py                                              0000664 0000000 0000000 00000001431 15000473553 0023214 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        from datetime import datetime
from aioxmlrpc.client import ServerProxy, MultiCall
async def test_method(client: ServerProxy):
    assert await client.pow(4, 2) == 16
async def test_lambda(client: ServerProxy):
    assert await client.add(4, 2) == 6
async def test_coroutine(client: ServerProxy):
    assert await client.multiply(4, 2) == 8
async def test_decorator(client: ServerProxy):
    assert await client.substract(16, 2) == 14
async def test_dotted(client: ServerProxy):
    assert await client.get_data() == "42"
    assert await client.dt.now() == datetime.today()
async def test_multicall(client: ServerProxy):
    multicall = MultiCall(client)
    multicall.pow(4, 2)
    multicall.add(4, 2)
    resp = await multicall()
    assert resp[0] == 16
    assert resp[1] == 6
                                                                                                                                                                                                                                       aioxmlrpc-0.10.0/tests/unittests/                                                                   0000775 0000000 0000000 00000000000 15000473553 0016774 5                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        aioxmlrpc-0.10.0/tests/unittests/__init__.py                                                        0000664 0000000 0000000 00000000054 15000473553 0021104 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        """
Test suite for the aioxmlrpc module
"""
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    aioxmlrpc-0.10.0/tests/unittests/test_client.py                                                     0000664 0000000 0000000 00000007405 15000473553 0021671 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        import ssl
import pytest
from httpx import Request, Response
from aioxmlrpc.client import Fault, MultiCall, ProtocolError, ServerProxy
RESPONSES = {
    "http://localhost/test_xmlrpc_ok": {
        "status": 200,
        "body": """
   
      
         1
      
   
""",
    },
    "http://localhost/test_xmlrpc_multi_ok": {
        "status": 200,
        "body": """
    
        
            
                
                    
                        
                            
                                1
                            
                        
                        
                            
                                2
                            
                        
                    
                
            
        
    
""",
    },
    "http://localhost/test_xmlrpc_fault": {
        "status": 200,
        "body": """
  
    
      
        
          faultCode
            4
            
        
           faultString
           You are not lucky
        
      
    
  
""",
    },
    "http://localhost/test_http_500": {
        "status": 500,
        "body": """
I am really broken
""",
    },
}
class DummyAsyncClient:
    async def post(self, url, *args, **kwargs):
        response = RESPONSES[url]
        return Response(
            status_code=response["status"],
            headers={},
            text=response["body"],
            request=Request("POST", url),
        )
async def test_xmlrpc_ok():
    client = ServerProxy("http://localhost/test_xmlrpc_ok", session=DummyAsyncClient())
    response = await client.name.space.proxfyiedcall()
    assert response == 1
async def test_xmlrpc_fault():
    client = ServerProxy(
        "http://localhost/test_xmlrpc_fault", session=DummyAsyncClient()
    )
    with pytest.raises(Fault):
        await client.name.space.proxfyiedcall()
async def test_http_500():
    client = ServerProxy("http://localhost/test_http_500", session=DummyAsyncClient())
    with pytest.raises(ProtocolError):
        await client.name.space.proxfyiedcall()
async def test_network_error():
    client = ServerProxy("http://nonexistent/nonexistent")
    with pytest.raises(ProtocolError):
        await client.name.space.proxfyiedcall()
def test_context_default():
    client = ServerProxy("http://nonexistent/nonexistent")
    ctx = client._session._transport._pool._ssl_context  # type: ignore
    assert ctx.verify_mode is ssl.VerifyMode.CERT_REQUIRED
def test_context_disable():
    client = ServerProxy("http://nonexistent/nonexistent", context=False)
    ctx = client._session._transport._pool._ssl_context  # type: ignore
    assert ctx.verify_mode is ssl.VerifyMode.CERT_NONE
def test_context_custom():
    ctx = ssl.create_default_context()
    client = ServerProxy("http://nonexistent/nonexistent", context=ctx)
    assert client._session._transport._pool._ssl_context is ctx  # type: ignore
async def test_multicall():
    client = ServerProxy(
        "http://localhost/test_xmlrpc_multi_ok", session=DummyAsyncClient()
    )
    mc = MultiCall(client)
    mc.name.space.proxfyiedcall()
    mc.name.space.proxfyiedcall()
    response = await mc()
    assert response[0] == 1
    assert response[1] == 2
                                                                                                                                                                                                                                                           aioxmlrpc-0.10.0/tests/unittests/test_server.py                                                     0000664 0000000 0000000 00000003751 15000473553 0021721 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        import pytest
from aioxmlrpc.server import SimpleXMLRPCDispatcher
RPC_CALL = """
    division
    
        {0}
        {1}
    
"""
RPC_RESPONSE = """
{0}
"""
RPC_FAULT = """
faultCode
1
faultString
{0}
"""
async def test_marshall_unregister():
    d = SimpleXMLRPCDispatcher()
    resp = await d._marshaled_dispatch(RPC_CALL.format(8, 2))
    assert resp.decode() == RPC_FAULT.format(
        "<class 'Exception'>:method \"division\" is not supported"
    )
@pytest.mark.parametrize(
    "params,expected",
    [
        pytest.param(RPC_CALL.format(8, 2), RPC_RESPONSE.format("4.0"), id="ok"),
        pytest.param(
            RPC_CALL.format(8, 0),
            RPC_FAULT.format("<class 'ZeroDivisionError'>:division by zero"),
            id="fault",
        ),
    ],
)
async def test_marshall(params: str, expected: str):
    d = SimpleXMLRPCDispatcher()
    d.register_function(lambda x, y: x / y, "division")
    resp = await d._marshaled_dispatch(params)
    assert resp.decode() == expected
async def test_multicall():
    d = SimpleXMLRPCDispatcher()
    d.register_function(lambda x, y: x / y, "division")
    resp = await d.system_multicall(
        [
            {"methodName": "division", "params": [8, 2]},
            {"methodName": "division", "params": [8, 0]},
        ],
    )
    assert resp == [
        [
            4.0,
        ],
        {
            "faultCode": 1,
            "faultString": "ZeroDivisionError:division by zero",
        },
    ]
                       aioxmlrpc-0.10.0/uv.lock                                                                            0000664 0000000 0000000 00000117234 15000473553 0015104 0                                                                                                    ustar 00root                            root                            0000000 0000000                                                                                                                                                                        version = 1
revision = 1
requires-python = ">=3.9"
[[package]]
name = "aioxmlrpc"
version = "0.10.0"
source = { editable = "." }
dependencies = [
    { name = "httpx" },
]
[package.optional-dependencies]
server = [
    { name = "starlette" },
    { name = "uvicorn" },
]
[package.dev-dependencies]
dev = [
    { name = "mypy" },
    { name = "pytest" },
    { name = "pytest-asyncio" },
    { name = "pytest-cov" },
    { name = "starlette" },
    { name = "uvicorn" },
]
[package.metadata]
requires-dist = [
    { name = "httpx", specifier = ">=0.24,<1" },
    { name = "starlette", marker = "extra == 'server'", specifier = ">=0.46.2" },
    { name = "uvicorn", marker = "extra == 'server'", specifier = ">=0.34.1" },
]
provides-extras = ["server"]
[package.metadata.requires-dev]
dev = [
    { name = "mypy", specifier = ">=1.13.0,<2" },
    { name = "pytest", specifier = ">=8.3.3,<9" },
    { name = "pytest-asyncio", specifier = ">=0.24.0" },
    { name = "pytest-cov", specifier = ">=6.0.0,<7" },
    { name = "starlette", specifier = ">=0.46.2" },
    { name = "uvicorn", specifier = ">=0.34.1" },
]
[[package]]
name = "anyio"
version = "4.6.2.post1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
    { name = "idna" },
    { name = "sniffio" },
    { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 },
]
[[package]]
name = "certifi"
version = "2024.8.30"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 },
]
[[package]]
name = "click"
version = "8.1.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "colorama", marker = "sys_platform == 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
]
[[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 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
]
[[package]]
name = "coverage"
version = "7.6.4"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/52/12/3669b6382792783e92046730ad3327f53b2726f0603f4c311c4da4824222/coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73", size = 798716 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/a5/93/4ad92f71e28ece5c0326e5f4a6630aa4928a8846654a65cfff69b49b95b9/coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07", size = 206713 },
    { url = "https://files.pythonhosted.org/packages/01/ae/747a580b1eda3f2e431d87de48f0604bd7bc92e52a1a95185a4aa585bc47/coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0", size = 207149 },
    { url = "https://files.pythonhosted.org/packages/07/1a/1f573f8a6145f6d4c9130bbc120e0024daf1b24cf2a78d7393fa6eb6aba7/coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72", size = 235584 },
    { url = "https://files.pythonhosted.org/packages/40/42/c8523f2e4db34aa9389caee0d3688b6ada7a84fcc782e943a868a7f302bd/coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51", size = 233486 },
    { url = "https://files.pythonhosted.org/packages/8d/95/565c310fffa16ede1a042e9ea1ca3962af0d8eb5543bc72df6b91dc0c3d5/coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491", size = 234649 },
    { url = "https://files.pythonhosted.org/packages/d5/81/3b550674d98968ec29c92e3e8650682be6c8b1fa7581a059e7e12e74c431/coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b", size = 233744 },
    { url = "https://files.pythonhosted.org/packages/0d/70/d66c7f51b3e33aabc5ea9f9624c1c9d9655472962270eb5e7b0d32707224/coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea", size = 232204 },
    { url = "https://files.pythonhosted.org/packages/23/2d/2b3a2dbed7a5f40693404c8a09e779d7c1a5fbed089d3e7224c002129ec8/coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a", size = 233335 },
    { url = "https://files.pythonhosted.org/packages/5a/4f/92d1d2ad720d698a4e71c176eacf531bfb8e0721d5ad560556f2c484a513/coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa", size = 209435 },
    { url = "https://files.pythonhosted.org/packages/c7/b9/cdf158e7991e2287bcf9082670928badb73d310047facac203ff8dcd5ff3/coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172", size = 210243 },
    { url = "https://files.pythonhosted.org/packages/87/31/9c0cf84f0dfcbe4215b7eb95c31777cdc0483c13390e69584c8150c85175/coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b", size = 206819 },
    { url = "https://files.pythonhosted.org/packages/53/ed/a38401079ad320ad6e054a01ec2b61d270511aeb3c201c80e99c841229d5/coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25", size = 207263 },
    { url = "https://files.pythonhosted.org/packages/20/e7/c3ad33b179ab4213f0d70da25a9c214d52464efa11caeab438592eb1d837/coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546", size = 239205 },
    { url = "https://files.pythonhosted.org/packages/36/91/fc02e8d8e694f557752120487fd982f654ba1421bbaa5560debf96ddceda/coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b", size = 236612 },
    { url = "https://files.pythonhosted.org/packages/cc/57/cb08f0eda0389a9a8aaa4fc1f9fec7ac361c3e2d68efd5890d7042c18aa3/coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e", size = 238479 },
    { url = "https://files.pythonhosted.org/packages/d5/c9/2c7681a9b3ca6e6f43d489c2e6653a53278ed857fd6e7010490c307b0a47/coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718", size = 237405 },
    { url = "https://files.pythonhosted.org/packages/b5/4e/ebfc6944b96317df8b537ae875d2e57c27b84eb98820bc0a1055f358f056/coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db", size = 236038 },
    { url = "https://files.pythonhosted.org/packages/13/f2/3a0bf1841a97c0654905e2ef531170f02c89fad2555879db8fe41a097871/coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522", size = 236812 },
    { url = "https://files.pythonhosted.org/packages/b9/9c/66bf59226b52ce6ed9541b02d33e80a6e816a832558fbdc1111a7bd3abd4/coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf", size = 209400 },
    { url = "https://files.pythonhosted.org/packages/2a/a0/b0790934c04dfc8d658d4a62acb8f7ca0efdf3818456fcad757b11c6479d/coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19", size = 210243 },
    { url = "https://files.pythonhosted.org/packages/7d/e7/9291de916d084f41adddfd4b82246e68d61d6a75747f075f7e64628998d2/coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2", size = 207013 },
    { url = "https://files.pythonhosted.org/packages/27/03/932c2c5717a7fa80cd43c6a07d3177076d97b79f12f40f882f9916db0063/coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117", size = 207251 },
    { url = "https://files.pythonhosted.org/packages/d5/3f/0af47dcb9327f65a45455fbca846fe96eb57c153af46c4754a3ba678938a/coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613", size = 240268 },
    { url = "https://files.pythonhosted.org/packages/8a/3c/37a9d81bbd4b23bc7d46ca820e16174c613579c66342faa390a271d2e18b/coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27", size = 237298 },
    { url = "https://files.pythonhosted.org/packages/c0/70/6b0627e5bd68204ee580126ed3513140b2298995c1233bd67404b4e44d0e/coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52", size = 239367 },
    { url = "https://files.pythonhosted.org/packages/3c/eb/634d7dfab24ac3b790bebaf9da0f4a5352cbc125ce6a9d5c6cf4c6cae3c7/coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2", size = 238853 },
    { url = "https://files.pythonhosted.org/packages/d9/0d/8e3ed00f1266ef7472a4e33458f42e39492e01a64281084fb3043553d3f1/coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1", size = 237160 },
    { url = "https://files.pythonhosted.org/packages/ce/9c/4337f468ef0ab7a2e0887a9c9da0e58e2eada6fc6cbee637a4acd5dfd8a9/coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5", size = 238824 },
    { url = "https://files.pythonhosted.org/packages/5e/09/3e94912b8dd37251377bb02727a33a67ee96b84bbbe092f132b401ca5dd9/coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17", size = 209639 },
    { url = "https://files.pythonhosted.org/packages/01/69/d4f3a4101171f32bc5b3caec8ff94c2c60f700107a6aaef7244b2c166793/coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08", size = 210428 },
    { url = "https://files.pythonhosted.org/packages/c2/4d/2dede4f7cb5a70fb0bb40a57627fddf1dbdc6b9c1db81f7c4dcdcb19e2f4/coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9", size = 207039 },
    { url = "https://files.pythonhosted.org/packages/3f/f9/d86368ae8c79e28f1fb458ebc76ae9ff3e8bd8069adc24e8f2fed03c58b7/coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba", size = 207298 },
    { url = "https://files.pythonhosted.org/packages/64/c5/b4cc3c3f64622c58fbfd4d8b9a7a8ce9d355f172f91fcabbba1f026852f6/coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c", size = 239813 },
    { url = "https://files.pythonhosted.org/packages/8a/86/14c42e60b70a79b26099e4d289ccdfefbc68624d096f4481163085aa614c/coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06", size = 236959 },
    { url = "https://files.pythonhosted.org/packages/7f/f8/4436a643631a2fbab4b44d54f515028f6099bfb1cd95b13cfbf701e7f2f2/coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f", size = 238950 },
    { url = "https://files.pythonhosted.org/packages/49/50/1571810ddd01f99a0a8be464a4ac8b147f322cd1e8e296a1528984fc560b/coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b", size = 238610 },
    { url = "https://files.pythonhosted.org/packages/f3/8c/6312d241fe7cbd1f0cade34a62fea6f333d1a261255d76b9a87074d8703c/coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21", size = 236697 },
    { url = "https://files.pythonhosted.org/packages/ce/5f/fef33dfd05d87ee9030f614c857deb6df6556b8f6a1c51bbbb41e24ee5ac/coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a", size = 238541 },
    { url = "https://files.pythonhosted.org/packages/a9/64/6a984b6e92e1ea1353b7ffa08e27f707a5e29b044622445859200f541e8c/coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e", size = 209707 },
    { url = "https://files.pythonhosted.org/packages/5c/60/ce5a9e942e9543783b3db5d942e0578b391c25cdd5e7f342d854ea83d6b7/coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963", size = 210439 },
    { url = "https://files.pythonhosted.org/packages/78/53/6719677e92c308207e7f10561a1b16ab8b5c00e9328efc9af7cfd6fb703e/coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f", size = 207784 },
    { url = "https://files.pythonhosted.org/packages/fa/dd/7054928930671fcb39ae6a83bb71d9ab5f0afb733172543ced4b09a115ca/coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806", size = 208058 },
    { url = "https://files.pythonhosted.org/packages/b5/7d/fd656ddc2b38301927b9eb3aae3fe827e7aa82e691923ed43721fd9423c9/coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11", size = 250772 },
    { url = "https://files.pythonhosted.org/packages/90/d0/eb9a3cc2100b83064bb086f18aedde3afffd7de6ead28f69736c00b7f302/coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3", size = 246490 },
    { url = "https://files.pythonhosted.org/packages/45/44/3f64f38f6faab8a0cfd2c6bc6eb4c6daead246b97cf5f8fc23bf3788f841/coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a", size = 248848 },
    { url = "https://files.pythonhosted.org/packages/5d/11/4c465a5f98656821e499f4b4619929bd5a34639c466021740ecdca42aa30/coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc", size = 248340 },
    { url = "https://files.pythonhosted.org/packages/f1/96/ebecda2d016cce9da812f404f720ca5df83c6b29f65dc80d2000d0078741/coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70", size = 246229 },
    { url = "https://files.pythonhosted.org/packages/16/d9/3d820c00066ae55d69e6d0eae11d6149a5ca7546de469ba9d597f01bf2d7/coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef", size = 247510 },
    { url = "https://files.pythonhosted.org/packages/8f/c3/4fa1eb412bb288ff6bfcc163c11700ff06e02c5fad8513817186e460ed43/coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e", size = 210353 },
    { url = "https://files.pythonhosted.org/packages/7e/77/03fc2979d1538884d921c2013075917fc927f41cd8526909852fe4494112/coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1", size = 211502 },
    { url = "https://files.pythonhosted.org/packages/fb/27/7efede2355bd1417137246246ab0980751b3ba6065102518a2d1eba6a278/coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3", size = 206714 },
    { url = "https://files.pythonhosted.org/packages/f3/94/594af55226676d078af72b329372e2d036f9ba1eb6bcf1f81debea2453c7/coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c", size = 207146 },
    { url = "https://files.pythonhosted.org/packages/d5/13/19de1c5315b22795dd67dbd9168281632424a344b648d23d146572e42c2b/coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076", size = 235180 },
    { url = "https://files.pythonhosted.org/packages/db/26/8fba01ce9f376708c7efed2761cea740f50a1b4138551886213797a4cecd/coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376", size = 233100 },
    { url = "https://files.pythonhosted.org/packages/74/66/4db60266551b89e820b457bc3811a3c5eaad3c1324cef7730c468633387a/coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0", size = 234231 },
    { url = "https://files.pythonhosted.org/packages/2a/9b/7b33f0892fccce50fc82ad8da76c7af1731aea48ec71279eef63a9522db7/coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858", size = 233383 },
    { url = "https://files.pythonhosted.org/packages/91/49/6ff9c4e8a67d9014e1c434566e9169965f970350f4792a0246cd0d839442/coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111", size = 231863 },
    { url = "https://files.pythonhosted.org/packages/81/f9/c9d330dec440676b91504fcceebca0814718fa71c8498cf29d4e21e9dbfc/coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901", size = 232854 },
    { url = "https://files.pythonhosted.org/packages/ee/d9/605517a023a0ba8eb1f30d958f0a7ff3a21867b07dcb42618f862695ca0e/coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09", size = 209437 },
    { url = "https://files.pythonhosted.org/packages/aa/79/2626903efa84e9f5b9c8ee6972de8338673fdb5bb8d8d2797740bf911027/coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f", size = 210209 },
    { url = "https://files.pythonhosted.org/packages/cc/56/e1d75e8981a2a92c2a777e67c26efa96c66da59d645423146eb9ff3a851b/coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e", size = 198954 },
]
[package.optional-dependencies]
toml = [
    { name = "tomli", marker = "python_full_version <= '3.11'" },
]
[[package]]
name = "exceptiongroup"
version = "1.2.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
]
[[package]]
name = "h11"
version = "0.14.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
]
[[package]]
name = "httpcore"
version = "1.0.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "certifi" },
    { name = "h11" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 },
]
[[package]]
name = "httpx"
version = "0.27.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "anyio" },
    { name = "certifi" },
    { name = "httpcore" },
    { name = "idna" },
    { name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 },
]
[[package]]
name = "idna"
version = "3.10"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
]
[[package]]
name = "iniconfig"
version = "2.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
]
[[package]]
name = "mypy"
version = "1.13.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "mypy-extensions" },
    { name = "tomli", marker = "python_full_version < '3.11'" },
    { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 },
    { url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 },
    { url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 },
    { url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 },
    { url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 },
    { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 },
    { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 },
    { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 },
    { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 },
    { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 },
    { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
    { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
    { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
    { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
    { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
    { url = "https://files.pythonhosted.org/packages/11/bb/ab4cfdc562cad80418f077d8be9b4491ee4fb257440da951b85cbb0a639e/mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7", size = 11069721 },
    { url = "https://files.pythonhosted.org/packages/59/3b/a393b1607cb749ea2c621def5ba8c58308ff05e30d9dbdc7c15028bca111/mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62", size = 10063996 },
    { url = "https://files.pythonhosted.org/packages/d1/1f/6b76be289a5a521bb1caedc1f08e76ff17ab59061007f201a8a18cc514d1/mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8", size = 12584043 },
    { url = "https://files.pythonhosted.org/packages/a6/83/5a85c9a5976c6f96e3a5a7591aa28b4a6ca3a07e9e5ba0cec090c8b596d6/mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7", size = 13036996 },
    { url = "https://files.pythonhosted.org/packages/b4/59/c39a6f752f1f893fccbcf1bdd2aca67c79c842402b5283563d006a67cf76/mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc", size = 9737709 },
    { url = "https://files.pythonhosted.org/packages/5f/d4/b33ddd40dad230efb317898a2d1c267c04edba73bc5086bf77edeb410fb2/mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc", size = 11013906 },
    { url = "https://files.pythonhosted.org/packages/f4/e6/f414bca465b44d01cd5f4a82761e15044bedd1bf8025c5af3cc64518fac5/mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732", size = 10180657 },
    { url = "https://files.pythonhosted.org/packages/38/e9/fc3865e417722f98d58409770be01afb961e2c1f99930659ff4ae7ca8b7e/mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc", size = 12586394 },
    { url = "https://files.pythonhosted.org/packages/2e/35/f4d8b6d2cb0b3dad63e96caf159419dda023f45a358c6c9ac582ccaee354/mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d", size = 13103591 },
    { url = "https://files.pythonhosted.org/packages/22/1d/80594aef135f921dd52e142fa0acd19df197690bd0cde42cea7b88cf5aa2/mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24", size = 9634690 },
    { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/98/a4/1ab47638b92648243faf97a5aeb6ea83059cc3624972ab6b8d2316078d3f/mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782", size = 4433 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
]
[[package]]
name = "packaging"
version = "24.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 },
]
[[package]]
name = "pluggy"
version = "1.5.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
]
[[package]]
name = "pytest"
version = "8.3.5"
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/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
]
[[package]]
name = "pytest-asyncio"
version = "0.24.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 },
]
[[package]]
name = "pytest-cov"
version = "6.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "coverage", extra = ["toml"] },
    { name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 },
]
[[package]]
name = "sniffio"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
]
[[package]]
name = "starlette"
version = "0.46.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "anyio" },
    { name = "typing-extensions", marker = "python_full_version < '3.10'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037 },
]
[[package]]
name = "tomli"
version = "2.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/35/b9/de2a5c0144d7d75a57ff355c0c24054f965b2dc3036456ae03a51ea6264b/tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed", size = 16096 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/cf/db/ce8eda256fa131af12e0a76d481711abe4681b6923c27efb9a255c9e4594/tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38", size = 13237 },
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
]
[[package]]
name = "uvicorn"
version = "0.34.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "click" },
    { name = "h11" },
    { name = "typing-extensions", marker = "python_full_version < '3.11'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/86/37/dd92f1f9cedb5eaf74d9999044306e06abe65344ff197864175dbbd91871/uvicorn-0.34.1.tar.gz", hash = "sha256:af981725fc4b7ffc5cb3b0e9eda6258a90c4b52cb2a83ce567ae0a7ae1757afc", size = 76755 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/5f/38/a5801450940a858c102a7ad9e6150146a25406a119851c993148d56ab041/uvicorn-0.34.1-py3-none-any.whl", hash = "sha256:984c3a8c7ca18ebaad15995ee7401179212c59521e67bfc390c07fa2b8d2e065", size = 62404 },
]