pax_global_header00006660000000000000000000000064146755511510014524gustar00rootroot0000000000000052 comment=b25d6f4301322a849c9fb4b58b34cd6e092b0139 firebase-messaging-0.4.4/000077500000000000000000000000001467555115100152645ustar00rootroot00000000000000firebase-messaging-0.4.4/.github/000077500000000000000000000000001467555115100166245ustar00rootroot00000000000000firebase-messaging-0.4.4/.github/actions/000077500000000000000000000000001467555115100202645ustar00rootroot00000000000000firebase-messaging-0.4.4/.github/actions/setup/000077500000000000000000000000001467555115100214245ustar00rootroot00000000000000firebase-messaging-0.4.4/.github/actions/setup/action.yml000066400000000000000000000061711467555115100234310ustar00rootroot00000000000000--- name: Setup Environment description: Install requested pipx dependencies, configure the system python, and install uv and the package dependencies inputs: uv-install-options: default: "" uv-version: default: 0.4.5 python-version: required: true cache-pre-commit: default: false runs: using: composite steps: - uses: "actions/setup-python@v5" id: setup-python with: python-version: "${{ inputs.python-version }}" allow-prereleases: true - name: Setup pipx environment Variables id: pipx-env-setup # pipx default home and bin dir are not writable by the cache action # so override them here and add the bin dir to PATH for later steps. # This also ensures the pipx cache only contains uv run: | SEP="${{ !startsWith(runner.os, 'windows') && '/' || '\\' }}" PIPX_CACHE="${{ github.workspace }}${SEP}pipx_cache" echo "pipx-cache-path=${PIPX_CACHE}" >> $GITHUB_OUTPUT echo "pipx-version=$(pipx --version)" >> $GITHUB_OUTPUT echo "PIPX_HOME=${PIPX_CACHE}${SEP}home" >> $GITHUB_ENV echo "PIPX_BIN_DIR=${PIPX_CACHE}${SEP}bin" >> $GITHUB_ENV echo "PIPX_MAN_DIR=${PIPX_CACHE}${SEP}man" >> $GITHUB_ENV echo "${PIPX_CACHE}${SEP}bin" >> $GITHUB_PATH shell: bash - name: Pipx cache id: pipx-cache uses: actions/cache@v4 with: path: ${{ steps.pipx-env-setup.outputs.pipx-cache-path }} key: cache-${{ inputs.cache-version }}-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipx-${{ steps.pipx-env-setup.outputs.pipx-version }}-uv-${{ inputs.uv-version }} - name: Install uv if: steps.pipx-cache.outputs.cache-hit != 'true' id: install-uv shell: bash run: |- pipx install uv==${{ inputs.uv-version }} --python "${{ steps.setup-python.outputs.python-path }}" - name: Read uv cache location id: uv-cache-location shell: bash run: |- echo "uv-venv-location=$(uv cache dir)" >> $GITHUB_OUTPUT - uses: actions/cache@v4 name: uv cache with: path: | ${{ steps.uv-cache-location.outputs.uv-venv-location }} key: cache-${{ inputs.cache-version }}-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('uv.lock') }}-options-${{ inputs.uv-install-options }} - name: "uv install" shell: bash run: | uv sync --python "${{ steps.setup-python.outputs.python-path }}" ${{ inputs.uv-install-options }} - name: Read pre-commit version if: inputs.cache-pre-commit == 'true' id: pre-commit-version shell: bash run: >- echo "pre-commit-version=$(uv run pre-commit -V | awk '{print $2}')" >> $GITHUB_OUTPUT - uses: actions/cache@v4 if: inputs.cache-pre-commit == 'true' name: Pre-commit cache with: path: ~/.cache/pre-commit/ key: cache-${{ inputs.cache-version }}-${{ runner.os }}-pre-commit-${{ steps.pre-commit-version.outputs.pre-commit-version }}-python-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('.pre-commit-config.yaml') }} firebase-messaging-0.4.4/.github/workflows/000077500000000000000000000000001467555115100206615ustar00rootroot00000000000000firebase-messaging-0.4.4/.github/workflows/ci.yml000066400000000000000000000046001467555115100217770ustar00rootroot00000000000000name: CI on: push: branches: ["main"] pull_request: branches: ["main"] env: UV_VERSION: 0.4.5 PACKAGE_NAME: firebase_messaging jobs: linting: name: "Perform linting checks" runs-on: ubuntu-latest strategy: matrix: python-version: ["3.12"] steps: - uses: "actions/checkout@v4" - name: Setup environment uses: ./.github/actions/setup with: python-version: ${{ matrix.python-version }} uv-version: ${{ env.UV_VERSION }} uv-install-options: "" cache-pre-commit: true - name: "Run pre-commit checks" run: | uv run pre-commit run --all-files --verbose docs: name: "Build docs" needs: linting runs-on: ubuntu-latest strategy: matrix: python-version: ["3.12"] steps: - uses: "actions/checkout@v4" - name: Setup environment uses: ./.github/actions/setup with: python-version: ${{ matrix.python-version }} uv-version: ${{ env.UV_VERSION }} uv-install-options: "--extra docs --no-dev" - name: Make docs run: | uv run make -C docs html tests: name: Tests - Python ${{ matrix.python-version}} on ${{ matrix.os }} needs: linting runs-on: ubuntu-latest strategy: fail-fast: true matrix: python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "pypy-3.9", "pypy-3.10"] os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: "actions/checkout@v4" - name: Setup environment uses: ./.github/actions/setup with: python-version: ${{ matrix.python-version }} uv-version: ${{ env.UV_VERSION }} uv-install-options: "" - name: Run tests run: > uv run pytest tests/ --cov=${{ env.PACKAGE_NAME }} --cov-report=xml --cov-report=term-missing --import-mode importlib - name: Coveralls GitHub Action uses: coverallsapp/github-action@v2.2.3 with: file: coverage.xml debug: true parallel: true if: ${{ success() && matrix.python-version == '3.12' }} finish: name: Finish coverage build needs: tests runs-on: ubuntu-latest steps: - name: Close parallel build uses: coverallsapp/github-action@v2.2.3 with: parallel-finished: true firebase-messaging-0.4.4/.github/workflows/publish.yml000066400000000000000000000071321467555115100230550ustar00rootroot00000000000000name: Publish Python distribution to PyPI and TestPyPI on: push: branches: ["main"] tags: - '*' env: UV_VERSION: 0.4.5 PYPI_PROJECT: firebase-messaging # GITHUB_TOKEN must have write access # https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/signing-the-distribution-packages jobs: build: name: Build distribution runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install uv run: |- pipx install uv==${{ env.UV_VERSION }} --python "${{ steps.setup-python.outputs.python-path }}" - name: Build with uv run: uv build - name: Store the distribution packages uses: actions/upload-artifact@v4 with: name: python-package-distributions path: dist/ publish-to-pypi: name: >- Publish to PyPI if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes needs: - build runs-on: ubuntu-latest environment: name: pypi url: https://pypi.org/p/${{ env.PYPI_PROJECT }} permissions: id-token: write # IMPORTANT: mandatory for trusted publishing steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: python-package-distributions path: dist/ - name: Publish distribution to PyPI uses: pypa/gh-action-pypi-publish@release/v1 github-release: name: >- Create github release needs: - publish-to-pypi runs-on: ubuntu-latest permissions: contents: write # IMPORTANT: mandatory for making GitHub Releases id-token: write # IMPORTANT: mandatory for sigstore steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: python-package-distributions path: dist/ - name: Sign the dists with Sigstore uses: sigstore/gh-action-sigstore-python@v2.1.1 with: inputs: >- ./dist/*.tar.gz ./dist/*.whl - name: Create GitHub Release env: GITHUB_TOKEN: ${{ github.token }} # Repo clone is required for --notes-from-tag to work run: | gh repo clone '${{ github.repository }}' cd ${{ github.event.repository.name }} gh release create '${{ github.ref_name }}' --verify-tag --notes-from-tag --title '${{ github.ref_name }}' ${{ contains(github.ref_name, 'dev') && '--prerelease --latest=false' || '--latest=true' }} cd .. - name: Upload artifact signatures to GitHub Release env: GITHUB_TOKEN: ${{ github.token }} # Upload to GitHub Release using the `gh` CLI. # `dist/` contains the built packages, and the # sigstore-produced signatures and certificates. run: >- gh release upload '${{ github.ref_name }}' dist/** --repo '${{ github.repository }}' publish-to-testpypi: name: Publish to TestPyPI needs: - build runs-on: ubuntu-latest environment: name: testpypi url: https://test.pypi.org/p/${{ env.PYPI_PROJECT }} permissions: id-token: write # IMPORTANT: mandatory for trusted publishing steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: python-package-distributions path: dist/ - name: Publish distribution to TestPyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ skip-existing: true firebase-messaging-0.4.4/.github_changelog_generator000066400000000000000000000007321467555115100226260ustar00rootroot00000000000000output=CHANGELOG.md user=sdb9696 project=firebase-messaging release-branch=main base=HISTORY.md since-tag=0.2.1 usernames-as-github-logins=true add-sections={"docs":{"prefix":"**Documentation updates:**","labels":["documentation"]},"maintenance":{"prefix":"**Project maintenance:**","labels":["maintenance"]}} exclude-labels=duplicate,question,invalid,wontfix,release-prep,stale,bug issues-wo-labels=false bug-labels=bugfix breaking-label=**Breaking change pull requests:** firebase-messaging-0.4.4/.gitignore000066400000000000000000000000661467555115100172560ustar00rootroot00000000000000__pycache__/ .vscode/ htmlcov/ docs/build dist .venv firebase-messaging-0.4.4/.pre-commit-config.yaml000066400000000000000000000022111467555115100215410ustar00rootroot00000000000000repos: - repo: https://github.com/astral-sh/uv-pre-commit # uv version. rev: 0.4.5 hooks: # Update the uv lockfile - id: uv-lock - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: check-docstring-first - id: check-yaml - id: debug-statements - id: check-ast - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - id: ruff-format - repo: https://github.com/PyCQA/doc8 rev: 'v1.1.1' hooks: - id: doc8 additional_dependencies: [tomli] - repo: local hooks: # Run mypy in the virtual environment so it uses the installed dependencies # for more accurate checking than using the pre-commit mypy mirror - id: mypy name: mypy entry: uv run mypy language: system types_or: [python, pyi] require_serial: true # exclude required because --all-files passes py and pyi # should match pattern in pyproject.toml exclude: | (?x)( ^docs/.*| ^tests/.*| ^firebase_messaging/proto/.*py$ ) firebase-messaging-0.4.4/.readthedocs.yaml000066400000000000000000000021751467555115100205200ustar00rootroot00000000000000# Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.11" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/source/conf.py # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs # builder: "dirhtml" # Fail on all warnings to avoid broken references # fail_on_warning: true # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub formats: all # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html # python: # install: # - requirements: docs/requirements.txt python: install: - method: pip path: . extra_requirements: - docs firebase-messaging-0.4.4/CHANGELOG.md000066400000000000000000000155641467555115100171100ustar00rootroot00000000000000# Changelog ## [0.4.4](https://github.com/sdb9696/firebase-messaging/tree/0.4.4) (2024-09-27) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.4.3...0.4.4) **Release highlights:** - Revert changes to compiled protobuf files so they are back to 4.24 to avoid ongoing release management headaches. **Merged pull requests:** - Revert protobuf compilation changes [\#19](https://github.com/sdb9696/firebase-messaging/pull/19) (@sdb9696) ## [0.4.3](https://github.com/sdb9696/firebase-messaging/tree/0.4.3) (2024-09-25) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.4.2...0.4.3) **Release highlights:** - Suppress unnecessary warnings from dependant library. **Fixed bugs:** - Catch excessive protobuf warnings [\#16](https://github.com/sdb9696/firebase-messaging/pull/16) (@sdb9696) ## [0.4.2](https://github.com/sdb9696/firebase-messaging/tree/0.4.2) (2024-09-25) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.4.1...0.4.2) **Release highlights:** Upgrades protobuf dependency to 5.28. **Project maintenance:** - Fix publish workflow to testpypi [\#15](https://github.com/sdb9696/firebase-messaging/pull/15) (@sdb9696) - Update protobuf to 5.28 [\#12](https://github.com/sdb9696/firebase-messaging/pull/12) (@sdb9696) ## [0.4.1](https://github.com/sdb9696/firebase-messaging/tree/0.4.1) (2024-09-06) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.4.0...0.4.1) **Release highlights:** Migration to uv for project/package management **Project maintenance:** - Migrate from poetry to uv and enable testpypi publishing [\#9](https://github.com/sdb9696/firebase-messaging/pull/9) (@sdb9696) ## [0.4.0](https://github.com/sdb9696/firebase-messaging/tree/0.4.0) (2024-08-29) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.3.0...0.4.0) **Release highlights:** - Support for new FCM HTTP v1 API - Previous versions of this library will no longer work due firebase [deprecating the legacy APIs](https://firebase.google.com/docs/cloud-messaging/migrate-v1) - Dropping official python 3.8 support - **Breaking** - this version of the library only supports being run in an asyncio event loop - **Breaking** - The api has changed, see the readme for updated details **Breaking change pull requests:** - Drop python 3.8 support and update CI [\#5](https://github.com/sdb9696/firebase-messaging/pull/5) (@sdb9696) **Implemented enhancements:** - Support FCM HTTP v1 \(async only\) [\#4](https://github.com/sdb9696/firebase-messaging/pull/4) (@sdb9696) **Project maintenance:** - Update releasing instructions and add changelog [\#6](https://github.com/sdb9696/firebase-messaging/pull/6) (@sdb9696) ## [0.3.0](https://github.com/sdb9696/firebase-messaging/tree/0.3.0) (2024-03-26) [Full Changelog](https://github.com/sdb9696/firebase-messaging/compare/0.2.1...0.3.0) **Merged pull requests:** - Make checkin async [\#2](https://github.com/sdb9696/firebase-messaging/pull/2) (@sdb9696) ## [0.2.1](https://github.com/sdb9696/firebase-messaging/releases/tag/0.2.1) - 2024-03-19 [Compare with 0.2.0](https://github.com/sdb9696/firebase-messaging/compare/0.2.0...0.2.1) ### Added - Add typing ([ae3bc88](https://github.com/sdb9696/firebase-messaging/commit/ae3bc8821c1ca16fc6da00af0f0655851f6f848f) by sdb9696). - Add ruff pre-commit hook ([bd98a4e](https://github.com/sdb9696/firebase-messaging/commit/bd98a4eea43ab0d63112f15f2ea3e2aa6c12f7c7) by sdb9696). - Publisher verbose ([98cd5c4](https://github.com/sdb9696/firebase-messaging/commit/98cd5c4a40b12a42fc234d61076560a21bf46666) by sdb9696). ### Fixed - Fix publisher ([6347dc2](https://github.com/sdb9696/firebase-messaging/commit/6347dc262df7f409099807df18db3e4550316106) by sdb9696). - Fix cryptography warning in key generation ([5d4685b](https://github.com/sdb9696/firebase-messaging/commit/5d4685b9be3b66c3bff38ae6b4049094ba116ffb) by sdb9696). - Fix broken proto file ([1bf3625](https://github.com/sdb9696/firebase-messaging/commit/1bf36259cd508bf6a58dc9f16138294aef235068) by sdb9696). ### Merged - Merge pull request #1 from sdb9696/add_typing ([919eb97](https://github.com/sdb9696/firebase-messaging/commit/919eb97750dc3481130056ed6a4b9f4773b8da15) by Steven B). ## [0.2.0](https://github.com/sdb9696/firebase-messaging/releases/tag/0.2.0) - 2023-10-31 [Compare with 0.1.4](https://github.com/sdb9696/firebase-messaging/compare/0.1.4...0.2.0) - Bump to 0.2.0, rename entry points and add run state for stability ([e3cbfda](https://github.com/sdb9696/firebase-messaging/commit/e3cbfda2f753e11029c437ec66720d836ccc0595) by sdb9696). ### Removed - Remove need to be created in an event loop ([87daa6b](https://github.com/sdb9696/firebase-messaging/commit/87daa6b0078ef17131c3e64519b3042c559e3630) by sdb9696). ## [0.1.4](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.4) - 2023-10-25 [Compare with 0.1.3](https://github.com/sdb9696/firebase-messaging/compare/0.1.3...0.1.4) - Relax protobuf dependency for HA ([9ac0bc6](https://github.com/sdb9696/firebase-messaging/commit/9ac0bc6d8212ea9a4fb4aa6cc412e7e760414dae) by sdb9696). ## [0.1.3](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.3) - 2023-10-25 [Compare with 0.1.2](https://github.com/sdb9696/firebase-messaging/compare/0.1.2...0.1.3) - Bugfix python 3.9 async lock ([c2ee681](https://github.com/sdb9696/firebase-messaging/commit/c2ee68123ee4b8d5d62060b80ed746b2ec639b29) by sdb9696). ## [0.1.2](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.2) - 2023-10-25 [Compare with 0.1.1](https://github.com/sdb9696/firebase-messaging/compare/0.1.1...0.1.2) ### Fixed - Update handling of no event loop and bump version ([29f3841](https://github.com/sdb9696/firebase-messaging/commit/29f38414eba0ed5893578c382eae558a826475de) by sdb9696). ## [0.1.1](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.1) - 2023-10-23 [Compare with 0.1.0](https://github.com/sdb9696/firebase-messaging/compare/0.1.0...0.1.1) ### Fixed - Fix gcm checkin with credentials ([4c51098](https://github.com/sdb9696/firebase-messaging/commit/4c5109816b0d3fa266329bb36ec6fdfb02598ca3) by sdb9696). ## [0.1.0](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.0) - 2023-10-23 [Compare with first commit](https://github.com/sdb9696/firebase-messaging/compare/acf9b784788d68026d64d2f6d39a23274dbd663e...0.1.0) ### Added - Add tests and docs and refactor ([77c225c](https://github.com/sdb9696/firebase-messaging/commit/77c225c142f1173ca2746c7a07de250b7d46e610) by sdb9696). ### Fixed - Fix publish workflow ([447d379](https://github.com/sdb9696/firebase-messaging/commit/447d37922aa2589e79b3952036ef10b02debb01a) by sdb9696). \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* firebase-messaging-0.4.4/HISTORY.md000066400000000000000000000073611467555115100167560ustar00rootroot00000000000000## [0.2.1](https://github.com/sdb9696/firebase-messaging/releases/tag/0.2.1) - 2024-03-19 [Compare with 0.2.0](https://github.com/sdb9696/firebase-messaging/compare/0.2.0...0.2.1) ### Added - Add typing ([ae3bc88](https://github.com/sdb9696/firebase-messaging/commit/ae3bc8821c1ca16fc6da00af0f0655851f6f848f) by sdb9696). - Add ruff pre-commit hook ([bd98a4e](https://github.com/sdb9696/firebase-messaging/commit/bd98a4eea43ab0d63112f15f2ea3e2aa6c12f7c7) by sdb9696). - Publisher verbose ([98cd5c4](https://github.com/sdb9696/firebase-messaging/commit/98cd5c4a40b12a42fc234d61076560a21bf46666) by sdb9696). ### Fixed - Fix publisher ([6347dc2](https://github.com/sdb9696/firebase-messaging/commit/6347dc262df7f409099807df18db3e4550316106) by sdb9696). - Fix cryptography warning in key generation ([5d4685b](https://github.com/sdb9696/firebase-messaging/commit/5d4685b9be3b66c3bff38ae6b4049094ba116ffb) by sdb9696). - Fix broken proto file ([1bf3625](https://github.com/sdb9696/firebase-messaging/commit/1bf36259cd508bf6a58dc9f16138294aef235068) by sdb9696). ### Merged - Merge pull request #1 from sdb9696/add_typing ([919eb97](https://github.com/sdb9696/firebase-messaging/commit/919eb97750dc3481130056ed6a4b9f4773b8da15) by Steven B). ## [0.2.0](https://github.com/sdb9696/firebase-messaging/releases/tag/0.2.0) - 2023-10-31 [Compare with 0.1.4](https://github.com/sdb9696/firebase-messaging/compare/0.1.4...0.2.0) - Bump to 0.2.0, rename entry points and add run state for stability ([e3cbfda](https://github.com/sdb9696/firebase-messaging/commit/e3cbfda2f753e11029c437ec66720d836ccc0595) by sdb9696). ### Removed - Remove need to be created in an event loop ([87daa6b](https://github.com/sdb9696/firebase-messaging/commit/87daa6b0078ef17131c3e64519b3042c559e3630) by sdb9696). ## [0.1.4](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.4) - 2023-10-25 [Compare with 0.1.3](https://github.com/sdb9696/firebase-messaging/compare/0.1.3...0.1.4) - Relax protobuf dependency for HA ([9ac0bc6](https://github.com/sdb9696/firebase-messaging/commit/9ac0bc6d8212ea9a4fb4aa6cc412e7e760414dae) by sdb9696). ## [0.1.3](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.3) - 2023-10-25 [Compare with 0.1.2](https://github.com/sdb9696/firebase-messaging/compare/0.1.2...0.1.3) - Bugfix python 3.9 async lock ([c2ee681](https://github.com/sdb9696/firebase-messaging/commit/c2ee68123ee4b8d5d62060b80ed746b2ec639b29) by sdb9696). ## [0.1.2](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.2) - 2023-10-25 [Compare with 0.1.1](https://github.com/sdb9696/firebase-messaging/compare/0.1.1...0.1.2) ### Fixed - Update handling of no event loop and bump version ([29f3841](https://github.com/sdb9696/firebase-messaging/commit/29f38414eba0ed5893578c382eae558a826475de) by sdb9696). ## [0.1.1](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.1) - 2023-10-23 [Compare with 0.1.0](https://github.com/sdb9696/firebase-messaging/compare/0.1.0...0.1.1) ### Fixed - Fix gcm checkin with credentials ([4c51098](https://github.com/sdb9696/firebase-messaging/commit/4c5109816b0d3fa266329bb36ec6fdfb02598ca3) by sdb9696). ## [0.1.0](https://github.com/sdb9696/firebase-messaging/releases/tag/0.1.0) - 2023-10-23 [Compare with first commit](https://github.com/sdb9696/firebase-messaging/compare/acf9b784788d68026d64d2f6d39a23274dbd663e...0.1.0) ### Added - Add tests and docs and refactor ([77c225c](https://github.com/sdb9696/firebase-messaging/commit/77c225c142f1173ca2746c7a07de250b7d46e610) by sdb9696). ### Fixed - Fix publish workflow ([447d379](https://github.com/sdb9696/firebase-messaging/commit/447d37922aa2589e79b3952036ef10b02debb01a) by sdb9696). firebase-messaging-0.4.4/LICENSE000066400000000000000000000021201467555115100162640ustar00rootroot00000000000000MIT License Copyright (c) 2017 Matthieu Lemoine Copyright (c) 2023 Steven Beth 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. firebase-messaging-0.4.4/README.rst000066400000000000000000000055601467555115100167610ustar00rootroot00000000000000================== Firebase Messaging ================== .. image:: https://badge.fury.io/py/firebase-messaging.svg :alt: PyPI Version :target: https://badge.fury.io/py/firebase-messaging .. image:: https://github.com/sdb9696/firebase-messaging/actions/workflows/ci.yml/badge.svg?branch=main :alt: Build Status :target: https://github.com/sdb9696/firebase-messaging/actions/workflows/ci.yml?branch=main .. image:: https://coveralls.io/repos/github/sdb9696/firebase-messaging/badge.svg?branch=main :alt: Coverage :target: https://coveralls.io/github/sdb9696/firebase-messaging?branch=main .. image:: https://readthedocs.org/projects/firebase-messaging/badge/?version=latest :alt: Documentation Status :target: https://firebase-messaging.readthedocs.io/?badge=latest .. image:: https://img.shields.io/pypi/pyversions/firebase-messaging.svg :alt: Py Versions :target: https://pypi.python.org/pypi/firebase-messaging# A library to subscribe to GCM/FCM and receive notifications within a python application. When should I use `firebase-messaging` ? ---------------------------------------- - I want to **receive** push notifications sent using Firebase Cloud Messaging in a python application. When should I not use `firebase-messaging` ? -------------------------------------------- - I want to **send** push notifications (use the firebase SDK instead) - My application is running on a FCM supported platform (Android, iOS, Web). Install ------- PyPi:: $ pip install firebase-messaging Requirements ------------ - Firebase configuration to receive notifications Usage ----- Must be run inside an asyncio event loop. python:: from firebase_messaging import FcmPushClient, FcmRegisterConfig def on_notification(obj, notification, data_message): # Do something with the notification pass credentials = None # Start off with none or load from previous save def on_credentials_updated(creds): # save the credentials to a file here for future use fcm_config = FcmRegisterConfig(fcm-project-id, fcm-app-id, fcm-api-key, fcm-message-sender-id) pc = FcmPushClient(on_notification, fcm_config, credentials, on_credentials_updated) fcm_token = await pc.checkin_or_register() await pc.start() # Adapt the following for your usage while some_condition_to_keep_listening: asyncio.sleep(2) Attribution ----------- Code originally based on typescript/node implementation by `Matthieu Lemoine `_. See `this blog post `_ for more details. Converted to python by `lolisamurai `_ http decryption logic in decrypt.py by `Martin Thomson `_ firebase-messaging-0.4.4/RELEASING.md000066400000000000000000000115331467555115100171220ustar00rootroot00000000000000# Releasing ## Requirements * [github client](https://github.com/cli/cli#installation) * [gitchub_changelog_generator](https://github.com/github-changelog-generator) * [github access token](https://github.com/github-changelog-generator/github-changelog-generator#github-token) ## Export changelog token ```bash export CHANGELOG_GITHUB_TOKEN=token ``` ## Set release information ```bash export NEW_RELEASE=x.x.x ``` ## Normal releases from main ### Create a branch for the release ```bash git checkout main git fetch origin main git rebase origin/main git checkout -b release/$NEW_RELEASE ``` ### Update the version number ```bash sed -i "0,/version = /{s/version = .*/version = \"${NEW_RELEASE}\"/}" pyproject.toml ``` ### Update dependencies ```bash uv sync --all-extras uv lock --upgrade ``` ### Run pre-commit and tests ```bash uv run pre-commit run --all-files uv run pytest ``` ### Create release summary (skip for dev releases) Write a short and understandable summary for the release. Can include images. #### Create $NEW_RELEASE milestone in github If not already created #### Create new issue linked to the milestone ```bash gh issue create --label "release-summary" --milestone $NEW_RELEASE --title "$NEW_RELEASE Release Summary" --body "**Release highlights:**" ``` You can exclude the --body option to get an interactive editor or go into the issue on github and edit there. #### Close the issue Either via github or: ```bash gh issue close ISSUE_NUMBER ``` ### Generate changelog Configuration settings are in `.github_changelog_generator` #### For pre-release EXCLUDE_TAGS will exclude all dev tags except for the current release dev tags. Regex should be something like this `^((?!0\.9\.0)(.*dev\d))+`. The first match group negative matches on the current release and the second matches on releases ending with dev. ```bash EXCLUDE_TAGS=${NEW_RELEASE%.dev*}; EXCLUDE_TAGS=${EXCLUDE_TAGS//"."/"\."}; EXCLUDE_TAGS="^((?!"$EXCLUDE_TAGS")(.*dev\d))+" echo "$EXCLUDE_TAGS" github_changelog_generator --future-release $NEW_RELEASE --exclude-tags-regex "$EXCLUDE_TAGS" ``` #### For production ```bash github_changelog_generator --future-release $NEW_RELEASE --exclude-tags-regex 'dev\d$' ``` You can ignore warnings about missing PR commits like below as these relate to PRs to branches other than main: ``` Warning: PR 111 merge commit was not found in the release branch or tagged git history and no rebased SHA comment was found ``` ### Export new release notes to variable ```bash export RELEASE_NOTES=$(grep -Poz '(?<=\# Changelog\n\n)(.|\n)+?(?=\#\#)' CHANGELOG.md | tr '\0' '\n' ) echo "$RELEASE_NOTES" # Check the output and copy paste if neccessary ``` ### Commit and push the changed files ```bash git commit --all --verbose -m "Prepare $NEW_RELEASE" git push origin release/$NEW_RELEASE -u ``` ### Create a PR for the release, merge it, and re-fetch the main #### Create the PR ``` gh pr create --title "Prepare $NEW_RELEASE" --body "$RELEASE_NOTES" --label release-prep --base main ``` #### Merge the PR once the CI passes Create a squash commit and add the markdown from the PR description to the commit description. ```bash gh pr merge --squash --body "$RELEASE_NOTES" ``` ### Rebase local main ```bash git checkout main git fetch origin main git rebase origin/main ``` ### Create a release tag Note, add changelog release notes as the tag commit message so `gh release create --notes-from-tag` can be used to create a release draft. ```bash git tag --annotate $NEW_RELEASE -m "$RELEASE_NOTES" # to create a signed tag replace --annotate with --sign git push origin $NEW_RELEASE ``` ### Approve the release workflow This will automatically deploy to pypi ## Updating protobuf version Skip this part under normal circumstances. Only required if protobuf minimum dependency is updated. ### Update protobuf version ```bash export PROTOBUF_VERSION=x.x.0 uv add "protobuf>$PROTOBUF_VERSION" uv add --dev "types-protobuf>$PROTOBUF_VERSION" ``` ### Download and unzip latest protoc compiler Replace download url with correct version/platform ```bash cd /var/tmp wget https://github.com/protocolbuffers/protobuf/releases/download/v28.0/protoc-28.0-linux-x86_64.zip unzip protoc-28.0-linux-x86_64.zip sudo cp bin/protoc /usr/local/bin/ cd protoc --version # check version as expected ``` ### Update generated python files ```bash export PROTO_DIR="firebase_messaging/proto" protoc --proto_path=$PROTO_DIR --python_out=$PROTO_DIR $PROTO_DIR/android_checkin.proto $PROTO_DIR/checkin.proto $PROTO_DIR/mcs.proto protoc --proto_path=$PROTO_DIR --pyi_out=$PROTO_DIR $PROTO_DIR/android_checkin.proto $PROTO_DIR/checkin.proto $PROTO_DIR/mcs.proto ``` ### Fix relative import `protoc` doesn't do relative imports https://github.com/protocolbuffers/protobuf/issues/1491 In `checkin_pb2.py` and `checkin_pb2.pyi` put `from . ` in front of `import android_checkin_pb2 ...` firebase-messaging-0.4.4/docs/000077500000000000000000000000001467555115100162145ustar00rootroot00000000000000firebase-messaging-0.4.4/docs/Makefile000066400000000000000000000011761467555115100176610ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = source BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) firebase-messaging-0.4.4/docs/make.bat000066400000000000000000000014011467555115100176150ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=source set BUILDDIR=build %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.https://www.sphinx-doc.org/ exit /b 1 ) if "%1" == "" goto help %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd firebase-messaging-0.4.4/docs/source/000077500000000000000000000000001467555115100175145ustar00rootroot00000000000000firebase-messaging-0.4.4/docs/source/api.rst000066400000000000000000000003231467555115100210150ustar00rootroot00000000000000.. py:module:: firebase_messaging API Documentation ***************** .. autoclass:: FcmPushClientConfig :members: :undoc-members: false .. autoclass:: FcmPushClient :members: :undoc-members: firebase-messaging-0.4.4/docs/source/changelog.md000066400000000000000000000000401467555115100217570ustar00rootroot00000000000000:::{include} ../../CHANGELOG.md firebase-messaging-0.4.4/docs/source/conf.py000066400000000000000000000024211467555115100210120ustar00rootroot00000000000000# Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html from importlib.metadata import version as _version # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information project = "firebase-messaging" copyright = "2023, Steven Beth" author = "Steven Beth" release = _version("firebase_messaging") version = _version("firebase_messaging") # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ "sphinx.ext.autodoc", "sphinx_autodoc_typehints", "sphinx.ext.coverage", "sphinx.ext.viewcode", "sphinx.ext.todo", "myst_parser", ] myst_enable_extensions = [ "colon_fence", ] templates_path = ["_templates"] exclude_patterns = [] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output html_theme = "sphinx_rtd_theme" autodoc_member_order = "bysource" # html_static_path = ["_static"] firebase-messaging-0.4.4/docs/source/index.rst000066400000000000000000000007061467555115100213600ustar00rootroot00000000000000.. python-ring-doorbell documentation master file, created by sphinx-quickstart on Fri Sep 22 17:28:31 2023. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to python-ring-doorbell's documentation! ================================================ .. include:: ../../README.rst .. toctree:: :hidden: :titlesonly: :maxdepth: 0 Home api changelog firebase-messaging-0.4.4/firebase_messaging/000077500000000000000000000000001467555115100211015ustar00rootroot00000000000000firebase-messaging-0.4.4/firebase_messaging/__init__.py000066400000000000000000000003651467555115100232160ustar00rootroot00000000000000from .fcmpushclient import FcmPushClient, FcmPushClientConfig, FcmPushClientRunState from .fcmregister import FcmRegisterConfig __all__ = [ "FcmPushClientConfig", "FcmPushClient", "FcmPushClientRunState", "FcmRegisterConfig", ] firebase-messaging-0.4.4/firebase_messaging/const.py000066400000000000000000000022471467555115100226060ustar00rootroot00000000000000"""Constants module.""" GCM_REGISTER_URL = "https://android.clients.google.com/c2dm/register3" GCM_CHECKIN_URL = "https://android.clients.google.com/checkin" GCM_SERVER_KEY_BIN = ( b"\x04\x33\x94\xf7\xdf\xa1\xeb\xb1\xdc\x03\xa2\x5e\x15\x71\xdb\x48\xd3" + b"\x2e\xed\xed\xb2\x34\xdb\xb7\x47\x3a\x0c\x8f\xc4\xcc\xe1\x6f\x3c" + b"\x8c\x84\xdf\xab\xb6\x66\x3e\xf2\x0c\xd4\x8b\xfe\xe3\xf9\x76\x2f" + b"\x14\x1c\x63\x08\x6a\x6f\x2d\xb1\x1a\x95\xb0\xce\x37\xc0\x9c\x6e" ) # urlsafe b64 encoding of the binary key with = padding removed GCM_SERVER_KEY_B64 = ( "BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoM" + "j8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4" ) FCM_SUBSCRIBE_URL = "https://fcm.googleapis.com/fcm/connect/subscribe/" FCM_SEND_URL = "https://fcm.googleapis.com/fcm/send/" FCM_API = "https://fcm.googleapis.com/v1/" FCM_REGISTRATION = "https://fcmregistrations.googleapis.com/v1/" FCM_INSTALLATION = "https://firebaseinstallations.googleapis.com/v1/" AUTH_VERSION = "FIS_v2" SDK_VERSION = "w:0.6.6" DOORBELLS_ENDPOINT = "/clients_api/doorbots/{0}" MCS_VERSION = 41 MCS_HOST = "mtalk.google.com" MCS_PORT = 5228 MCS_SELECTIVE_ACK_ID = 12 MCS_STREAM_ACK_ID = 13 firebase-messaging-0.4.4/firebase_messaging/fcmpushclient.py000066400000000000000000000711051467555115100243230ustar00rootroot00000000000000from __future__ import annotations import asyncio import contextlib import json import logging import ssl import struct import time import traceback from base64 import urlsafe_b64decode from contextlib import suppress as contextlib_suppress from dataclasses import dataclass from enum import Enum from typing import TYPE_CHECKING, Any, Callable from aiohttp import ClientSession from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import load_der_private_key from google.protobuf.json_format import MessageToJson from google.protobuf.message import Message from http_ece import decrypt as http_decrypt # type: ignore[import-untyped] from .const import ( MCS_HOST, MCS_PORT, MCS_SELECTIVE_ACK_ID, MCS_VERSION, ) from .fcmregister import FcmRegister, FcmRegisterConfig from .proto.mcs_pb2 import ( # pylint: disable=no-name-in-module Close, DataMessageStanza, HeartbeatAck, HeartbeatPing, IqStanza, LoginRequest, LoginResponse, SelectiveAck, StreamErrorStanza, ) _logger = logging.getLogger(__name__) OnNotificationCallable = Callable[[dict[str, Any], str, Any], None] CredentialsUpdatedCallable = Callable[[dict[str, Any]], None] # MCS Message Types and Tags MCS_MESSAGE_TAG = { HeartbeatPing: 0, HeartbeatAck: 1, LoginRequest: 2, LoginResponse: 3, Close: 4, "MessageStanza": 5, "PresenceStanza": 6, IqStanza: 7, DataMessageStanza: 8, "BatchPresenceStanza": 9, StreamErrorStanza: 10, "HttpRequest": 11, "HttpResponse": 12, "BindAccountRequest": 13, "BindAccountResponse": 14, "TalkMetadata": 15, } class ErrorType(Enum): CONNECTION = 1 READ = 2 LOGIN = 3 NOTIFY = 4 class FcmPushClientRunState(Enum): CREATED = (1,) STARTING_TASKS = (2,) STARTING_CONNECTION = (3,) STARTING_LOGIN = (4,) STARTED = (5,) RESETTING = (6,) STOPPING = (7,) STOPPED = (8,) @dataclass class FcmPushClientConfig: # pylint:disable=too-many-instance-attributes """Class to provide configuration to :class:`firebase_messaging.FcmPushClientConfig`.FcmPushClient.""" server_heartbeat_interval: int | None = 10 """Time in seconds to request the server to send heartbeats""" client_heartbeat_interval: int | None = 20 """Time in seconds to send heartbeats to the server""" send_selective_acknowledgements: bool = True """True to send selective acknowledgements for each message received. Currently if false the client does not send any acknowlegements.""" connection_retry_count: int = 5 """Number of times to retry the connection before giving up.""" start_seconds_before_retry_connect: float = 3 """Time in seconds to wait before attempting to retry the connection after failure.""" reset_interval: float = 3 """Time in seconds to wait between resets after errors or disconnection.""" heartbeat_ack_timeout: float = 5 """Time in seconds to wait for a heartbeat ack before resetting.""" abort_on_sequential_error_count: int | None = 3 """Number of sequential errors of the same time to wait before aborting. If set to None the client will not abort.""" monitor_interval: float = 1 """Time in seconds for the monitor task to fire and check for heartbeats, stale connections and shut down of the main event loop.""" log_warn_limit: int | None = 5 """Number of times to log specific warning messages before going silent for a specific warning type.""" log_debug_verbose: bool = False """Set to True to log all message info including tokens.""" class FcmPushClient: # pylint:disable=too-many-instance-attributes """Client that connects to Firebase Cloud Messaging and receives messages. :param credentials: credentials object returned by register() :param credentials_updated_callback: callback when new credentials are created to allow client to store them :param received_persistent_ids: any persistent id's you already received. :param config: configuration class of :class:`firebase_messaging.FcmPushClientConfig` """ def __init__( self, callback: Callable[[dict, str, Any | None], None], fcm_config: FcmRegisterConfig, credentials: dict | None = None, credentials_updated_callback: CredentialsUpdatedCallable | None = None, *, callback_context: object | None = None, received_persistent_ids: list[str] | None = None, config: FcmPushClientConfig | None = None, http_client_session: ClientSession | None = None, ): """Initializes the receiver.""" self.callback = callback self.callback_context = callback_context self.fcm_config = fcm_config self.credentials = credentials self.credentials_updated_callback = credentials_updated_callback self.persistent_ids = received_persistent_ids if received_persistent_ids else [] self.config = config if config else FcmPushClientConfig() if self.config.log_debug_verbose: _logger.setLevel(logging.DEBUG) self._http_client_session = http_client_session self.reader: asyncio.StreamReader | None = None self.writer: asyncio.StreamWriter | None = None self.do_listen = False self.sequential_error_counters: dict[ErrorType, int] = {} self.log_warn_counters: dict[str, int] = {} # reset variables self.input_stream_id = 0 self.last_input_stream_id_reported = -1 self.first_message = True self.last_login_time: float | None = None self.last_message_time: float | None = None self.run_state: FcmPushClientRunState = FcmPushClientRunState.CREATED self.tasks: list[asyncio.Task] = [] self.reset_lock: asyncio.Lock | None = None self.stopping_lock: asyncio.Lock | None = None def _msg_str(self, msg: Message) -> str: if self.config.log_debug_verbose: return type(msg).__name__ + "\n" + MessageToJson(msg, indent=4) return type(msg).__name__ def _log_verbose(self, msg: str, *args: object) -> None: if self.config.log_debug_verbose: _logger.debug(msg, *args) def _log_warn_with_limit(self, msg: str, *args: object) -> None: if msg not in self.log_warn_counters: self.log_warn_counters[msg] = 0 if ( self.config.log_warn_limit and self.config.log_warn_limit > self.log_warn_counters[msg] ): self.log_warn_counters[msg] += 1 _logger.warning(msg, *args) async def _do_writer_close(self) -> None: writer = self.writer self.writer = None if writer: writer.close() with contextlib.suppress(Exception): await writer.wait_closed() async def _reset(self) -> None: if ( (self.reset_lock and self.reset_lock.locked()) or (self.stopping_lock and self.stopping_lock.locked()) or not self.do_listen ): return async with self.reset_lock: # type: ignore[union-attr] _logger.debug("Resetting connection") self.run_state = FcmPushClientRunState.RESETTING await self._do_writer_close() now = time.time() time_since_last_login = now - self.last_login_time # type: ignore[operator] if time_since_last_login < self.config.reset_interval: _logger.debug("%ss since last reset attempt.", time_since_last_login) await asyncio.sleep(self.config.reset_interval - time_since_last_login) _logger.debug("Reestablishing connection") if not await self._connect_with_retry(): _logger.error( "Unable to connect to MCS endpoint " + "after %s tries, shutting down", self.config.connection_retry_count, ) self._terminate() return _logger.debug("Re-connected to ssl socket") await self._login() # protobuf variable length integers are encoded in base 128 # each byte contains 7 bits of the integer and the msb is set if there's # more. pretty simple to implement async def _read_varint32(self) -> int: res = 0 shift = 0 while True: r = await self.reader.readexactly(1) # type: ignore[union-attr] (b,) = struct.unpack("B", r) res |= (b & 0x7F) << shift if (b & 0x80) == 0: break shift += 7 return res @staticmethod def _encode_varint32(x: int) -> bytes: if x == 0: return bytes(bytearray([0])) res = bytearray([]) while x != 0: b = x & 0x7F x >>= 7 if x != 0: b |= 0x80 res.append(b) return bytes(res) @staticmethod def _make_packet(msg: Message, include_version: bool) -> bytes: tag = MCS_MESSAGE_TAG[type(msg)] header = bytearray([MCS_VERSION, tag]) if include_version else bytearray([tag]) payload = msg.SerializeToString() buf = bytes(header) + FcmPushClient._encode_varint32(len(payload)) + payload return buf async def _send_msg(self, msg: Message) -> None: self._log_verbose("Sending packet to server: %s", self._msg_str(msg)) buf = FcmPushClient._make_packet(msg, self.first_message) self.writer.write(buf) # type: ignore[union-attr] await self.writer.drain() # type: ignore[union-attr] async def _receive_msg(self) -> Message | None: if self.first_message: r = await self.reader.readexactly(2) # type: ignore[union-attr] version, tag = struct.unpack("BB", r) if version < MCS_VERSION and version != 38: raise RuntimeError(f"protocol version {version} unsupported") self.first_message = False else: r = await self.reader.readexactly(1) # type: ignore[union-attr] (tag,) = struct.unpack("B", r) size = await self._read_varint32() self._log_verbose( "Received message with tag %s and size %s", tag, size, ) if not size >= 0: self._log_warn_with_limit("Unexpected message size %s", size) return None buf = await self.reader.readexactly(size) # type: ignore[union-attr] msg_class = next(iter([c for c, t in MCS_MESSAGE_TAG.items() if t == tag])) if not msg_class: self._log_warn_with_limit("Unexpected message tag %s", tag) return None if isinstance(msg_class, str): self._log_warn_with_limit("Unconfigured message class %s", msg_class) return None payload = msg_class() # type: ignore[operator] payload.ParseFromString(buf) self._log_verbose("Received payload: %s", self._msg_str(payload)) return payload async def _login(self) -> None: self.run_state = FcmPushClientRunState.STARTING_LOGIN now = time.time() self.input_stream_id = 0 self.last_input_stream_id_reported = -1 self.first_message = True self.last_login_time = now try: android_id = self.credentials["gcm"]["android_id"] # type: ignore[index] req = LoginRequest() req.adaptive_heartbeat = False req.auth_service = LoginRequest.ANDROID_ID # 2 req.auth_token = self.credentials["gcm"]["security_token"] # type: ignore[index] req.id = self.fcm_config.chrome_version req.domain = "mcs.android.com" req.device_id = f"android-{int(android_id):x}" req.network_type = 1 req.resource = android_id req.user = android_id req.use_rmq2 = True req.setting.add(name="new_vc", value="1") req.received_persistent_id.extend(self.persistent_ids) if ( self.config.server_heartbeat_interval and self.config.server_heartbeat_interval > 0 ): req.heartbeat_stat.ip = "" req.heartbeat_stat.timeout = True req.heartbeat_stat.interval_ms = ( 1000 * self.config.server_heartbeat_interval ) await self._send_msg(req) _logger.debug("Sent login request") except Exception as ex: _logger.error("Received an exception logging in: %s", ex) if self._try_increment_error_count(ErrorType.LOGIN): await self._reset() @staticmethod def _decrypt_raw_data( credentials: dict[str, dict[str, str]], crypto_key_str: str, salt_str: str, raw_data: bytes, ) -> bytes: crypto_key = urlsafe_b64decode(crypto_key_str.encode("ascii")) salt = urlsafe_b64decode(salt_str.encode("ascii")) der_data_str = credentials["keys"]["private"] der_data = urlsafe_b64decode(der_data_str.encode("ascii") + b"========") secret_str = credentials["keys"]["secret"] secret = urlsafe_b64decode(secret_str.encode("ascii") + b"========") privkey = load_der_private_key( der_data, password=None, backend=default_backend() ) decrypted = http_decrypt( raw_data, salt=salt, private_key=privkey, dh=crypto_key, version="aesgcm", auth_secret=secret, ) return decrypted def _app_data_by_key( self, p: DataMessageStanza, key: str, do_not_raise: bool = False ) -> str: for x in p.app_data: if x.key == key: return x.value if do_not_raise: return "" raise RuntimeError(f"couldn't find in app_data {key}") def _handle_data_message( self, msg: DataMessageStanza, ) -> None: _logger.debug( "Received data message Stream ID: %s, Last: %s, Status: %s", msg.stream_id, msg.last_stream_id_received, msg.status, ) if ( self._app_data_by_key(msg, "message_type", do_not_raise=True) == "deleted_messages" ): # The deleted_messages message does not contain data. return crypto_key = self._app_data_by_key(msg, "crypto-key")[3:] # strip dh= salt = self._app_data_by_key(msg, "encryption")[5:] # strip salt= subtype = self._app_data_by_key(msg, "subtype") if TYPE_CHECKING: assert self.credentials if subtype != self.credentials["gcm"]["app_id"]: self._log_warn_with_limit( "Subtype %s in data message does not match" + "app id client was registered with %s", subtype, self.credentials["gcm"]["app_id"], ) if not self.credentials: return decrypted = self._decrypt_raw_data( self.credentials, crypto_key, salt, msg.raw_data ) with contextlib_suppress(json.JSONDecodeError, ValueError): decrypted_json = json.loads(decrypted.decode("utf-8")) ret_val = decrypted_json if decrypted_json else decrypted self._log_verbose( "Decrypted data for message %s is: %s", msg.persistent_id, ret_val ) try: self.callback(ret_val, msg.persistent_id, self.callback_context) self._reset_error_count(ErrorType.NOTIFY) except Exception: _logger.exception("Unexpected exception calling notification callback\n") self._try_increment_error_count(ErrorType.NOTIFY) def _new_input_stream_id_available(self) -> bool: return self.last_input_stream_id_reported != self.input_stream_id def _get_input_stream_id(self) -> int: self.last_input_stream_id_reported = self.input_stream_id return self.input_stream_id async def _handle_ping(self, p: HeartbeatPing) -> None: _logger.debug( "Received heartbeat ping, sending ack: Stream ID: %s, Last: %s, Status: %s", p.stream_id, p.last_stream_id_received, p.status, ) req = HeartbeatAck() if self._new_input_stream_id_available(): req.last_stream_id_received = self._get_input_stream_id() await self._send_msg(req) async def _handle_iq(self, p: IqStanza) -> None: if not p.extension: self._log_warn_with_limit( "Unexpected IqStanza id received with no extension", str(p) ) return if p.extension.id not in (12, 13): self._log_warn_with_limit( "Unexpected extension id received: %s", p.extension.id ) return async def _send_selective_ack(self, persistent_id: str) -> None: iqs = IqStanza() iqs.type = IqStanza.IqType.SET iqs.id = "" iqs.extension.id = MCS_SELECTIVE_ACK_ID sa = SelectiveAck() sa.id.extend([persistent_id]) iqs.extension.data = sa.SerializeToString() _logger.debug("Sending selective ack for message id %s", persistent_id) await self._send_msg(iqs) async def _send_heartbeat(self) -> None: req = HeartbeatPing() if self._new_input_stream_id_available(): req.last_stream_id_received = self._get_input_stream_id() await self._send_msg(req) _logger.debug("Sent heartbeat ping") def _terminate(self) -> None: self.run_state = FcmPushClientRunState.STOPPING self.do_listen = False current_task = asyncio.current_task() for task in self.tasks: if ( current_task != task and not task.done() ): # cancel return if task is done so no need to check task.cancel() async def _do_monitor(self) -> None: while self.do_listen: await asyncio.sleep(self.config.monitor_interval) if self.run_state == FcmPushClientRunState.STARTED: # if server_heartbeat_interval is set and less than # client_heartbeat_interval then the last_message_time # will be within the client window if connected if self.config.client_heartbeat_interval: now = time.time() if ( self.last_message_time + self.config.client_heartbeat_interval # type: ignore[operator] < now ): await self._send_heartbeat() await asyncio.sleep(self.config.heartbeat_ack_timeout) now = time.time() if ( # Check state hasn't changed during sleep self.last_message_time # type: ignore[operator] + self.config.client_heartbeat_interval < now and self.do_listen and self.run_state == FcmPushClientRunState.STARTED ): await self._reset() elif self.config.server_heartbeat_interval: now = time.time() if ( # We give the server 2 extra seconds self.last_message_time + self.config.server_heartbeat_interval # type: ignore[operator] < now - 2 ): await self._reset() def _reset_error_count(self, error_type: ErrorType) -> None: self.sequential_error_counters[error_type] = 0 def _try_increment_error_count(self, error_type: ErrorType) -> bool: if error_type not in self.sequential_error_counters: self.sequential_error_counters[error_type] = 0 self.sequential_error_counters[error_type] += 1 if ( self.config.abort_on_sequential_error_count and self.sequential_error_counters[error_type] >= self.config.abort_on_sequential_error_count ): _logger.error( "Shutting down push receiver due to " + f"{self.sequential_error_counters[error_type]} sequential" + f" errors of type {error_type}" ) self._terminate() return False return True async def _handle_message(self, msg: Message) -> None: self.last_message_time = time.time() self.input_stream_id += 1 if isinstance(msg, Close): self._log_warn_with_limit("Server sent Close message, resetting") if self._try_increment_error_count(ErrorType.CONNECTION): await self._reset() return if isinstance(msg, LoginResponse): if str(msg.error): _logger.error("Received login error response: %s", msg) if self._try_increment_error_count(ErrorType.LOGIN): await self._reset() else: _logger.info("Succesfully logged in to MCS endpoint") self._reset_error_count(ErrorType.LOGIN) self.run_state = FcmPushClientRunState.STARTED self.persistent_ids = [] return if isinstance(msg, DataMessageStanza): self._handle_data_message(msg) self.persistent_ids.append(msg.persistent_id) if self.config.send_selective_acknowledgements: await self._send_selective_ack(msg.persistent_id) elif isinstance(msg, HeartbeatPing): await self._handle_ping(msg) elif isinstance(msg, HeartbeatAck): _logger.debug("Received heartbeat ack: %s", msg) elif isinstance(msg, IqStanza): pass else: self._log_warn_with_limit("Unexpected message type %s.", type(msg).__name__) # Reset error count if a read has been succesful self._reset_error_count(ErrorType.READ) self._reset_error_count(ErrorType.CONNECTION) @staticmethod async def _open_connection( host: str, port: int, ssl_context: ssl.SSLContext ) -> tuple[asyncio.StreamReader, asyncio.StreamWriter]: return await asyncio.open_connection(host=host, port=port, ssl=ssl_context) async def _connect(self) -> bool: try: loop = asyncio.get_running_loop() # create_default_context() blocks the event loop ssl_context = await loop.run_in_executor(None, ssl.create_default_context) self.reader, self.writer = await self._open_connection( host=MCS_HOST, port=MCS_PORT, ssl_context=ssl_context ) _logger.debug("Connected to MCS endpoint (%s,%s)", MCS_HOST, MCS_PORT) return True except OSError as oex: _logger.error( "Could not connected to MCS endpoint (%s,%s): %s", MCS_HOST, MCS_PORT, oex, ) return False async def _connect_with_retry(self) -> bool: self.run_state = FcmPushClientRunState.STARTING_CONNECTION trycount = 0 connected = False while ( trycount < self.config.connection_retry_count and not connected and self.do_listen ): trycount += 1 connected = await self._connect() if not connected: sleep_time = ( self.config.start_seconds_before_retry_connect * trycount * trycount ) _logger.info( "Could not connect to MCS Endpoint on " + "try %s, sleeping for %s seconds", trycount, sleep_time, ) await asyncio.sleep(sleep_time) if not connected: _logger.error( "Unable to connect to MCS endpoint after %s tries, aborting", trycount ) return connected async def _listen(self) -> None: """listens for push notifications.""" if not await self._connect_with_retry(): return try: await self._login() while self.do_listen: try: if self.run_state == FcmPushClientRunState.RESETTING: await asyncio.sleep(1) elif msg := await self._receive_msg(): await self._handle_message(msg) except (OSError, EOFError) as osex: if ( isinstance( osex, ( ConnectionResetError, TimeoutError, asyncio.IncompleteReadError, ssl.SSLError, ), ) and self.run_state == FcmPushClientRunState.RESETTING ): if ( isinstance(osex, ssl.SSLError) # pylint: disable=no-member and osex.reason != "APPLICATION_DATA_AFTER_CLOSE_NOTIFY" ): self._log_warn_with_limit( "Unexpected SSLError reason during reset of %s", osex.reason, ) else: self._log_verbose( "Expected read error during reset: %s", type(osex).__name__, ) else: _logger.exception("Unexpected exception during read\n") if self._try_increment_error_count(ErrorType.CONNECTION): await self._reset() except Exception as ex: _logger.error( "Unknown error: %s, shutting down FcmPushClient.\n%s", ex, traceback.format_exc(), ) self._terminate() finally: await self._do_writer_close() async def checkin_or_register(self) -> str: """Check in if you have credentials otherwise register as a new client. :param sender_id: sender id identifying push service you are connecting to. :param app_id: identifier for your application. :return: The FCM token which is used to identify you with the push end point application. """ self.register = FcmRegister( self.fcm_config, self.credentials, self.credentials_updated_callback, http_client_session=self._http_client_session, ) self.credentials = await self.register.checkin_or_register() # await self.register.fcm_refresh_install() await self.register.close() return self.credentials["fcm"]["registration"]["token"] async def start(self) -> None: """Connect to FCM and start listening for push notifications.""" self.reset_lock = asyncio.Lock() self.stopping_lock = asyncio.Lock() self.do_listen = True self.run_state = FcmPushClientRunState.STARTING_TASKS try: self.tasks = [ asyncio.create_task(self._listen()), asyncio.create_task(self._do_monitor()), ] except Exception as ex: _logger.error("Unexpected error running FcmPushClient: %s", ex) async def stop(self) -> None: if ( self.stopping_lock and self.stopping_lock.locked() or self.run_state in ( FcmPushClientRunState.STOPPING, FcmPushClientRunState.STOPPED, ) ): return async with self.stopping_lock: # type: ignore[union-attr] try: self.run_state = FcmPushClientRunState.STOPPING self.do_listen = False for task in self.tasks: if not task.done(): task.cancel() finally: self.run_state = FcmPushClientRunState.STOPPED self.fcm_thread = None self.listen_event_loop = None def is_started(self) -> bool: return self.run_state == FcmPushClientRunState.STARTED async def send_message(self, raw_data: bytes, persistent_id: str) -> None: """Not implemented, does nothing atm.""" dms = DataMessageStanza() dms.persistent_id = persistent_id # Not supported yet firebase-messaging-0.4.4/firebase_messaging/fcmregister.py000066400000000000000000000432011467555115100237650ustar00rootroot00000000000000from __future__ import annotations import asyncio import json import logging import os import secrets import time import uuid from base64 import b64encode, urlsafe_b64encode from dataclasses import dataclass from typing import Any, Callable from aiohttp import ClientSession, ClientTimeout from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec from google.protobuf.json_format import MessageToDict, MessageToJson from .const import ( AUTH_VERSION, FCM_INSTALLATION, FCM_REGISTRATION, FCM_SEND_URL, GCM_CHECKIN_URL, GCM_REGISTER_URL, GCM_SERVER_KEY_B64, SDK_VERSION, ) from .proto.android_checkin_pb2 import ( DEVICE_CHROME_BROWSER, AndroidCheckinProto, ChromeBuildProto, ) from .proto.checkin_pb2 import ( AndroidCheckinRequest, AndroidCheckinResponse, ) _logger = logging.getLogger(__name__) @dataclass class FcmRegisterConfig: project_id: str app_id: str api_key: str messaging_sender_id: str bundle_id: str = "receiver.push.com" chrome_id: str = "org.chromium.linux" chrome_version: str = "94.0.4606.51" vapid_key: str | None = GCM_SERVER_KEY_B64 persistend_ids: list[str] | None = None heartbeat_interval_ms: int = 5 * 60 * 1000 # 5 mins def __postinit__(self) -> None: if self.persistend_ids is None: self.persistend_ids = [] class FcmRegister: CLIENT_TIMEOUT = ClientTimeout(total=3) def __init__( self, config: FcmRegisterConfig, credentials: dict | None = None, credentials_updated_callback: Callable[[dict[str, Any]], None] | None = None, *, http_client_session: ClientSession | None = None, log_debug_verbose: bool = False, ): self.config = config self.credentials = credentials self.credentials_updated_callback = credentials_updated_callback self._log_debug_verbose = log_debug_verbose self._http_client_session = http_client_session self._local_session: ClientSession | None = None def _get_checkin_payload( self, android_id: int | None = None, security_token: int | None = None ) -> AndroidCheckinRequest: chrome = ChromeBuildProto() chrome.platform = ChromeBuildProto.Platform.PLATFORM_LINUX # 3 chrome.chrome_version = self.config.chrome_version chrome.channel = ChromeBuildProto.Channel.CHANNEL_STABLE # 1 checkin = AndroidCheckinProto() checkin.type = DEVICE_CHROME_BROWSER # 3 checkin.chrome_build.CopyFrom(chrome) payload = AndroidCheckinRequest() payload.user_serial_number = 0 payload.checkin.CopyFrom(checkin) payload.version = 3 if android_id and security_token: payload.id = int(android_id) payload.security_token = int(security_token) return payload async def gcm_check_in_and_register( self, ) -> dict[str, Any] | None: options = await self.gcm_check_in() if not options: raise RuntimeError("Unable to register and check in to gcm") gcm_credentials = await self.gcm_register(options) return gcm_credentials async def gcm_check_in( self, android_id: int | None = None, security_token: int | None = None, ) -> dict[str, Any] | None: """ perform check-in request android_id, security_token can be provided if we already did the initial check-in returns dict with android_id, security_token and more """ payload = self._get_checkin_payload(android_id, security_token) if self._log_debug_verbose: _logger.debug("GCM check in payload:\n%s", payload) retries = 3 acir = None content = None for try_num in range(retries): try: async with self._session.post( url=GCM_CHECKIN_URL, headers={"Content-Type": "application/x-protobuf"}, data=payload.SerializeToString(), timeout=self.CLIENT_TIMEOUT, ) as resp: if resp.status == 200: acir = AndroidCheckinResponse() content = await resp.read() break else: text = await resp.text() if acir and content: break else: _logger.warning( "GCM checkin failed on attempt %s out " + "of %s with status: %s, %s", try_num + 1, retries, resp.status, text, ) # retry without android id and security_token payload = self._get_checkin_payload() await asyncio.sleep(1) except Exception as e: _logger.warning( "Error during gcm checkin post attempt %s out of %s", try_num + 1, retries, exc_info=e, ) await asyncio.sleep(1) if not acir or not content: _logger.error("Unable to checkin to gcm after %s retries", retries) return None acir.ParseFromString(content) if self._log_debug_verbose: msg = MessageToJson(acir, indent=4) _logger.debug("GCM check in response (raw):\n%s", msg) return MessageToDict(acir) async def gcm_register( self, options: dict[str, Any], retries: int = 2, ) -> dict[str, str] | None: """ obtains a gcm token app_id: app id as an integer retries: number of failed requests before giving up returns {"token": "...", "gcm_app_id": 123123, "androidId":123123, "securityToken": 123123} """ # contains android_id, security_token and more gcm_app_id = f"wp:{self.config.bundle_id}#{uuid.uuid4()}" android_id = options["androidId"] security_token = options["securityToken"] headers = { "Authorization": f"AidLogin {android_id}:{security_token}", "Content-Type": "application/x-www-form-urlencoded", } body = { "app": "org.chromium.linux", "X-subtype": gcm_app_id, "device": android_id, "sender": GCM_SERVER_KEY_B64, } if self._log_debug_verbose: _logger.debug("GCM Registration request: %s", body) last_error: str | Exception | None = None for try_num in range(retries): try: async with self._session.post( url=GCM_REGISTER_URL, headers=headers, data=body, timeout=self.CLIENT_TIMEOUT, ) as resp: response_text = await resp.text() if "Error" in response_text: _logger.warning( "GCM register request attempt %s out of %s has failed with %s", try_num + 1, retries, response_text, ) last_error = response_text await asyncio.sleep(1) continue token = response_text.split("=")[1] return { "token": token, "app_id": gcm_app_id, "android_id": android_id, "security_token": security_token, } except Exception as e: last_error = e _logger.warning( "Error during gcm auth request attempt %s out of %s", try_num + 1, retries, exc_info=e, ) await asyncio.sleep(1) errorstr = f"Unable to complete gcm auth request after {retries} tries" if isinstance(last_error, Exception): _logger.error(errorstr, exc_info=last_error) else: errorstr += f", last error was {last_error}" _logger.error(errorstr) return None async def fcm_install_and_register( self, gcm_data: dict[str, Any], keys: dict[str, Any] ) -> dict[str, Any] | None: if installation := await self.fcm_install(): registration = await self.fcm_register(gcm_data, installation, keys) return { "registration": registration, "installation": installation, } return None async def fcm_install(self) -> dict | None: fid = bytearray(secrets.token_bytes(17)) # Replace the first 4 bits with the FID header 0b0111. fid[0] = 0b01110000 + (fid[0] % 0b00010000) fid64 = b64encode(fid).decode() hb_header = b64encode( json.dumps({"heartbeats": [], "version": 2}).encode() ).decode() headers = { "x-firebase-client": hb_header, "x-goog-api-key": self.config.api_key, } payload = { "appId": self.config.app_id, "authVersion": AUTH_VERSION, "fid": fid64, "sdkVersion": SDK_VERSION, } url = FCM_INSTALLATION + f"projects/{self.config.project_id}/installations" async with self._session.post( url=url, headers=headers, data=json.dumps(payload), timeout=self.CLIENT_TIMEOUT, ) as resp: if resp.status == 200: fcm_install = await resp.json() return { "token": fcm_install["authToken"]["token"], "expires_in": int(fcm_install["authToken"]["expiresIn"][:-1:]), "refresh_token": fcm_install["refreshToken"], "fid": fcm_install["fid"], "created_at": time.monotonic(), } else: text = await resp.text() _logger.error( "Error during fcm_install: %s ", text, ) return None async def fcm_refresh_install_token(self) -> dict | None: hb_header = b64encode( json.dumps({"heartbeats": [], "version": 2}).encode() ).decode() if not self.credentials: raise RuntimeError("Credentials must be set to refresh install token") fcm_refresh_token = self.credentials["fcm"]["installation"]["refresh_token"] headers = { "Authorization": f"{AUTH_VERSION} {fcm_refresh_token}", "x-firebase-client": hb_header, "x-goog-api-key": self.config.api_key, } payload = { "installation": { "sdkVersion": SDK_VERSION, "appId": self.config.app_id, } } url = ( FCM_INSTALLATION + f"projects/{self.config.project_id}/" "installations/{fid}/authTokens:generate" ) async with self._session.post( url=url, headers=headers, data=json.dumps(payload), timeout=self.CLIENT_TIMEOUT, ) as resp: if resp.status == 200: fcm_refresh = await resp.json() return { "token": fcm_refresh["token"], "expires_in": int(fcm_refresh["expiresIn"][:-1:]), "created_at": time.monotonic(), } else: text = await resp.text() _logger.error( "Error during fcm_refresh_install_token: %s ", text, ) return None def generate_keys(self) -> dict: private_key = ec.generate_private_key(ec.SECP256R1()) public_key = private_key.public_key() serialized_private = private_key.private_bytes( encoding=serialization.Encoding.DER, # asn1 format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption(), ) serialized_public = public_key.public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) return { "public": urlsafe_b64encode(serialized_public[26:]).decode( "ascii" ), # urlsafe_base64(serialized_public[26:]), "private": urlsafe_b64encode(serialized_private).decode("ascii"), "secret": urlsafe_b64encode(os.urandom(16)).decode("ascii"), } async def fcm_register( self, gcm_data: dict, installation: dict, keys: dict, retries: int = 2, ) -> dict[str, Any] | None: headers = { "x-goog-api-key": self.config.api_key, "x-goog-firebase-installations-auth": installation["token"], } # If vapid_key is the default do not send it here or it will error vapid_key = ( self.config.vapid_key if self.config.vapid_key != GCM_SERVER_KEY_B64 else None ) payload = { "web": { "applicationPubKey": vapid_key, "auth": keys["secret"], "endpoint": FCM_SEND_URL + gcm_data["token"], "p256dh": keys["public"], } } url = FCM_REGISTRATION + f"projects/{self.config.project_id}/registrations" if self._log_debug_verbose: _logger.debug("FCM registration data: %s", payload) for try_num in range(retries): try: async with self._session.post( url=url, headers=headers, data=json.dumps(payload), timeout=self.CLIENT_TIMEOUT, ) as resp: if resp.status == 200: fcm = await resp.json() return fcm else: text = await resp.text() _logger.error( # pylint: disable=duplicate-code "Error during fmc register request " "attempt %s out of %s: %s", try_num + 1, retries, text, ) except Exception as e: _logger.error( # pylint: disable=duplicate-code "Error during fmc register request attempt %s out of %s", try_num + 1, retries, exc_info=e, ) await asyncio.sleep(1) return None async def checkin_or_register(self) -> dict[str, Any]: """Check in if you have credentials otherwise register as a new client. :param sender_id: sender id identifying push service you are connecting to. :param app_id: identifier for your application. :return: The FCM token which is used to identify you with the push end point application. """ if self.credentials: gcm_response = await self.gcm_check_in( self.credentials["gcm"]["android_id"], self.credentials["gcm"]["security_token"], ) if gcm_response: return self.credentials self.credentials = await self.register() if self.credentials_updated_callback: self.credentials_updated_callback(self.credentials) return self.credentials async def register(self) -> dict: """Register gcm and fcm tokens for sender_id. Typically you would call checkin instead of register which does not do a full registration if credentials are present :param sender_id: sender id identifying push service you are connecting to. :param app_id: identifier for your application. :return: The dict containing all credentials. """ keys = self.generate_keys() gcm_data = await self.gcm_check_in_and_register() if gcm_data is None: raise RuntimeError( "Unable to establish subscription with Google Cloud Messaging." ) self._log_verbose("GCM subscription: %s", gcm_data) fcm_data = await self.fcm_install_and_register(gcm_data, keys) if not fcm_data: raise RuntimeError("Unable to register with fcm") self._log_verbose("FCM registration: %s", fcm_data) res: dict[str, Any] = { "keys": keys, "gcm": gcm_data, "fcm": fcm_data, "config": { "bundle_id": self.config.bundle_id, "project_id": self.config.project_id, "vapid_key": self.config.vapid_key, }, } self._log_verbose("Credential: %s", res) _logger.info("Registered with FCM") return res def _log_verbose(self, msg: str, *args: object) -> None: if self._log_debug_verbose: _logger.debug(msg, *args) @property def _session(self) -> ClientSession: if self._http_client_session: return self._http_client_session if self._local_session is None: self._local_session = ClientSession() return self._local_session async def close(self) -> None: """Close aiohttp session.""" session = self._local_session self._local_session = None if session: await session.close() firebase-messaging-0.4.4/firebase_messaging/proto/000077500000000000000000000000001467555115100222445ustar00rootroot00000000000000firebase-messaging-0.4.4/firebase_messaging/proto/android_checkin.proto000066400000000000000000000060451467555115100264420ustar00rootroot00000000000000// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Logging information for Android "checkin" events (automatic, periodic // requests made by Android devices to the server). syntax = "proto2"; option optimize_for = LITE_RUNTIME; package checkin_proto; // Build characteristics unique to the Chrome browser, and Chrome OS message ChromeBuildProto { enum Platform { PLATFORM_WIN = 1; PLATFORM_MAC = 2; PLATFORM_LINUX = 3; PLATFORM_CROS = 4; PLATFORM_IOS = 5; // Just a placeholder. Likely don't need it due to the presence of the // Android GCM on phone/tablet devices. PLATFORM_ANDROID = 6; } enum Channel { CHANNEL_STABLE = 1; CHANNEL_BETA = 2; CHANNEL_DEV = 3; CHANNEL_CANARY = 4; CHANNEL_UNKNOWN = 5; // for tip of tree or custom builds } // The platform of the device. optional Platform platform = 1; // The Chrome instance's version. optional string chrome_version = 2; // The Channel (build type) of Chrome. optional Channel channel = 3; } // Information sent by the device in a "checkin" request. message AndroidCheckinProto { // Miliseconds since the Unix epoch of the device's last successful checkin. optional int64 last_checkin_msec = 2; // The current MCC+MNC of the mobile device's current cell. optional string cell_operator = 6; // The MCC+MNC of the SIM card (different from operator if the // device is roaming, for instance). optional string sim_operator = 7; // The device's current roaming state (reported starting in eclair builds). // Currently one of "{,not}mobile-{,not}roaming", if it is present at all. optional string roaming = 8; // For devices supporting multiple user profiles (which may be // supported starting in jellybean), the ordinal number of the // profile that is checking in. This is 0 for the primary profile // (which can't be changed without wiping the device), and 1,2,3,... // for additional profiles (which can be added and deleted freely). optional int32 user_number = 9; // Class of device. Indicates the type of build proto // (IosBuildProto/ChromeBuildProto/AndroidBuildProto) // That is included in this proto optional DeviceType type = 12 [default = DEVICE_ANDROID_OS]; // For devices running MCS on Chrome, build-specific characteristics // of the browser. There are no hardware aspects (except for ChromeOS). // This will only be populated for Chrome builds/ChromeOS devices optional checkin_proto.ChromeBuildProto chrome_build = 13; // Note: Some of the Android specific optional fields were skipped to limit // the protobuf definition. // Next 14 } // enum values correspond to the type of device. // Used in the AndroidCheckinProto and Device proto. enum DeviceType { // Android Device DEVICE_ANDROID_OS = 1; // Apple IOS device DEVICE_IOS_OS = 2; // Chrome browser - Not Chrome OS. No hardware records. DEVICE_CHROME_BROWSER = 3; // Chrome OS DEVICE_CHROME_OS = 4; } firebase-messaging-0.4.4/firebase_messaging/proto/android_checkin_pb2.py000066400000000000000000000054411467555115100264710ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! # source: android_checkin.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( b'\n\x15\x61ndroid_checkin.proto\x12\rcheckin_proto"\x8a\x03\n\x10\x43hromeBuildProto\x12:\n\x08platform\x18\x01 \x01(\x0e\x32(.checkin_proto.ChromeBuildProto.Platform\x12\x16\n\x0e\x63hrome_version\x18\x02 \x01(\t\x12\x38\n\x07\x63hannel\x18\x03 \x01(\x0e\x32\'.checkin_proto.ChromeBuildProto.Channel"}\n\x08Platform\x12\x10\n\x0cPLATFORM_WIN\x10\x01\x12\x10\n\x0cPLATFORM_MAC\x10\x02\x12\x12\n\x0ePLATFORM_LINUX\x10\x03\x12\x11\n\rPLATFORM_CROS\x10\x04\x12\x10\n\x0cPLATFORM_IOS\x10\x05\x12\x14\n\x10PLATFORM_ANDROID\x10\x06"i\n\x07\x43hannel\x12\x12\n\x0e\x43HANNEL_STABLE\x10\x01\x12\x10\n\x0c\x43HANNEL_BETA\x10\x02\x12\x0f\n\x0b\x43HANNEL_DEV\x10\x03\x12\x12\n\x0e\x43HANNEL_CANARY\x10\x04\x12\x13\n\x0f\x43HANNEL_UNKNOWN\x10\x05"\xf6\x01\n\x13\x41ndroidCheckinProto\x12\x19\n\x11last_checkin_msec\x18\x02 \x01(\x03\x12\x15\n\rcell_operator\x18\x06 \x01(\t\x12\x14\n\x0csim_operator\x18\x07 \x01(\t\x12\x0f\n\x07roaming\x18\x08 \x01(\t\x12\x13\n\x0buser_number\x18\t \x01(\x05\x12:\n\x04type\x18\x0c \x01(\x0e\x32\x19.checkin_proto.DeviceType:\x11\x44\x45VICE_ANDROID_OS\x12\x35\n\x0c\x63hrome_build\x18\r \x01(\x0b\x32\x1f.checkin_proto.ChromeBuildProto*g\n\nDeviceType\x12\x15\n\x11\x44\x45VICE_ANDROID_OS\x10\x01\x12\x11\n\rDEVICE_IOS_OS\x10\x02\x12\x19\n\x15\x44\x45VICE_CHROME_BROWSER\x10\x03\x12\x14\n\x10\x44\x45VICE_CHROME_OS\x10\x04\x42\x02H\x03' ) _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "android_checkin_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: _globals["DESCRIPTOR"]._options = None _globals["DESCRIPTOR"]._serialized_options = b"H\003" _globals["_DEVICETYPE"]._serialized_start = 686 _globals["_DEVICETYPE"]._serialized_end = 789 _globals["_CHROMEBUILDPROTO"]._serialized_start = 41 _globals["_CHROMEBUILDPROTO"]._serialized_end = 435 _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_start = 203 _globals["_CHROMEBUILDPROTO_PLATFORM"]._serialized_end = 328 _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_start = 330 _globals["_CHROMEBUILDPROTO_CHANNEL"]._serialized_end = 435 _globals["_ANDROIDCHECKINPROTO"]._serialized_start = 438 _globals["_ANDROIDCHECKINPROTO"]._serialized_end = 684 # @@protoc_insertion_point(module_scope) firebase-messaging-0.4.4/firebase_messaging/proto/android_checkin_pb2.pyi000066400000000000000000000222431467555115100266410ustar00rootroot00000000000000""" @generated by mypy-protobuf. Do not edit manually! isort:skip_file Copyright 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. Logging information for Android "checkin" events (automatic, periodic requests made by Android devices to the server). """ import builtins import google.protobuf.descriptor import google.protobuf.internal.enum_type_wrapper import google.protobuf.message import sys import typing if sys.version_info >= (3, 10): import typing as typing_extensions else: import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor class _DeviceType: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _DeviceTypeEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DeviceType.ValueType], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor DEVICE_ANDROID_OS: _DeviceType.ValueType # 1 """Android Device""" DEVICE_IOS_OS: _DeviceType.ValueType # 2 """Apple IOS device""" DEVICE_CHROME_BROWSER: _DeviceType.ValueType # 3 """Chrome browser - Not Chrome OS. No hardware records.""" DEVICE_CHROME_OS: _DeviceType.ValueType # 4 """Chrome OS""" class DeviceType(_DeviceType, metaclass=_DeviceTypeEnumTypeWrapper): """enum values correspond to the type of device. Used in the AndroidCheckinProto and Device proto. """ DEVICE_ANDROID_OS: DeviceType.ValueType # 1 """Android Device""" DEVICE_IOS_OS: DeviceType.ValueType # 2 """Apple IOS device""" DEVICE_CHROME_BROWSER: DeviceType.ValueType # 3 """Chrome browser - Not Chrome OS. No hardware records.""" DEVICE_CHROME_OS: DeviceType.ValueType # 4 """Chrome OS""" global___DeviceType = DeviceType @typing_extensions.final class ChromeBuildProto(google.protobuf.message.Message): """Build characteristics unique to the Chrome browser, and Chrome OS""" DESCRIPTOR: google.protobuf.descriptor.Descriptor class _Platform: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _PlatformEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ ChromeBuildProto._Platform.ValueType ], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor PLATFORM_WIN: ChromeBuildProto._Platform.ValueType # 1 PLATFORM_MAC: ChromeBuildProto._Platform.ValueType # 2 PLATFORM_LINUX: ChromeBuildProto._Platform.ValueType # 3 PLATFORM_CROS: ChromeBuildProto._Platform.ValueType # 4 PLATFORM_IOS: ChromeBuildProto._Platform.ValueType # 5 PLATFORM_ANDROID: ChromeBuildProto._Platform.ValueType # 6 """Just a placeholder. Likely don't need it due to the presence of the Android GCM on phone/tablet devices. """ class Platform(_Platform, metaclass=_PlatformEnumTypeWrapper): ... PLATFORM_WIN: ChromeBuildProto.Platform.ValueType # 1 PLATFORM_MAC: ChromeBuildProto.Platform.ValueType # 2 PLATFORM_LINUX: ChromeBuildProto.Platform.ValueType # 3 PLATFORM_CROS: ChromeBuildProto.Platform.ValueType # 4 PLATFORM_IOS: ChromeBuildProto.Platform.ValueType # 5 PLATFORM_ANDROID: ChromeBuildProto.Platform.ValueType # 6 """Just a placeholder. Likely don't need it due to the presence of the Android GCM on phone/tablet devices. """ class _Channel: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _ChannelEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ ChromeBuildProto._Channel.ValueType ], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor CHANNEL_STABLE: ChromeBuildProto._Channel.ValueType # 1 CHANNEL_BETA: ChromeBuildProto._Channel.ValueType # 2 CHANNEL_DEV: ChromeBuildProto._Channel.ValueType # 3 CHANNEL_CANARY: ChromeBuildProto._Channel.ValueType # 4 CHANNEL_UNKNOWN: ChromeBuildProto._Channel.ValueType # 5 """for tip of tree or custom builds""" class Channel(_Channel, metaclass=_ChannelEnumTypeWrapper): ... CHANNEL_STABLE: ChromeBuildProto.Channel.ValueType # 1 CHANNEL_BETA: ChromeBuildProto.Channel.ValueType # 2 CHANNEL_DEV: ChromeBuildProto.Channel.ValueType # 3 CHANNEL_CANARY: ChromeBuildProto.Channel.ValueType # 4 CHANNEL_UNKNOWN: ChromeBuildProto.Channel.ValueType # 5 """for tip of tree or custom builds""" PLATFORM_FIELD_NUMBER: builtins.int CHROME_VERSION_FIELD_NUMBER: builtins.int CHANNEL_FIELD_NUMBER: builtins.int platform: global___ChromeBuildProto.Platform.ValueType """The platform of the device.""" chrome_version: builtins.str """The Chrome instance's version.""" channel: global___ChromeBuildProto.Channel.ValueType """The Channel (build type) of Chrome.""" def __init__( self, *, platform: global___ChromeBuildProto.Platform.ValueType | None = ..., chrome_version: builtins.str | None = ..., channel: global___ChromeBuildProto.Channel.ValueType | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "channel", b"channel", "chrome_version", b"chrome_version", "platform", b"platform", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "channel", b"channel", "chrome_version", b"chrome_version", "platform", b"platform", ], ) -> None: ... global___ChromeBuildProto = ChromeBuildProto @typing_extensions.final class AndroidCheckinProto(google.protobuf.message.Message): """Information sent by the device in a "checkin" request.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor LAST_CHECKIN_MSEC_FIELD_NUMBER: builtins.int CELL_OPERATOR_FIELD_NUMBER: builtins.int SIM_OPERATOR_FIELD_NUMBER: builtins.int ROAMING_FIELD_NUMBER: builtins.int USER_NUMBER_FIELD_NUMBER: builtins.int TYPE_FIELD_NUMBER: builtins.int CHROME_BUILD_FIELD_NUMBER: builtins.int last_checkin_msec: builtins.int """Miliseconds since the Unix epoch of the device's last successful checkin.""" cell_operator: builtins.str """The current MCC+MNC of the mobile device's current cell.""" sim_operator: builtins.str """The MCC+MNC of the SIM card (different from operator if the device is roaming, for instance). """ roaming: builtins.str """The device's current roaming state (reported starting in eclair builds). Currently one of "{,not}mobile-{,not}roaming", if it is present at all. """ user_number: builtins.int """For devices supporting multiple user profiles (which may be supported starting in jellybean), the ordinal number of the profile that is checking in. This is 0 for the primary profile (which can't be changed without wiping the device), and 1,2,3,... for additional profiles (which can be added and deleted freely). """ type: global___DeviceType.ValueType """Class of device. Indicates the type of build proto (IosBuildProto/ChromeBuildProto/AndroidBuildProto) That is included in this proto """ @property def chrome_build(self) -> global___ChromeBuildProto: """For devices running MCS on Chrome, build-specific characteristics of the browser. There are no hardware aspects (except for ChromeOS). This will only be populated for Chrome builds/ChromeOS devices """ def __init__( self, *, last_checkin_msec: builtins.int | None = ..., cell_operator: builtins.str | None = ..., sim_operator: builtins.str | None = ..., roaming: builtins.str | None = ..., user_number: builtins.int | None = ..., type: global___DeviceType.ValueType | None = ..., chrome_build: global___ChromeBuildProto | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "cell_operator", b"cell_operator", "chrome_build", b"chrome_build", "last_checkin_msec", b"last_checkin_msec", "roaming", b"roaming", "sim_operator", b"sim_operator", "type", b"type", "user_number", b"user_number", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "cell_operator", b"cell_operator", "chrome_build", b"chrome_build", "last_checkin_msec", b"last_checkin_msec", "roaming", b"roaming", "sim_operator", b"sim_operator", "type", b"type", "user_number", b"user_number", ], ) -> None: ... global___AndroidCheckinProto = AndroidCheckinProto firebase-messaging-0.4.4/firebase_messaging/proto/checkin.proto000066400000000000000000000141711467555115100247410ustar00rootroot00000000000000// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Request and reply to the "checkin server" devices poll every few hours. syntax = "proto2"; option optimize_for = LITE_RUNTIME; package checkin_proto; import "android_checkin.proto"; // A concrete name/value pair sent to the device's Gservices database. message GservicesSetting { required bytes name = 1; required bytes value = 2; } // Devices send this every few hours to tell us how they're doing. message AndroidCheckinRequest { // IMEI (used by GSM phones) is sent and stored as 15 decimal // digits; the 15th is a check digit. optional string imei = 1; // IMEI, reported but not logged. // MEID (used by CDMA phones) is sent and stored as 14 hexadecimal // digits (no check digit). optional string meid = 10; // MEID, reported but not logged. // MAC address (used by non-phone devices). 12 hexadecimal digits; // no separators (eg "0016E6513AC2", not "00:16:E6:51:3A:C2"). repeated string mac_addr = 9; // MAC address, reported but not logged. // An array parallel to mac_addr, describing the type of interface. // Currently accepted values: "wifi", "ethernet", "bluetooth". If // not present, "wifi" is assumed. repeated string mac_addr_type = 19; // Serial number (a manufacturer-defined unique hardware // identifier). Alphanumeric, case-insensitive. optional string serial_number = 16; // Older CDMA networks use an ESN (8 hex digits) instead of an MEID. optional string esn = 17; // ESN, reported but not logged optional int64 id = 2; // Android device ID, not logged optional int64 logging_id = 7; // Pseudonymous logging ID for Sawmill optional string digest = 3; // Digest of device provisioning, not logged. optional string locale = 6; // Current locale in standard (xx_XX) format required AndroidCheckinProto checkin = 4; // DEPRECATED, see AndroidCheckinProto.requested_group optional string desired_build = 5; // Blob of data from the Market app to be passed to Market API server optional string market_checkin = 8; // SID cookies of any google accounts stored on the phone. Not logged. repeated string account_cookie = 11; // Time zone. Not currently logged. optional string time_zone = 12; // Security token used to validate the checkin request. // Required for android IDs issued to Froyo+ devices, not for legacy IDs. optional fixed64 security_token = 13; // Version of checkin protocol. // // There are currently two versions: // // - version field missing: android IDs are assigned based on // hardware identifiers. unsecured in the sense that you can // "unregister" someone's phone by sending a registration request // with their IMEI/MEID/MAC. // // - version=2: android IDs are assigned randomly. The device is // sent a security token that must be included in all future // checkins for that android id. // // - version=3: same as version 2, but the 'fragment' field is // provided, and the device understands incremental updates to the // gservices table (ie, only returning the keys whose values have // changed.) // // (version=1 was skipped to avoid confusion with the "missing" // version field that is effectively version 1.) optional int32 version = 14; // OTA certs accepted by device (base-64 SHA-1 of cert files). Not // logged. repeated string ota_cert = 15; // Honeycomb and newer devices send configuration data with their checkin. // optional DeviceConfigurationProto device_configuration = 18; // A single CheckinTask on the device may lead to multiple checkin // requests if there is too much log data to upload in a single // request. For version 3 and up, this field will be filled in with // the number of the request, starting with 0. optional int32 fragment = 20; // For devices supporting multiple users, the name of the current // profile (they all check in independently, just as if they were // multiple physical devices). This may not be set, even if the // device is using multiuser. (checkin.user_number should be set to // the ordinal of the user.) optional string user_name = 21; // For devices supporting multiple user profiles, the serial number // for the user checking in. Not logged. May not be set, even if // the device supportes multiuser. checkin.user_number is the // ordinal of the user (0, 1, 2, ...), which may be reused if users // are deleted and re-created. user_serial_number is never reused // (unless the device is wiped). optional int32 user_serial_number = 22; // NEXT TAG: 23 } // The response to the device. message AndroidCheckinResponse { required bool stats_ok = 1; // Whether statistics were recorded properly. optional int64 time_msec = 3; // Time of day from server (Java epoch). // repeated AndroidIntentProto intent = 2; // Provisioning is sent if the request included an obsolete digest. // // For version <= 2, 'digest' contains the digest that should be // sent back to the server on the next checkin, and 'setting' // contains the entire gservices table (which replaces the entire // current table on the device). // // for version >= 3, 'digest' will be absent. If 'settings_diff' // is false, then 'setting' contains the entire table, as in version // 2. If 'settings_diff' is true, then 'delete_setting' contains // the keys to delete, and 'setting' contains only keys to be added // or for which the value has changed. All other keys in the // current table should be left untouched. If 'settings_diff' is // absent, don't touch the existing gservices table. // optional string digest = 4; optional bool settings_diff = 9; repeated string delete_setting = 10; repeated GservicesSetting setting = 5; optional bool market_ok = 6; // If Market got the market_checkin data OK. optional fixed64 android_id = 7; // From the request, or newly assigned optional fixed64 security_token = 8; // The associated security token optional string version_info = 11; // NEXT TAG: 12 } firebase-messaging-0.4.4/firebase_messaging/proto/checkin_pb2.py000066400000000000000000000053531467555115100247730ustar00rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: checkin.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( b'\n\rcheckin.proto\x12\rcheckin_proto\x1a\x15\x61ndroid_checkin.proto"/\n\x10GservicesSetting\x12\x0c\n\x04name\x18\x01 \x02(\x0c\x12\r\n\x05value\x18\x02 \x02(\x0c"\xcb\x03\n\x15\x41ndroidCheckinRequest\x12\x0c\n\x04imei\x18\x01 \x01(\t\x12\x0c\n\x04meid\x18\n \x01(\t\x12\x10\n\x08mac_addr\x18\t \x03(\t\x12\x15\n\rmac_addr_type\x18\x13 \x03(\t\x12\x15\n\rserial_number\x18\x10 \x01(\t\x12\x0b\n\x03\x65sn\x18\x11 \x01(\t\x12\n\n\x02id\x18\x02 \x01(\x03\x12\x12\n\nlogging_id\x18\x07 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x03 \x01(\t\x12\x0e\n\x06locale\x18\x06 \x01(\t\x12\x33\n\x07\x63heckin\x18\x04 \x02(\x0b\x32".checkin_proto.AndroidCheckinProto\x12\x15\n\rdesired_build\x18\x05 \x01(\t\x12\x16\n\x0emarket_checkin\x18\x08 \x01(\t\x12\x16\n\x0e\x61\x63\x63ount_cookie\x18\x0b \x03(\t\x12\x11\n\ttime_zone\x18\x0c \x01(\t\x12\x16\n\x0esecurity_token\x18\r \x01(\x06\x12\x0f\n\x07version\x18\x0e \x01(\x05\x12\x10\n\x08ota_cert\x18\x0f \x03(\t\x12\x10\n\x08\x66ragment\x18\x14 \x01(\x05\x12\x11\n\tuser_name\x18\x15 \x01(\t\x12\x1a\n\x12user_serial_number\x18\x16 \x01(\x05"\x83\x02\n\x16\x41ndroidCheckinResponse\x12\x10\n\x08stats_ok\x18\x01 \x02(\x08\x12\x11\n\ttime_msec\x18\x03 \x01(\x03\x12\x0e\n\x06\x64igest\x18\x04 \x01(\t\x12\x15\n\rsettings_diff\x18\t \x01(\x08\x12\x16\n\x0e\x64\x65lete_setting\x18\n \x03(\t\x12\x30\n\x07setting\x18\x05 \x03(\x0b\x32\x1f.checkin_proto.GservicesSetting\x12\x11\n\tmarket_ok\x18\x06 \x01(\x08\x12\x12\n\nandroid_id\x18\x07 \x01(\x06\x12\x16\n\x0esecurity_token\x18\x08 \x01(\x06\x12\x14\n\x0cversion_info\x18\x0b \x01(\tB\x02H\x03' ) _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "checkin_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: _globals["DESCRIPTOR"]._options = None _globals["DESCRIPTOR"]._serialized_options = b"H\003" _globals["_GSERVICESSETTING"]._serialized_start = 55 _globals["_GSERVICESSETTING"]._serialized_end = 102 _globals["_ANDROIDCHECKINREQUEST"]._serialized_start = 105 _globals["_ANDROIDCHECKINREQUEST"]._serialized_end = 564 _globals["_ANDROIDCHECKINRESPONSE"]._serialized_start = 567 _globals["_ANDROIDCHECKINRESPONSE"]._serialized_end = 826 # @@protoc_insertion_point(module_scope) firebase-messaging-0.4.4/firebase_messaging/proto/checkin_pb2.pyi000066400000000000000000000344421467555115100251450ustar00rootroot00000000000000""" @generated by mypy-protobuf. Do not edit manually! isort:skip_file Copyright 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. Request and reply to the "checkin server" devices poll every few hours. """ from . import android_checkin_pb2 import builtins import collections.abc import google.protobuf.descriptor import google.protobuf.internal.containers import google.protobuf.message import sys if sys.version_info >= (3, 8): import typing as typing_extensions else: import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor @typing_extensions.final class GservicesSetting(google.protobuf.message.Message): """A concrete name/value pair sent to the device's Gservices database.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor NAME_FIELD_NUMBER: builtins.int VALUE_FIELD_NUMBER: builtins.int name: builtins.bytes value: builtins.bytes def __init__( self, *, name: builtins.bytes | None = ..., value: builtins.bytes | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"] ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"] ) -> None: ... global___GservicesSetting = GservicesSetting @typing_extensions.final class AndroidCheckinRequest(google.protobuf.message.Message): """Devices send this every few hours to tell us how they're doing.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor IMEI_FIELD_NUMBER: builtins.int MEID_FIELD_NUMBER: builtins.int MAC_ADDR_FIELD_NUMBER: builtins.int MAC_ADDR_TYPE_FIELD_NUMBER: builtins.int SERIAL_NUMBER_FIELD_NUMBER: builtins.int ESN_FIELD_NUMBER: builtins.int ID_FIELD_NUMBER: builtins.int LOGGING_ID_FIELD_NUMBER: builtins.int DIGEST_FIELD_NUMBER: builtins.int LOCALE_FIELD_NUMBER: builtins.int CHECKIN_FIELD_NUMBER: builtins.int DESIRED_BUILD_FIELD_NUMBER: builtins.int MARKET_CHECKIN_FIELD_NUMBER: builtins.int ACCOUNT_COOKIE_FIELD_NUMBER: builtins.int TIME_ZONE_FIELD_NUMBER: builtins.int SECURITY_TOKEN_FIELD_NUMBER: builtins.int VERSION_FIELD_NUMBER: builtins.int OTA_CERT_FIELD_NUMBER: builtins.int FRAGMENT_FIELD_NUMBER: builtins.int USER_NAME_FIELD_NUMBER: builtins.int USER_SERIAL_NUMBER_FIELD_NUMBER: builtins.int imei: builtins.str """IMEI (used by GSM phones) is sent and stored as 15 decimal digits; the 15th is a check digit. IMEI, reported but not logged. """ meid: builtins.str """MEID (used by CDMA phones) is sent and stored as 14 hexadecimal digits (no check digit). MEID, reported but not logged. """ @property def mac_addr( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: """MAC address (used by non-phone devices). 12 hexadecimal digits; no separators (eg "0016E6513AC2", not "00:16:E6:51:3A:C2"). MAC address, reported but not logged. """ @property def mac_addr_type( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: """An array parallel to mac_addr, describing the type of interface. Currently accepted values: "wifi", "ethernet", "bluetooth". If not present, "wifi" is assumed. """ serial_number: builtins.str """Serial number (a manufacturer-defined unique hardware identifier). Alphanumeric, case-insensitive. """ esn: builtins.str """Older CDMA networks use an ESN (8 hex digits) instead of an MEID. ESN, reported but not logged """ id: builtins.int """Android device ID, not logged""" logging_id: builtins.int """Pseudonymous logging ID for Sawmill""" digest: builtins.str """Digest of device provisioning, not logged.""" locale: builtins.str """Current locale in standard (xx_XX) format""" @property def checkin(self) -> android_checkin_pb2.AndroidCheckinProto: ... desired_build: builtins.str """DEPRECATED, see AndroidCheckinProto.requested_group""" market_checkin: builtins.str """Blob of data from the Market app to be passed to Market API server""" @property def account_cookie( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: """SID cookies of any google accounts stored on the phone. Not logged.""" time_zone: builtins.str """Time zone. Not currently logged.""" security_token: builtins.int """Security token used to validate the checkin request. Required for android IDs issued to Froyo+ devices, not for legacy IDs. """ version: builtins.int """Version of checkin protocol. There are currently two versions: - version field missing: android IDs are assigned based on hardware identifiers. unsecured in the sense that you can "unregister" someone's phone by sending a registration request with their IMEI/MEID/MAC. - version=2: android IDs are assigned randomly. The device is sent a security token that must be included in all future checkins for that android id. - version=3: same as version 2, but the 'fragment' field is provided, and the device understands incremental updates to the gservices table (ie, only returning the keys whose values have changed.) (version=1 was skipped to avoid confusion with the "missing" version field that is effectively version 1.) """ @property def ota_cert( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: """OTA certs accepted by device (base-64 SHA-1 of cert files). Not logged. """ fragment: builtins.int """Honeycomb and newer devices send configuration data with their checkin. optional DeviceConfigurationProto device_configuration = 18; A single CheckinTask on the device may lead to multiple checkin requests if there is too much log data to upload in a single request. For version 3 and up, this field will be filled in with the number of the request, starting with 0. """ user_name: builtins.str """For devices supporting multiple users, the name of the current profile (they all check in independently, just as if they were multiple physical devices). This may not be set, even if the device is using multiuser. (checkin.user_number should be set to the ordinal of the user.) """ user_serial_number: builtins.int """For devices supporting multiple user profiles, the serial number for the user checking in. Not logged. May not be set, even if the device supportes multiuser. checkin.user_number is the ordinal of the user (0, 1, 2, ...), which may be reused if users are deleted and re-created. user_serial_number is never reused (unless the device is wiped). """ def __init__( self, *, imei: builtins.str | None = ..., meid: builtins.str | None = ..., mac_addr: collections.abc.Iterable[builtins.str] | None = ..., mac_addr_type: collections.abc.Iterable[builtins.str] | None = ..., serial_number: builtins.str | None = ..., esn: builtins.str | None = ..., id: builtins.int | None = ..., logging_id: builtins.int | None = ..., digest: builtins.str | None = ..., locale: builtins.str | None = ..., checkin: android_checkin_pb2.AndroidCheckinProto | None = ..., desired_build: builtins.str | None = ..., market_checkin: builtins.str | None = ..., account_cookie: collections.abc.Iterable[builtins.str] | None = ..., time_zone: builtins.str | None = ..., security_token: builtins.int | None = ..., version: builtins.int | None = ..., ota_cert: collections.abc.Iterable[builtins.str] | None = ..., fragment: builtins.int | None = ..., user_name: builtins.str | None = ..., user_serial_number: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "checkin", b"checkin", "desired_build", b"desired_build", "digest", b"digest", "esn", b"esn", "fragment", b"fragment", "id", b"id", "imei", b"imei", "locale", b"locale", "logging_id", b"logging_id", "market_checkin", b"market_checkin", "meid", b"meid", "security_token", b"security_token", "serial_number", b"serial_number", "time_zone", b"time_zone", "user_name", b"user_name", "user_serial_number", b"user_serial_number", "version", b"version", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "account_cookie", b"account_cookie", "checkin", b"checkin", "desired_build", b"desired_build", "digest", b"digest", "esn", b"esn", "fragment", b"fragment", "id", b"id", "imei", b"imei", "locale", b"locale", "logging_id", b"logging_id", "mac_addr", b"mac_addr", "mac_addr_type", b"mac_addr_type", "market_checkin", b"market_checkin", "meid", b"meid", "ota_cert", b"ota_cert", "security_token", b"security_token", "serial_number", b"serial_number", "time_zone", b"time_zone", "user_name", b"user_name", "user_serial_number", b"user_serial_number", "version", b"version", ], ) -> None: ... global___AndroidCheckinRequest = AndroidCheckinRequest @typing_extensions.final class AndroidCheckinResponse(google.protobuf.message.Message): """The response to the device.""" DESCRIPTOR: google.protobuf.descriptor.Descriptor STATS_OK_FIELD_NUMBER: builtins.int TIME_MSEC_FIELD_NUMBER: builtins.int DIGEST_FIELD_NUMBER: builtins.int SETTINGS_DIFF_FIELD_NUMBER: builtins.int DELETE_SETTING_FIELD_NUMBER: builtins.int SETTING_FIELD_NUMBER: builtins.int MARKET_OK_FIELD_NUMBER: builtins.int ANDROID_ID_FIELD_NUMBER: builtins.int SECURITY_TOKEN_FIELD_NUMBER: builtins.int VERSION_INFO_FIELD_NUMBER: builtins.int stats_ok: builtins.bool """Whether statistics were recorded properly.""" time_msec: builtins.int """Time of day from server (Java epoch).""" digest: builtins.str """repeated AndroidIntentProto intent = 2; Provisioning is sent if the request included an obsolete digest. For version <= 2, 'digest' contains the digest that should be sent back to the server on the next checkin, and 'setting' contains the entire gservices table (which replaces the entire current table on the device). for version >= 3, 'digest' will be absent. If 'settings_diff' is false, then 'setting' contains the entire table, as in version 2. If 'settings_diff' is true, then 'delete_setting' contains the keys to delete, and 'setting' contains only keys to be added or for which the value has changed. All other keys in the current table should be left untouched. If 'settings_diff' is absent, don't touch the existing gservices table. """ settings_diff: builtins.bool @property def delete_setting( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ builtins.str ]: ... @property def setting( self, ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[ global___GservicesSetting ]: ... market_ok: builtins.bool """If Market got the market_checkin data OK.""" android_id: builtins.int """From the request, or newly assigned""" security_token: builtins.int """The associated security token""" version_info: builtins.str """NEXT TAG: 12""" def __init__( self, *, stats_ok: builtins.bool | None = ..., time_msec: builtins.int | None = ..., digest: builtins.str | None = ..., settings_diff: builtins.bool | None = ..., delete_setting: collections.abc.Iterable[builtins.str] | None = ..., setting: collections.abc.Iterable[global___GservicesSetting] | None = ..., market_ok: builtins.bool | None = ..., android_id: builtins.int | None = ..., security_token: builtins.int | None = ..., version_info: builtins.str | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "android_id", b"android_id", "digest", b"digest", "market_ok", b"market_ok", "security_token", b"security_token", "settings_diff", b"settings_diff", "stats_ok", b"stats_ok", "time_msec", b"time_msec", "version_info", b"version_info", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "android_id", b"android_id", "delete_setting", b"delete_setting", "digest", b"digest", "market_ok", b"market_ok", "security_token", b"security_token", "setting", b"setting", "settings_diff", b"settings_diff", "stats_ok", b"stats_ok", "time_msec", b"time_msec", "version_info", b"version_info", ], ) -> None: ... global___AndroidCheckinResponse = AndroidCheckinResponse firebase-messaging-0.4.4/firebase_messaging/proto/mcs.proto000066400000000000000000000201111467555115100241060ustar00rootroot00000000000000// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // MCS protocol for communication between Chrome client and Mobile Connection // Server . syntax = "proto2"; option optimize_for = LITE_RUNTIME; package mcs_proto; /* Common fields/comments: stream_id: no longer sent by server, each side keeps a counter last_stream_id_received: sent only if a packet was received since last time a last_stream was sent status: new bitmask including the 'idle' as bit 0. */ /** TAG: 0 */ message HeartbeatPing { optional int32 stream_id = 1; optional int32 last_stream_id_received = 2; optional int64 status = 3; } /** TAG: 1 */ message HeartbeatAck { optional int32 stream_id = 1; optional int32 last_stream_id_received = 2; optional int64 status = 3; } message ErrorInfo { required int32 code = 1; optional string message = 2; optional string type = 3; optional Extension extension = 4; } // MobileSettings class. // "u:f", "u:b", "u:s" - multi user devices reporting foreground, background // and stopped users. // hbping: heatbeat ping interval // rmq2v: include explicit stream IDs message Setting { required string name = 1; required string value = 2; } message HeartbeatStat { required string ip = 1; required bool timeout = 2; required int32 interval_ms = 3; } message HeartbeatConfig { optional bool upload_stat = 1; optional string ip = 2; optional int32 interval_ms = 3; } // ClientEvents are used to inform the server of failed and successful // connections. message ClientEvent { enum Type { UNKNOWN = 0; // Count of discarded events if the buffer filled up and was trimmed. DISCARDED_EVENTS = 1; // Failed connection event: the connection failed to be established or we // had a login error. FAILED_CONNECTION = 2; // Successful connection event: information about the last successful // connection, including the time at which it was established. SUCCESSFUL_CONNECTION = 3; } // Common fields [1-99] optional Type type = 1; // Fields for DISCARDED_EVENTS messages [100-199] optional uint32 number_discarded_events = 100; // Fields for FAILED_CONNECTION and SUCCESSFUL_CONNECTION messages [200-299] // Network type is a value in net::NetworkChangeNotifier::ConnectionType. optional int32 network_type = 200; // Reserved for network_port. reserved 201; optional uint64 time_connection_started_ms = 202; optional uint64 time_connection_ended_ms = 203; // Error code should be a net::Error value. optional int32 error_code = 204; // Fields for SUCCESSFUL_CONNECTION messages [300-399] optional uint64 time_connection_established_ms = 300; } /** TAG: 2 */ message LoginRequest { enum AuthService { ANDROID_ID = 2; } required string id = 1; // Must be present ( proto required ), may be empty // string. // mcs.android.com. required string domain = 2; // Decimal android ID required string user = 3; required string resource = 4; // Secret required string auth_token = 5; // Format is: android-HEX_DEVICE_ID // The user is the decimal value. optional string device_id = 6; // RMQ1 - no longer used optional int64 last_rmq_id = 7; repeated Setting setting = 8; //optional int32 compress = 9; repeated string received_persistent_id = 10; // Replaced by "rmq2v" setting // optional bool include_stream_ids = 11; optional bool adaptive_heartbeat = 12; optional HeartbeatStat heartbeat_stat = 13; // Must be true. optional bool use_rmq2 = 14; optional int64 account_id = 15; // ANDROID_ID = 2 optional AuthService auth_service = 16; optional int32 network_type = 17; optional int64 status = 18; // 19, 20, and 21 are not currently populated by Chrome. reserved 19, 20, 21; // Events recorded on the client after the last successful connection. repeated ClientEvent client_event = 22; } /** * TAG: 3 */ message LoginResponse { required string id = 1; // Not used. optional string jid = 2; // Null if login was ok. optional ErrorInfo error = 3; repeated Setting setting = 4; optional int32 stream_id = 5; // Should be "1" optional int32 last_stream_id_received = 6; optional HeartbeatConfig heartbeat_config = 7; // used by the client to synchronize with the server timestamp. optional int64 server_timestamp = 8; } message StreamErrorStanza { required string type = 1; optional string text = 2; } /** * TAG: 4 */ message Close { } message Extension { // 12: SelectiveAck // 13: StreamAck required int32 id = 1; required bytes data = 2; } /** * TAG: 7 * IqRequest must contain a single extension. IqResponse may contain 0 or 1 * extensions. */ message IqStanza { enum IqType { GET = 0; SET = 1; RESULT = 2; IQ_ERROR = 3; } optional int64 rmq_id = 1; required IqType type = 2; required string id = 3; optional string from = 4; optional string to = 5; optional ErrorInfo error = 6; // Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id) optional Extension extension = 7; optional string persistent_id = 8; optional int32 stream_id = 9; optional int32 last_stream_id_received = 10; optional int64 account_id = 11; optional int64 status = 12; } message AppData { required string key = 1; required string value = 2; } /** * TAG: 8 */ message DataMessageStanza { // Not used. // optional int64 rmq_id = 1; // This is the message ID, set by client, DMP.9 (message_id) optional string id = 2; // Project ID of the sender, DMP.1 required string from = 3; // Part of DMRequest - also the key in DataMessageProto. optional string to = 4; // Package name. DMP.2 required string category = 5; // The collapsed key, DMP.3 optional string token = 6; // User data + GOOGLE. prefixed special entries, DMP.4 repeated AppData app_data = 7; // Not used. optional bool from_trusted_server = 8; // Part of the ACK protocol, returned in DataMessageResponse on server side. // It's part of the key of DMP. optional string persistent_id = 9; // In-stream ack. Increments on each message sent - a bit redundant // Not used in DMP/DMR. optional int32 stream_id = 10; optional int32 last_stream_id_received = 11; // Not used. // optional string permission = 12; // Sent by the device shortly after registration. optional string reg_id = 13; // Not used. // optional string pkg_signature = 14; // Not used. // optional string client_id = 15; // serial number of the target user, DMP.8 // It is the 'serial number' according to user manager. optional int64 device_user_id = 16; // Time to live, in seconds. optional int32 ttl = 17; // Timestamp ( according to client ) when message was sent by app, in seconds optional int64 sent = 18; // How long has the message been queued before the flush, in seconds. // This is needed to account for the time difference between server and // client: server should adjust 'sent' based on its 'receive' time. optional int32 queued = 19; optional int64 status = 20; // Optional field containing the binary payload of the message. optional bytes raw_data = 21; // Not used. // The maximum delay of the message, in seconds. // optional int32 max_delay = 22; // Not used. // How long the message was delayed before it was sent, in seconds. // optional int32 actual_delay = 23; // If set the server requests immediate ack. Used for important messages and // for testing. optional bool immediate_ack = 24; // Not used. // Enables message receipts from MCS/GCM back to CCS clients // optional bool delivery_receipt_requested = 25; } /** Included in IQ with ID 13, sent from client or server after 10 unconfirmed messages. */ message StreamAck { // No last_streamid_received required. This is included within an IqStanza, // which includes the last_stream_id_received. } /** Included in IQ sent after LoginResponse from server with ID 12. */ message SelectiveAck { repeated string id = 1; } firebase-messaging-0.4.4/firebase_messaging/proto/mcs_pb2.py000066400000000000000000000170651467555115100241540ustar00rootroot00000000000000# Generated by the protocol buffer compiler. DO NOT EDIT! # source: mcs.proto """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( b'\n\tmcs.proto\x12\tmcs_proto"S\n\rHeartbeatPing\x12\x11\n\tstream_id\x18\x01 \x01(\x05\x12\x1f\n\x17last_stream_id_received\x18\x02 \x01(\x05\x12\x0e\n\x06status\x18\x03 \x01(\x03"R\n\x0cHeartbeatAck\x12\x11\n\tstream_id\x18\x01 \x01(\x05\x12\x1f\n\x17last_stream_id_received\x18\x02 \x01(\x05\x12\x0e\n\x06status\x18\x03 \x01(\x03"a\n\tErrorInfo\x12\x0c\n\x04\x63ode\x18\x01 \x02(\x05\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\t\x12\'\n\textension\x18\x04 \x01(\x0b\x32\x14.mcs_proto.Extension"&\n\x07Setting\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x02(\t"A\n\rHeartbeatStat\x12\n\n\x02ip\x18\x01 \x02(\t\x12\x0f\n\x07timeout\x18\x02 \x02(\x08\x12\x13\n\x0binterval_ms\x18\x03 \x02(\x05"G\n\x0fHeartbeatConfig\x12\x13\n\x0bupload_stat\x18\x01 \x01(\x08\x12\n\n\x02ip\x18\x02 \x01(\t\x12\x13\n\x0binterval_ms\x18\x03 \x01(\x05"\xdb\x02\n\x0b\x43lientEvent\x12)\n\x04type\x18\x01 \x01(\x0e\x32\x1b.mcs_proto.ClientEvent.Type\x12\x1f\n\x17number_discarded_events\x18\x64 \x01(\r\x12\x15\n\x0cnetwork_type\x18\xc8\x01 \x01(\x05\x12#\n\x1atime_connection_started_ms\x18\xca\x01 \x01(\x04\x12!\n\x18time_connection_ended_ms\x18\xcb\x01 \x01(\x04\x12\x13\n\nerror_code\x18\xcc\x01 \x01(\x05\x12\'\n\x1etime_connection_established_ms\x18\xac\x02 \x01(\x04"[\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x14\n\x10\x44ISCARDED_EVENTS\x10\x01\x12\x15\n\x11\x46\x41ILED_CONNECTION\x10\x02\x12\x19\n\x15SUCCESSFUL_CONNECTION\x10\x03J\x06\x08\xc9\x01\x10\xca\x01"\xff\x03\n\x0cLoginRequest\x12\n\n\x02id\x18\x01 \x02(\t\x12\x0e\n\x06\x64omain\x18\x02 \x02(\t\x12\x0c\n\x04user\x18\x03 \x02(\t\x12\x10\n\x08resource\x18\x04 \x02(\t\x12\x12\n\nauth_token\x18\x05 \x02(\t\x12\x11\n\tdevice_id\x18\x06 \x01(\t\x12\x13\n\x0blast_rmq_id\x18\x07 \x01(\x03\x12#\n\x07setting\x18\x08 \x03(\x0b\x32\x12.mcs_proto.Setting\x12\x1e\n\x16received_persistent_id\x18\n \x03(\t\x12\x1a\n\x12\x61\x64\x61ptive_heartbeat\x18\x0c \x01(\x08\x12\x30\n\x0eheartbeat_stat\x18\r \x01(\x0b\x32\x18.mcs_proto.HeartbeatStat\x12\x10\n\x08use_rmq2\x18\x0e \x01(\x08\x12\x12\n\naccount_id\x18\x0f \x01(\x03\x12\x39\n\x0c\x61uth_service\x18\x10 \x01(\x0e\x32#.mcs_proto.LoginRequest.AuthService\x12\x14\n\x0cnetwork_type\x18\x11 \x01(\x05\x12\x0e\n\x06status\x18\x12 \x01(\x03\x12,\n\x0c\x63lient_event\x18\x16 \x03(\x0b\x32\x16.mcs_proto.ClientEvent"\x1d\n\x0b\x41uthService\x12\x0e\n\nANDROID_ID\x10\x02J\x04\x08\x13\x10\x14J\x04\x08\x14\x10\x15J\x04\x08\x15\x10\x16"\xf6\x01\n\rLoginResponse\x12\n\n\x02id\x18\x01 \x02(\t\x12\x0b\n\x03jid\x18\x02 \x01(\t\x12#\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x14.mcs_proto.ErrorInfo\x12#\n\x07setting\x18\x04 \x03(\x0b\x32\x12.mcs_proto.Setting\x12\x11\n\tstream_id\x18\x05 \x01(\x05\x12\x1f\n\x17last_stream_id_received\x18\x06 \x01(\x05\x12\x34\n\x10heartbeat_config\x18\x07 \x01(\x0b\x32\x1a.mcs_proto.HeartbeatConfig\x12\x18\n\x10server_timestamp\x18\x08 \x01(\x03"/\n\x11StreamErrorStanza\x12\x0c\n\x04type\x18\x01 \x02(\t\x12\x0c\n\x04text\x18\x02 \x01(\t"\x07\n\x05\x43lose"%\n\tExtension\x12\n\n\x02id\x18\x01 \x02(\x05\x12\x0c\n\x04\x64\x61ta\x18\x02 \x02(\x0c"\xdd\x02\n\x08IqStanza\x12\x0e\n\x06rmq_id\x18\x01 \x01(\x03\x12(\n\x04type\x18\x02 \x02(\x0e\x32\x1a.mcs_proto.IqStanza.IqType\x12\n\n\x02id\x18\x03 \x02(\t\x12\x0c\n\x04\x66rom\x18\x04 \x01(\t\x12\n\n\x02to\x18\x05 \x01(\t\x12#\n\x05\x65rror\x18\x06 \x01(\x0b\x32\x14.mcs_proto.ErrorInfo\x12\'\n\textension\x18\x07 \x01(\x0b\x32\x14.mcs_proto.Extension\x12\x15\n\rpersistent_id\x18\x08 \x01(\t\x12\x11\n\tstream_id\x18\t \x01(\x05\x12\x1f\n\x17last_stream_id_received\x18\n \x01(\x05\x12\x12\n\naccount_id\x18\x0b \x01(\x03\x12\x0e\n\x06status\x18\x0c \x01(\x03"4\n\x06IqType\x12\x07\n\x03GET\x10\x00\x12\x07\n\x03SET\x10\x01\x12\n\n\x06RESULT\x10\x02\x12\x0c\n\x08IQ_ERROR\x10\x03"%\n\x07\x41ppData\x12\x0b\n\x03key\x18\x01 \x02(\t\x12\r\n\x05value\x18\x02 \x02(\t"\xf4\x02\n\x11\x44\x61taMessageStanza\x12\n\n\x02id\x18\x02 \x01(\t\x12\x0c\n\x04\x66rom\x18\x03 \x02(\t\x12\n\n\x02to\x18\x04 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x05 \x02(\t\x12\r\n\x05token\x18\x06 \x01(\t\x12$\n\x08\x61pp_data\x18\x07 \x03(\x0b\x32\x12.mcs_proto.AppData\x12\x1b\n\x13\x66rom_trusted_server\x18\x08 \x01(\x08\x12\x15\n\rpersistent_id\x18\t \x01(\t\x12\x11\n\tstream_id\x18\n \x01(\x05\x12\x1f\n\x17last_stream_id_received\x18\x0b \x01(\x05\x12\x0e\n\x06reg_id\x18\r \x01(\t\x12\x16\n\x0e\x64\x65vice_user_id\x18\x10 \x01(\x03\x12\x0b\n\x03ttl\x18\x11 \x01(\x05\x12\x0c\n\x04sent\x18\x12 \x01(\x03\x12\x0e\n\x06queued\x18\x13 \x01(\x05\x12\x0e\n\x06status\x18\x14 \x01(\x03\x12\x10\n\x08raw_data\x18\x15 \x01(\x0c\x12\x15\n\rimmediate_ack\x18\x18 \x01(\x08"\x0b\n\tStreamAck"\x1a\n\x0cSelectiveAck\x12\n\n\x02id\x18\x01 \x03(\tB\x02H\x03' ) _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "mcs_pb2", _globals) if _descriptor._USE_C_DESCRIPTORS == False: _globals["DESCRIPTOR"]._options = None _globals["DESCRIPTOR"]._serialized_options = b"H\003" _globals["_HEARTBEATPING"]._serialized_start = 24 _globals["_HEARTBEATPING"]._serialized_end = 107 _globals["_HEARTBEATACK"]._serialized_start = 109 _globals["_HEARTBEATACK"]._serialized_end = 191 _globals["_ERRORINFO"]._serialized_start = 193 _globals["_ERRORINFO"]._serialized_end = 290 _globals["_SETTING"]._serialized_start = 292 _globals["_SETTING"]._serialized_end = 330 _globals["_HEARTBEATSTAT"]._serialized_start = 332 _globals["_HEARTBEATSTAT"]._serialized_end = 397 _globals["_HEARTBEATCONFIG"]._serialized_start = 399 _globals["_HEARTBEATCONFIG"]._serialized_end = 470 _globals["_CLIENTEVENT"]._serialized_start = 473 _globals["_CLIENTEVENT"]._serialized_end = 820 _globals["_CLIENTEVENT_TYPE"]._serialized_start = 721 _globals["_CLIENTEVENT_TYPE"]._serialized_end = 812 _globals["_LOGINREQUEST"]._serialized_start = 823 _globals["_LOGINREQUEST"]._serialized_end = 1334 _globals["_LOGINREQUEST_AUTHSERVICE"]._serialized_start = 1287 _globals["_LOGINREQUEST_AUTHSERVICE"]._serialized_end = 1316 _globals["_LOGINRESPONSE"]._serialized_start = 1337 _globals["_LOGINRESPONSE"]._serialized_end = 1583 _globals["_STREAMERRORSTANZA"]._serialized_start = 1585 _globals["_STREAMERRORSTANZA"]._serialized_end = 1632 _globals["_CLOSE"]._serialized_start = 1634 _globals["_CLOSE"]._serialized_end = 1641 _globals["_EXTENSION"]._serialized_start = 1643 _globals["_EXTENSION"]._serialized_end = 1680 _globals["_IQSTANZA"]._serialized_start = 1683 _globals["_IQSTANZA"]._serialized_end = 2032 _globals["_IQSTANZA_IQTYPE"]._serialized_start = 1980 _globals["_IQSTANZA_IQTYPE"]._serialized_end = 2032 _globals["_APPDATA"]._serialized_start = 2034 _globals["_APPDATA"]._serialized_end = 2071 _globals["_DATAMESSAGESTANZA"]._serialized_start = 2074 _globals["_DATAMESSAGESTANZA"]._serialized_end = 2446 _globals["_STREAMACK"]._serialized_start = 2448 _globals["_STREAMACK"]._serialized_end = 2459 _globals["_SELECTIVEACK"]._serialized_start = 2461 _globals["_SELECTIVEACK"]._serialized_end = 2487 # @@protoc_insertion_point(module_scope) firebase-messaging-0.4.4/firebase_messaging/proto/mcs_pb2.pyi000066400000000000000000001022471467555115100243220ustar00rootroot00000000000000""" @generated by mypy-protobuf. Do not edit manually! isort:skip_file Copyright 2013 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. MCS protocol for communication between Chrome client and Mobile Connection Server . """ import builtins import collections.abc import google.protobuf.descriptor import google.protobuf.internal.containers import google.protobuf.internal.enum_type_wrapper import google.protobuf.message import sys import typing if sys.version_info >= (3, 10): import typing as typing_extensions else: import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor @typing_extensions.final class HeartbeatPing(google.protobuf.message.Message): """ Common fields/comments: stream_id: no longer sent by server, each side keeps a counter last_stream_id_received: sent only if a packet was received since last time a last_stream was sent status: new bitmask including the 'idle' as bit 0. * TAG: 0 """ DESCRIPTOR: google.protobuf.descriptor.Descriptor STREAM_ID_FIELD_NUMBER: builtins.int LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int STATUS_FIELD_NUMBER: builtins.int stream_id: builtins.int last_stream_id_received: builtins.int status: builtins.int def __init__( self, *, stream_id: builtins.int | None = ..., last_stream_id_received: builtins.int | None = ..., status: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id", ], ) -> None: ... global___HeartbeatPing = HeartbeatPing @typing_extensions.final class HeartbeatAck(google.protobuf.message.Message): """* TAG: 1 """ DESCRIPTOR: google.protobuf.descriptor.Descriptor STREAM_ID_FIELD_NUMBER: builtins.int LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int STATUS_FIELD_NUMBER: builtins.int stream_id: builtins.int last_stream_id_received: builtins.int status: builtins.int def __init__( self, *, stream_id: builtins.int | None = ..., last_stream_id_received: builtins.int | None = ..., status: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "last_stream_id_received", b"last_stream_id_received", "status", b"status", "stream_id", b"stream_id", ], ) -> None: ... global___HeartbeatAck = HeartbeatAck @typing_extensions.final class ErrorInfo(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor CODE_FIELD_NUMBER: builtins.int MESSAGE_FIELD_NUMBER: builtins.int TYPE_FIELD_NUMBER: builtins.int EXTENSION_FIELD_NUMBER: builtins.int code: builtins.int message: builtins.str type: builtins.str @property def extension(self) -> global___Extension: ... def __init__( self, *, code: builtins.int | None = ..., message: builtins.str | None = ..., type: builtins.str | None = ..., extension: global___Extension | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "code", b"code", "extension", b"extension", "message", b"message", "type", b"type", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "code", b"code", "extension", b"extension", "message", b"message", "type", b"type", ], ) -> None: ... global___ErrorInfo = ErrorInfo @typing_extensions.final class Setting(google.protobuf.message.Message): """MobileSettings class. "u:f", "u:b", "u:s" - multi user devices reporting foreground, background and stopped users. hbping: heatbeat ping interval rmq2v: include explicit stream IDs """ DESCRIPTOR: google.protobuf.descriptor.Descriptor NAME_FIELD_NUMBER: builtins.int VALUE_FIELD_NUMBER: builtins.int name: builtins.str value: builtins.str def __init__( self, *, name: builtins.str | None = ..., value: builtins.str | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"] ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal["name", b"name", "value", b"value"] ) -> None: ... global___Setting = Setting @typing_extensions.final class HeartbeatStat(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor IP_FIELD_NUMBER: builtins.int TIMEOUT_FIELD_NUMBER: builtins.int INTERVAL_MS_FIELD_NUMBER: builtins.int ip: builtins.str timeout: builtins.bool interval_ms: builtins.int def __init__( self, *, ip: builtins.str | None = ..., timeout: builtins.bool | None = ..., interval_ms: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "interval_ms", b"interval_ms", "ip", b"ip", "timeout", b"timeout" ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "interval_ms", b"interval_ms", "ip", b"ip", "timeout", b"timeout" ], ) -> None: ... global___HeartbeatStat = HeartbeatStat @typing_extensions.final class HeartbeatConfig(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor UPLOAD_STAT_FIELD_NUMBER: builtins.int IP_FIELD_NUMBER: builtins.int INTERVAL_MS_FIELD_NUMBER: builtins.int upload_stat: builtins.bool ip: builtins.str interval_ms: builtins.int def __init__( self, *, upload_stat: builtins.bool | None = ..., ip: builtins.str | None = ..., interval_ms: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "interval_ms", b"interval_ms", "ip", b"ip", "upload_stat", b"upload_stat" ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "interval_ms", b"interval_ms", "ip", b"ip", "upload_stat", b"upload_stat" ], ) -> None: ... global___HeartbeatConfig = HeartbeatConfig @typing_extensions.final class ClientEvent(google.protobuf.message.Message): """ClientEvents are used to inform the server of failed and successful connections. """ DESCRIPTOR: google.protobuf.descriptor.Descriptor class _Type: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _TypeEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ ClientEvent._Type.ValueType ], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor UNKNOWN: ClientEvent._Type.ValueType # 0 DISCARDED_EVENTS: ClientEvent._Type.ValueType # 1 """Count of discarded events if the buffer filled up and was trimmed.""" FAILED_CONNECTION: ClientEvent._Type.ValueType # 2 """Failed connection event: the connection failed to be established or we had a login error. """ SUCCESSFUL_CONNECTION: ClientEvent._Type.ValueType # 3 """Successful connection event: information about the last successful connection, including the time at which it was established. """ class Type(_Type, metaclass=_TypeEnumTypeWrapper): ... UNKNOWN: ClientEvent.Type.ValueType # 0 DISCARDED_EVENTS: ClientEvent.Type.ValueType # 1 """Count of discarded events if the buffer filled up and was trimmed.""" FAILED_CONNECTION: ClientEvent.Type.ValueType # 2 """Failed connection event: the connection failed to be established or we had a login error. """ SUCCESSFUL_CONNECTION: ClientEvent.Type.ValueType # 3 """Successful connection event: information about the last successful connection, including the time at which it was established. """ TYPE_FIELD_NUMBER: builtins.int NUMBER_DISCARDED_EVENTS_FIELD_NUMBER: builtins.int NETWORK_TYPE_FIELD_NUMBER: builtins.int TIME_CONNECTION_STARTED_MS_FIELD_NUMBER: builtins.int TIME_CONNECTION_ENDED_MS_FIELD_NUMBER: builtins.int ERROR_CODE_FIELD_NUMBER: builtins.int TIME_CONNECTION_ESTABLISHED_MS_FIELD_NUMBER: builtins.int type: global___ClientEvent.Type.ValueType """Common fields [1-99]""" number_discarded_events: builtins.int """Fields for DISCARDED_EVENTS messages [100-199]""" network_type: builtins.int """Fields for FAILED_CONNECTION and SUCCESSFUL_CONNECTION messages [200-299] Network type is a value in net::NetworkChangeNotifier::ConnectionType. """ time_connection_started_ms: builtins.int time_connection_ended_ms: builtins.int error_code: builtins.int """Error code should be a net::Error value.""" time_connection_established_ms: builtins.int """Fields for SUCCESSFUL_CONNECTION messages [300-399]""" def __init__( self, *, type: global___ClientEvent.Type.ValueType | None = ..., number_discarded_events: builtins.int | None = ..., network_type: builtins.int | None = ..., time_connection_started_ms: builtins.int | None = ..., time_connection_ended_ms: builtins.int | None = ..., error_code: builtins.int | None = ..., time_connection_established_ms: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "error_code", b"error_code", "network_type", b"network_type", "number_discarded_events", b"number_discarded_events", "time_connection_ended_ms", b"time_connection_ended_ms", "time_connection_established_ms", b"time_connection_established_ms", "time_connection_started_ms", b"time_connection_started_ms", "type", b"type", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "error_code", b"error_code", "network_type", b"network_type", "number_discarded_events", b"number_discarded_events", "time_connection_ended_ms", b"time_connection_ended_ms", "time_connection_established_ms", b"time_connection_established_ms", "time_connection_started_ms", b"time_connection_started_ms", "type", b"type", ], ) -> None: ... global___ClientEvent = ClientEvent @typing_extensions.final class LoginRequest(google.protobuf.message.Message): """* TAG: 2 """ DESCRIPTOR: google.protobuf.descriptor.Descriptor class _AuthService: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _AuthServiceEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ LoginRequest._AuthService.ValueType ], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor ANDROID_ID: LoginRequest._AuthService.ValueType # 2 class AuthService(_AuthService, metaclass=_AuthServiceEnumTypeWrapper): ... ANDROID_ID: LoginRequest.AuthService.ValueType # 2 ID_FIELD_NUMBER: builtins.int DOMAIN_FIELD_NUMBER: builtins.int USER_FIELD_NUMBER: builtins.int RESOURCE_FIELD_NUMBER: builtins.int AUTH_TOKEN_FIELD_NUMBER: builtins.int DEVICE_ID_FIELD_NUMBER: builtins.int LAST_RMQ_ID_FIELD_NUMBER: builtins.int SETTING_FIELD_NUMBER: builtins.int RECEIVED_PERSISTENT_ID_FIELD_NUMBER: builtins.int ADAPTIVE_HEARTBEAT_FIELD_NUMBER: builtins.int HEARTBEAT_STAT_FIELD_NUMBER: builtins.int USE_RMQ2_FIELD_NUMBER: builtins.int ACCOUNT_ID_FIELD_NUMBER: builtins.int AUTH_SERVICE_FIELD_NUMBER: builtins.int NETWORK_TYPE_FIELD_NUMBER: builtins.int STATUS_FIELD_NUMBER: builtins.int CLIENT_EVENT_FIELD_NUMBER: builtins.int id: builtins.str """Must be present ( proto required ), may be empty""" domain: builtins.str """string. mcs.android.com. """ user: builtins.str """Decimal android ID""" resource: builtins.str auth_token: builtins.str """Secret""" device_id: builtins.str """Format is: android-HEX_DEVICE_ID The user is the decimal value. """ last_rmq_id: builtins.int """RMQ1 - no longer used""" @property def setting( self, ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[ global___Setting ]: ... @property def received_persistent_id( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: """optional int32 compress = 9;""" adaptive_heartbeat: builtins.bool """Replaced by "rmq2v" setting optional bool include_stream_ids = 11; """ @property def heartbeat_stat(self) -> global___HeartbeatStat: ... use_rmq2: builtins.bool """Must be true.""" account_id: builtins.int auth_service: global___LoginRequest.AuthService.ValueType """ANDROID_ID = 2""" network_type: builtins.int status: builtins.int @property def client_event( self, ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[ global___ClientEvent ]: """Events recorded on the client after the last successful connection.""" def __init__( self, *, id: builtins.str | None = ..., domain: builtins.str | None = ..., user: builtins.str | None = ..., resource: builtins.str | None = ..., auth_token: builtins.str | None = ..., device_id: builtins.str | None = ..., last_rmq_id: builtins.int | None = ..., setting: collections.abc.Iterable[global___Setting] | None = ..., received_persistent_id: collections.abc.Iterable[builtins.str] | None = ..., adaptive_heartbeat: builtins.bool | None = ..., heartbeat_stat: global___HeartbeatStat | None = ..., use_rmq2: builtins.bool | None = ..., account_id: builtins.int | None = ..., auth_service: global___LoginRequest.AuthService.ValueType | None = ..., network_type: builtins.int | None = ..., status: builtins.int | None = ..., client_event: collections.abc.Iterable[global___ClientEvent] | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "account_id", b"account_id", "adaptive_heartbeat", b"adaptive_heartbeat", "auth_service", b"auth_service", "auth_token", b"auth_token", "device_id", b"device_id", "domain", b"domain", "heartbeat_stat", b"heartbeat_stat", "id", b"id", "last_rmq_id", b"last_rmq_id", "network_type", b"network_type", "resource", b"resource", "status", b"status", "use_rmq2", b"use_rmq2", "user", b"user", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "account_id", b"account_id", "adaptive_heartbeat", b"adaptive_heartbeat", "auth_service", b"auth_service", "auth_token", b"auth_token", "client_event", b"client_event", "device_id", b"device_id", "domain", b"domain", "heartbeat_stat", b"heartbeat_stat", "id", b"id", "last_rmq_id", b"last_rmq_id", "network_type", b"network_type", "received_persistent_id", b"received_persistent_id", "resource", b"resource", "setting", b"setting", "status", b"status", "use_rmq2", b"use_rmq2", "user", b"user", ], ) -> None: ... global___LoginRequest = LoginRequest @typing_extensions.final class LoginResponse(google.protobuf.message.Message): """* TAG: 3 """ DESCRIPTOR: google.protobuf.descriptor.Descriptor ID_FIELD_NUMBER: builtins.int JID_FIELD_NUMBER: builtins.int ERROR_FIELD_NUMBER: builtins.int SETTING_FIELD_NUMBER: builtins.int STREAM_ID_FIELD_NUMBER: builtins.int LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int HEARTBEAT_CONFIG_FIELD_NUMBER: builtins.int SERVER_TIMESTAMP_FIELD_NUMBER: builtins.int id: builtins.str jid: builtins.str """Not used.""" @property def error(self) -> global___ErrorInfo: """Null if login was ok.""" @property def setting( self, ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[ global___Setting ]: ... stream_id: builtins.int last_stream_id_received: builtins.int """Should be "1" """ @property def heartbeat_config(self) -> global___HeartbeatConfig: ... server_timestamp: builtins.int """used by the client to synchronize with the server timestamp.""" def __init__( self, *, id: builtins.str | None = ..., jid: builtins.str | None = ..., error: global___ErrorInfo | None = ..., setting: collections.abc.Iterable[global___Setting] | None = ..., stream_id: builtins.int | None = ..., last_stream_id_received: builtins.int | None = ..., heartbeat_config: global___HeartbeatConfig | None = ..., server_timestamp: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "error", b"error", "heartbeat_config", b"heartbeat_config", "id", b"id", "jid", b"jid", "last_stream_id_received", b"last_stream_id_received", "server_timestamp", b"server_timestamp", "stream_id", b"stream_id", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "error", b"error", "heartbeat_config", b"heartbeat_config", "id", b"id", "jid", b"jid", "last_stream_id_received", b"last_stream_id_received", "server_timestamp", b"server_timestamp", "setting", b"setting", "stream_id", b"stream_id", ], ) -> None: ... global___LoginResponse = LoginResponse @typing_extensions.final class StreamErrorStanza(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor TYPE_FIELD_NUMBER: builtins.int TEXT_FIELD_NUMBER: builtins.int type: builtins.str text: builtins.str def __init__( self, *, type: builtins.str | None = ..., text: builtins.str | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal["text", b"text", "type", b"type"] ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal["text", b"text", "type", b"type"] ) -> None: ... global___StreamErrorStanza = StreamErrorStanza @typing_extensions.final class Close(google.protobuf.message.Message): """* TAG: 4 """ DESCRIPTOR: google.protobuf.descriptor.Descriptor def __init__( self, ) -> None: ... global___Close = Close @typing_extensions.final class Extension(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor ID_FIELD_NUMBER: builtins.int DATA_FIELD_NUMBER: builtins.int id: builtins.int """12: SelectiveAck 13: StreamAck """ data: builtins.bytes def __init__( self, *, id: builtins.int | None = ..., data: builtins.bytes | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal["data", b"data", "id", b"id"] ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal["data", b"data", "id", b"id"] ) -> None: ... global___Extension = Extension @typing_extensions.final class IqStanza(google.protobuf.message.Message): """* TAG: 7 IqRequest must contain a single extension. IqResponse may contain 0 or 1 extensions. """ DESCRIPTOR: google.protobuf.descriptor.Descriptor class _IqType: ValueType = typing.NewType("ValueType", builtins.int) V: typing_extensions.TypeAlias = ValueType class _IqTypeEnumTypeWrapper( google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ IqStanza._IqType.ValueType ], builtins.type, ): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor GET: IqStanza._IqType.ValueType # 0 SET: IqStanza._IqType.ValueType # 1 RESULT: IqStanza._IqType.ValueType # 2 IQ_ERROR: IqStanza._IqType.ValueType # 3 class IqType(_IqType, metaclass=_IqTypeEnumTypeWrapper): ... GET: IqStanza.IqType.ValueType # 0 SET: IqStanza.IqType.ValueType # 1 RESULT: IqStanza.IqType.ValueType # 2 IQ_ERROR: IqStanza.IqType.ValueType # 3 RMQ_ID_FIELD_NUMBER: builtins.int TYPE_FIELD_NUMBER: builtins.int ID_FIELD_NUMBER: builtins.int FROM_FIELD_NUMBER: builtins.int TO_FIELD_NUMBER: builtins.int ERROR_FIELD_NUMBER: builtins.int EXTENSION_FIELD_NUMBER: builtins.int PERSISTENT_ID_FIELD_NUMBER: builtins.int STREAM_ID_FIELD_NUMBER: builtins.int LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int ACCOUNT_ID_FIELD_NUMBER: builtins.int STATUS_FIELD_NUMBER: builtins.int rmq_id: builtins.int type: global___IqStanza.IqType.ValueType id: builtins.str to: builtins.str @property def error(self) -> global___ErrorInfo: ... @property def extension(self) -> global___Extension: """Only field used in the 38+ protocol (besides common last_stream_id_received, status, rmq_id)""" persistent_id: builtins.str stream_id: builtins.int last_stream_id_received: builtins.int account_id: builtins.int status: builtins.int def __init__( self, *, rmq_id: builtins.int | None = ..., type: global___IqStanza.IqType.ValueType | None = ..., id: builtins.str | None = ..., to: builtins.str | None = ..., error: global___ErrorInfo | None = ..., extension: global___Extension | None = ..., persistent_id: builtins.str | None = ..., stream_id: builtins.int | None = ..., last_stream_id_received: builtins.int | None = ..., account_id: builtins.int | None = ..., status: builtins.int | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "account_id", b"account_id", "error", b"error", "extension", b"extension", "from", b"from", "id", b"id", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "rmq_id", b"rmq_id", "status", b"status", "stream_id", b"stream_id", "to", b"to", "type", b"type", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "account_id", b"account_id", "error", b"error", "extension", b"extension", "from", b"from", "id", b"id", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "rmq_id", b"rmq_id", "status", b"status", "stream_id", b"stream_id", "to", b"to", "type", b"type", ], ) -> None: ... global___IqStanza = IqStanza @typing_extensions.final class AppData(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor KEY_FIELD_NUMBER: builtins.int VALUE_FIELD_NUMBER: builtins.int key: builtins.str value: builtins.str def __init__( self, *, key: builtins.str | None = ..., value: builtins.str | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"] ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal["key", b"key", "value", b"value"] ) -> None: ... global___AppData = AppData @typing_extensions.final class DataMessageStanza(google.protobuf.message.Message): """* TAG: 8 Not used. optional int64 rmq_id = 1; """ DESCRIPTOR: google.protobuf.descriptor.Descriptor ID_FIELD_NUMBER: builtins.int FROM_FIELD_NUMBER: builtins.int TO_FIELD_NUMBER: builtins.int CATEGORY_FIELD_NUMBER: builtins.int TOKEN_FIELD_NUMBER: builtins.int APP_DATA_FIELD_NUMBER: builtins.int FROM_TRUSTED_SERVER_FIELD_NUMBER: builtins.int PERSISTENT_ID_FIELD_NUMBER: builtins.int STREAM_ID_FIELD_NUMBER: builtins.int LAST_STREAM_ID_RECEIVED_FIELD_NUMBER: builtins.int REG_ID_FIELD_NUMBER: builtins.int DEVICE_USER_ID_FIELD_NUMBER: builtins.int TTL_FIELD_NUMBER: builtins.int SENT_FIELD_NUMBER: builtins.int QUEUED_FIELD_NUMBER: builtins.int STATUS_FIELD_NUMBER: builtins.int RAW_DATA_FIELD_NUMBER: builtins.int IMMEDIATE_ACK_FIELD_NUMBER: builtins.int id: builtins.str """This is the message ID, set by client, DMP.9 (message_id)""" to: builtins.str """Part of DMRequest - also the key in DataMessageProto.""" category: builtins.str """Package name. DMP.2""" token: builtins.str """The collapsed key, DMP.3""" @property def app_data( self, ) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[ global___AppData ]: """User data + GOOGLE. prefixed special entries, DMP.4""" from_trusted_server: builtins.bool """Not used.""" persistent_id: builtins.str """Part of the ACK protocol, returned in DataMessageResponse on server side. It's part of the key of DMP. """ stream_id: builtins.int """In-stream ack. Increments on each message sent - a bit redundant Not used in DMP/DMR. """ last_stream_id_received: builtins.int reg_id: builtins.str """Not used. optional string permission = 12; Sent by the device shortly after registration. """ device_user_id: builtins.int """Not used. optional string pkg_signature = 14; Not used. optional string client_id = 15; serial number of the target user, DMP.8 It is the 'serial number' according to user manager. """ ttl: builtins.int """Time to live, in seconds.""" sent: builtins.int """Timestamp ( according to client ) when message was sent by app, in seconds""" queued: builtins.int """How long has the message been queued before the flush, in seconds. This is needed to account for the time difference between server and client: server should adjust 'sent' based on its 'receive' time. """ status: builtins.int raw_data: builtins.bytes """Optional field containing the binary payload of the message.""" immediate_ack: builtins.bool """Not used. How long the message was delayed before it was sent, in seconds. optional int32 actual_delay = 23; If set the server requests immediate ack. Used for important messages and for testing. """ def __init__( self, *, id: builtins.str | None = ..., to: builtins.str | None = ..., category: builtins.str | None = ..., token: builtins.str | None = ..., app_data: collections.abc.Iterable[global___AppData] | None = ..., from_trusted_server: builtins.bool | None = ..., persistent_id: builtins.str | None = ..., stream_id: builtins.int | None = ..., last_stream_id_received: builtins.int | None = ..., reg_id: builtins.str | None = ..., device_user_id: builtins.int | None = ..., ttl: builtins.int | None = ..., sent: builtins.int | None = ..., queued: builtins.int | None = ..., status: builtins.int | None = ..., raw_data: builtins.bytes | None = ..., immediate_ack: builtins.bool | None = ..., ) -> None: ... def HasField( self, field_name: typing_extensions.Literal[ "category", b"category", "device_user_id", b"device_user_id", "from", b"from", "from_trusted_server", b"from_trusted_server", "id", b"id", "immediate_ack", b"immediate_ack", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "queued", b"queued", "raw_data", b"raw_data", "reg_id", b"reg_id", "sent", b"sent", "status", b"status", "stream_id", b"stream_id", "to", b"to", "token", b"token", "ttl", b"ttl", ], ) -> builtins.bool: ... def ClearField( self, field_name: typing_extensions.Literal[ "app_data", b"app_data", "category", b"category", "device_user_id", b"device_user_id", "from", b"from", "from_trusted_server", b"from_trusted_server", "id", b"id", "immediate_ack", b"immediate_ack", "last_stream_id_received", b"last_stream_id_received", "persistent_id", b"persistent_id", "queued", b"queued", "raw_data", b"raw_data", "reg_id", b"reg_id", "sent", b"sent", "status", b"status", "stream_id", b"stream_id", "to", b"to", "token", b"token", "ttl", b"ttl", ], ) -> None: ... global___DataMessageStanza = DataMessageStanza @typing_extensions.final class StreamAck(google.protobuf.message.Message): """* Included in IQ with ID 13, sent from client or server after 10 unconfirmed messages. No last_streamid_received required. This is included within an IqStanza, which includes the last_stream_id_received. """ DESCRIPTOR: google.protobuf.descriptor.Descriptor def __init__( self, ) -> None: ... global___StreamAck = StreamAck @typing_extensions.final class SelectiveAck(google.protobuf.message.Message): """* Included in IQ sent after LoginResponse from server with ID 12. """ DESCRIPTOR: google.protobuf.descriptor.Descriptor ID_FIELD_NUMBER: builtins.int @property def id( self, ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[ builtins.str ]: ... def __init__( self, *, id: collections.abc.Iterable[builtins.str] | None = ..., ) -> None: ... def ClearField( self, field_name: typing_extensions.Literal["id", b"id"] ) -> None: ... global___SelectiveAck = SelectiveAck firebase-messaging-0.4.4/firebase_messaging/py.typed000066400000000000000000000000001467555115100225660ustar00rootroot00000000000000firebase-messaging-0.4.4/pyproject.toml000066400000000000000000000061661467555115100202110ustar00rootroot00000000000000[project] name = "firebase-messaging" version = "0.4.4" description = "FCM/GCM push notification client" authors = [{ name = "sdb9696", email = "sdb9696@users.noreply.github.com" }] license = { text="MIT" } readme = "README.rst" requires-python = ">=3.9.0" dependencies = [ "protobuf>=4.24.3,<6", "http-ece~=1.1.0", "cryptography>=2.5", "aiohttp>=3.9.3", ] keywords = [ "Firebase", "Firebase Cloud Messaging", "Google Cloud Messaging", ] classifiers = [ "Environment :: Other Environment", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "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", "Topic :: Software Development :: Libraries :: Python Modules" ] [project.urls] Homepage = "https://github.com/sdb9696/firebase-messaging" Repository = "https://github.com/sdb9696/firebase-messaging" Documentation = "http://firebase-messaging.readthedocs.io/" "Bug Tracker" = "https://github.com/sdb9696/firebase-messaging/issues" [project.optional-dependencies] docs = ["sphinx==7.1.2", "sphinx-rtd-theme~=1.3", "sphinx-autodoc-typehints~=1.24", "myst-parser"] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.sdist] include = [ "/firebase_messaging", "/tests", "/docs", "/CHANGELOG.md", ] [tool.uv] dev-dependencies = [ "pre-commit", "pytest", "pytest-mock", "pytest-asyncio", "pytest-cov", "async-timeout>=3.0.0", "pytest-socket~=0.7.0", "aioresponses~=0.7.6", "types-protobuf>=4.24", "mypy~=1.0", "ruff>=0.6.8", ] [tool.pytest.ini_options] testpaths = "tests" norecursedirs = ".git" asyncio_mode = "auto" addopts = "--disable-socket --allow-unix-socket" [tool.coverage.run] omit = [ "firebase_messaging/proto/*", "firebase_messaging/decrypt.py*" ] [tool.ruff] target-version = "py39" exclude = [ "firebase_messaging/proto/*" ] lint.select = [ "E", # pycodestyle # "D", # pydocstyle "F", # pyflakes "UP", # pyupgrade "B", # flake8-bugbear "SIM", # flake8-simplify "I", # isort "S", # bandit ] lint.ignore = [ "D105", # Missing docstring in magic method "D107", # Missing docstring in `__init__` ] [tool.ruff.lint.pydocstyle] convention = "pep257" [tool.ruff.lint.per-file-ignores] "tests/*.py" = [ "D100", "D101", "D102", "D103", "D104", "F401", "S101", # allow asserts "E501", # ignore line-too-longs ] "docs/source/conf.py" = [ "D100", "D103", ] [tool.mypy] # exclude pattern inside triple quotes should be synced to .pre-commit-config.yaml exclude = '''(?x)( ^docs/.*| ^tests/.*| ^firebase_messaging/proto/.*py$ )''' disallow_untyped_defs = true [[tool.mypy.overrides]] module = [ "firebase_messaging.proto.*" ] disallow_untyped_defs = false [tool.doc8] paths = ["docs"] ignore = ["D001"] ignore-path = ["docs/build"] firebase-messaging-0.4.4/tests/000077500000000000000000000000001467555115100164265ustar00rootroot00000000000000firebase-messaging-0.4.4/tests/__init__.py000066400000000000000000000000001467555115100205250ustar00rootroot00000000000000firebase-messaging-0.4.4/tests/conftest.py000066400000000000000000000063621467555115100206340ustar00rootroot00000000000000"""Test configuration for the Ring platform.""" import asyncio import json import logging import os import threading from unittest.mock import patch import pytest from aioresponses import CallbackResult, aioresponses from google.protobuf.json_format import Parse as JsonParse from firebase_messaging.fcmpushclient import ( FcmPushClient, FcmPushClientConfig, FcmRegisterConfig, ) from firebase_messaging.proto.checkin_pb2 import AndroidCheckinResponse from firebase_messaging.proto.mcs_pb2 import LoginResponse from tests.fakes import FakeMcsEndpoint def load_fixture(filename): """Load a fixture.""" path = os.path.join(os.path.dirname(__file__), "fixtures", filename) with open(path) as fdp: return fdp.read() def load_fixture_as_dict(filename): """Load a fixture.""" return json.loads(load_fixture(filename)) def load_fixture_as_msg(filename, msg_class): """Load a fixture.""" msg = msg_class() JsonParse(load_fixture(filename), msg) return msg @pytest.fixture() async def fake_mcs_endpoint(): fmce = FakeMcsEndpoint() async def _mock_open_conn(*_, **__): return fmce.client_reader, fmce.client_writer with patch("asyncio.open_connection", side_effect=_mock_open_conn, autospec=True): yield fmce fmce.close() @pytest.fixture() async def logged_in_push_client(request, fake_mcs_endpoint, mocker, caplog): clients = {} caplog.set_level(logging.DEBUG) async def _logged_in_push_client( msg_callback, credentials, *, callback_obj=None, supress_disconnect=False, **config_kwargs, ): config = FcmPushClientConfig(**config_kwargs) fcm_config = FcmRegisterConfig("project-1234", "bar", "foobar", "foobar") pr = FcmPushClient( msg_callback, fcm_config, credentials, None, callback_context=callback_obj, config=config, ) await pr.checkin_or_register() await pr.start() await fake_mcs_endpoint.get_message() lr = load_fixture_as_msg("login_response.json", LoginResponse) await fake_mcs_endpoint.put_message(lr) clients[pr] = supress_disconnect return pr yield _logged_in_push_client for k, v in clients.items(): if not v: await k.stop() @pytest.fixture(autouse=True, name="aioresponses_mock") def aioresponses_mock_fixture(): with aioresponses() as mock: mock.post( "https://android.clients.google.com/checkin", body=load_fixture_as_msg( "android_checkin_response.json", AndroidCheckinResponse ).SerializeToString(), ) mock.post( "https://android.clients.google.com/c2dm/register3", body=load_fixture("gcm_register_response.txt"), ) mock.post( "https://firebaseinstallations.googleapis.com/v1/projects/project-1234/installations", payload=load_fixture_as_dict("fcm_install_response.json"), ) mock.post( "https://fcmregistrations.googleapis.com/v1/projects/project-1234/registrations", payload=load_fixture_as_dict("fcm_register_response.json"), ) yield mock firebase-messaging-0.4.4/tests/fakes.py000066400000000000000000000101651467555115100200740ustar00rootroot00000000000000import asyncio import struct from unittest.mock import patch # When support for cpython older than 3.11 is dropped # async_timeout can be replaced with asyncio.timeout from async_timeout import timeout as asyncio_timeout from firebase_messaging.fcmpushclient import MCS_MESSAGE_TAG, MCS_VERSION, FcmPushClient from firebase_messaging.proto.checkin_pb2 import AndroidCheckinResponse from firebase_messaging.proto.mcs_pb2 import LoginResponse class FakeMcsEndpoint: def __init__(self): # self.connection_mock = patch( # "asyncio.open_connection", side_effect=self.open_connection, autospec=True # ) # self.connection_mock.start() self.client_writer = self.FakeWriter() self.client_reader = self.FakeReader() def close(self): # self.connection_mock.stop() pass async def open_connection(self, *_, **__): # Queues should be created on the loop that will be accessing them self.client_writer = self.FakeWriter() self.client_reader = self.FakeReader() return self.client_reader, self.client_writer async def put_message(self, message): await self.client_reader.put_message(message) async def put_error(self, error): await self.client_reader.put_error(error) async def get_message(self): return await self.client_writer.get_message() class FakeReader: def __init__(self): self.queue = asyncio.Queue() self.lock = asyncio.Lock() async def readexactly(self, size): if size == 0: return b"" val = await self.queue.get() if isinstance(val, BaseException): raise val else: for _ in range(1, size): val += await self.queue.get() return val async def put_message(self, message): include_version = isinstance(message, LoginResponse) packet = FcmPushClient._make_packet(message, include_version) async with self.lock: for p in packet: b = bytes([p]) await self.queue.put(b) async def put_error(self, error): async with self.lock: await self.queue.put(error) class FakeWriter: def __init__(self): self.queue = asyncio.Queue() self.buf = "" self.lock = asyncio.Lock() def write(self, buffer): for i in buffer: b = bytes([i]) self.queue.put_nowait(b) async def drain(self): pass def close(self): pass async def wait_closed(self): pass async def get_bytes(self, size): async with self.lock: val = b"" for _ in range(size): val += await self.queue.get() return val async def get_message(self, timeout=2): async with asyncio_timeout(timeout): r = await self.get_bytes(1) (b,) = struct.unpack("B", r) if b == MCS_VERSION: # first message r = await self.get_bytes(1) (b,) = struct.unpack("B", r) tag = b size = await self._read_varint32() msgstr = await self.get_bytes(size) msg_class = next( iter([c for c, t in MCS_MESSAGE_TAG.items() if t == tag]) ) msg = msg_class() msg.ParseFromString(msgstr) return msg # protobuf variable length integers are encoded in base 128 # each byte contains 7 bits of the integer and the msb is set if there's # more. pretty simple to implement async def _read_varint32(self): res = 0 shift = 0 while True: r = await self.get_bytes(1) (b,) = struct.unpack("B", r) res |= (b & 0x7F) << shift if (b & 0x80) == 0: break shift += 7 return res firebase-messaging-0.4.4/tests/fixtures/000077500000000000000000000000001467555115100202775ustar00rootroot00000000000000firebase-messaging-0.4.4/tests/fixtures/android_checkin_response.json000066400000000000000000000003031467555115100262100ustar00rootroot00000000000000{ "statsOk": true, "timeMsec": "1697711296660", "androidId": "5678901234567890123", "securityToken": "0123456789012345678", "versionInfo": "Y9B3d2P5mMMSQKri541rkWUVCal3tBg" } firebase-messaging-0.4.4/tests/fixtures/close.json000066400000000000000000000000031467555115100222700ustar00rootroot00000000000000{} firebase-messaging-0.4.4/tests/fixtures/credentials.json000066400000000000000000000044171467555115100234750ustar00rootroot00000000000000{ "gcm": { "token": "XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz", "app_id": "abcdef01-ef12-1234-12ef-abcdef012345", "android_id": "5678901234567890123", "security_token": "0123456789012345678" }, "keys": { "public": "BPEHm32RWI4db8FCk0IM6G9f9vz_uJeRiuU64Y5dkyZjkBXmyGgzwzZMylPaLNvg50EuoQmNlU7sSMUf0mYctn0=", "private": "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg-jTz69Lsq4oa49_5PMMkcqYFwkEGc5L-zGDwUwfY5eahRANCAATxB5t9kViOHW_BQpNCDOhvX_b8_7iXkYrlOuGOXZMmY5AV5shoM8M2TMpT2izb4OdBLqEJjZVO7EjFH9JmHLZ9", "secret": "_zGHqwp9rRP5cgzilMLvCA" }, "fcm": { "registration": { "name": "projects/project-1234/registrations/abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz_XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "token": "abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz_XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "web": { "endpoint": "https://fcm.googleapis.com/fcm/send/XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz", "p256dh": "123456967219824KDJDOWFNAFW=", "auth": "DSFNDSAKGFAGFA==" } }, "installation": { "token": "OPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijkl", "expires_in": 604800, "refresh_token": "1_OPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijkl", "fid": "1234AMXDRTTYODLsd-nb14", "created_at": 36245.436300371 } }, "config": { "bundle_id": "project.push.com", "project_id": "project-1234", "vapid_key": "BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoMj8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4" } } firebase-messaging-0.4.4/tests/fixtures/data_message_stanza.json000066400000000000000000000014421467555115100251700ustar00rootroot00000000000000{ "id": "ABCDEF12", "from": "ZYXW01-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnop-1_zyxwvutsrqZYXWVUTSRQ12345", "category": "org.chromium.linux", "appData": [ { "key": "google.source", "value": "webpush" }, { "key": "encryption", "value": "salt=zZYXWVUTSRQ12yxwvutsrq==" }, { "key": "subtype", "value": "abcdef01-ef12-1234-12ef-abcdef012345" }, { "key": "crypto-key", "value": "dh=BAGEFtID7WlmwzQ9pbjdRYAhfPe7Z8lA3ZGIPUh0SE3ikoY2PIrWUP0rmhpE4Kl8ImgMUDjKWrz0WmtLxORIHuw=" } ], "persistentId": "0:0123456789123456%0123456789abcdef", "lastStreamIdReceived": 6, "ttl": 240, "sent": "1697189311810", "rawData": "3vJvXzzGf1gF9D7eB6/ioZT+lWWstyY9B/Yjebjm7mU3YTg=" } firebase-messaging-0.4.4/tests/fixtures/fcm_install_response.json000066400000000000000000000011021467555115100253750ustar00rootroot00000000000000{ "name": "projects/123456789101/installations/1234AMXDRTTYODLsd-nb14", "fid": "1234AMXDRTTYODLsd-nb14", "refreshToken": "1_OPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijkl", "authToken": { "token": "OPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijklOPQRSTUVWXYZ-01234abcdefghijkl", "expiresIn": "604800s" } } firebase-messaging-0.4.4/tests/fixtures/fcm_register_response.json000066400000000000000000000012641467555115100255640ustar00rootroot00000000000000{ "name": "projects/project-1234/registrations/abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz_XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "token": "abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz_XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ", "web": { "endpoint": "https://fcm.googleapis.com/fcm/send/XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz", "p256dh": "123456967219824KDJDOWFNAFW=", "auth": "DSFNDSAKGFAGFA==" } } firebase-messaging-0.4.4/tests/fixtures/gcm_register_response.txt000066400000000000000000000002371467555115100254320ustar00rootroot00000000000000token=XYZ01234zyx:APA91b0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-0123456789_ABCDEFGHIJKLMNOPQRSTUVWXYZ-01234abcdefghijklmnopqrstuvwxyz firebase-messaging-0.4.4/tests/fixtures/heartbeat_ack.json000066400000000000000000000000421467555115100237430ustar00rootroot00000000000000{ "lastStreamIdReceived": 3 } firebase-messaging-0.4.4/tests/fixtures/heartbeat_ping.json000066400000000000000000000000031467555115100241370ustar00rootroot00000000000000{} firebase-messaging-0.4.4/tests/fixtures/iq_stanza_selective_ack.json000066400000000000000000000002271467555115100260450ustar00rootroot00000000000000{ "type": "SET", "id": "", "extension": { "id": 12, "data": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn==" } } firebase-messaging-0.4.4/tests/fixtures/iq_stanza_stream_ack.json000066400000000000000000000001171467555115100253530ustar00rootroot00000000000000{ "type": "SET", "id": "", "extension": { "id": 13 } } firebase-messaging-0.4.4/tests/fixtures/login_request.json000066400000000000000000000010251467555115100240500ustar00rootroot00000000000000{ "id": "chrome-63.0.3234.0", "domain": "mcs.android.com", "user": "0123456789876543210", "resource": "9876543210987654321", "authToken": "123456789123456789", "deviceId": "android-490ca293031302b0", "setting": [ { "name": "new_vc", "value": "1" } ], "adaptiveHeartbeat": false, "heartbeatStat": { "ip": "", "timeout": true, "intervalMs": 30000 }, "useRmq2": true, "authService": "ANDROID_ID", "networkType": 1 } firebase-messaging-0.4.4/tests/fixtures/login_response.json000066400000000000000000000002301467555115100242130ustar00rootroot00000000000000{ "id": "chrome-63.0.3234.0", "jid": "user@firebase.com/notifications", "lastStreamIdReceived": 1, "serverTimestamp": "1697190143057" } firebase-messaging-0.4.4/tests/test_fcmpushclient.py000066400000000000000000000147671467555115100227220ustar00rootroot00000000000000"""The tests for the Ring platform.""" import asyncio from base64 import standard_b64encode, urlsafe_b64decode import pytest from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.serialization import load_der_private_key from http_ece import encrypt from firebase_messaging import FcmPushClient, FcmRegisterConfig from firebase_messaging.proto.mcs_pb2 import ( Close, DataMessageStanza, HeartbeatAck, HeartbeatPing, IqStanza, LoginRequest, ) from tests.conftest import load_fixture_as_dict, load_fixture_as_msg async def test_register(): pr = FcmPushClient( None, FcmRegisterConfig("project-1234", "bar", "foobar", "foobar"), None ) await pr.checkin_or_register() async def test_login(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): await logged_in_push_client(None, None) await asyncio.sleep(0.1) assert ( len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 ) assert "Succesfully logged in to MCS endpoint" in [ record.message for record in caplog.records if record.levelname == "INFO" ] async def test_data_message_receive( logged_in_push_client, fake_mcs_endpoint, mocker, caplog ): notification = None persistent_id = None callback_obj = None cb_loop = None def on_msg(ntf, psid, obj=None): nonlocal notification nonlocal persistent_id nonlocal callback_obj nonlocal cb_loop notification = ntf persistent_id = psid callback_obj = obj cb_loop = asyncio.get_running_loop() credentials = load_fixture_as_dict("credentials.json") obj = "Foobar" await logged_in_push_client(on_msg, credentials, callback_obj=obj) dms = load_fixture_as_msg("data_message_stanza.json", DataMessageStanza) await fake_mcs_endpoint.put_message(dms) msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, IqStanza) await asyncio.sleep(0.1) assert ( len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 ) assert notification == {"foo": "bar"} assert persistent_id == dms.persistent_id assert obj == callback_obj async def test_connection_reset(logged_in_push_client, fake_mcs_endpoint, mocker): # ConnectionResetError, TimeoutError, SSLError pr = await logged_in_push_client( None, None, abort_on_sequential_error_count=3, reset_interval=0.1 ) reset_spy = mocker.spy(pr, "_reset") await fake_mcs_endpoint.put_error(ConnectionResetError()) await asyncio.sleep(0.1) assert reset_spy.call_count == 1 msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, LoginRequest) @pytest.mark.parametrize("error_count", [1, 2, 3, 6]) async def test_terminate( logged_in_push_client, fake_mcs_endpoint, mocker, error_count, caplog ): pr = await logged_in_push_client( None, None, abort_on_sequential_error_count=error_count, reset_interval=0 ) reset_spy = mocker.spy(pr, "_reset") term_spy = mocker.spy(pr, "_terminate") for i in range(1, error_count + 1): await fake_mcs_endpoint.put_error(ConnectionResetError()) await asyncio.sleep(0.1) # client should reset while it gets errors < abort_on_sequential_error_count then it should terminate if i < error_count: assert reset_spy.call_count == i assert term_spy.call_count == 0 msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, LoginRequest) else: assert reset_spy.call_count == i - 1 assert term_spy.call_count == 1 async def test_heartbeat_receive(logged_in_push_client, fake_mcs_endpoint, caplog): await logged_in_push_client(None, None) ping = load_fixture_as_msg("heartbeat_ping.json", HeartbeatPing) await fake_mcs_endpoint.put_message(ping) msg = await fake_mcs_endpoint.get_message() assert isinstance(msg, HeartbeatAck) assert ( len([record for record in caplog.records if record.levelname == "ERROR"]) == 0 ) async def test_heartbeat_send(logged_in_push_client, fake_mcs_endpoint, mocker, caplog): pr: FcmPushClient = await logged_in_push_client(None, None) ack = load_fixture_as_msg("heartbeat_ack.json", HeartbeatAck) await pr._send_heartbeat() ping_msg = await fake_mcs_endpoint.get_message() await fake_mcs_endpoint.put_message(ack) await asyncio.sleep(0.1) assert isinstance(ping_msg, HeartbeatPing) assert ( len( [ record.message for record in caplog.records if record.levelname == "DEBUG" and "Received heartbeat ack" in record.message ] ) == 1 ) async def test_decrypt(): def get_app_data_by_key(msg, key): for x in msg.app_data: if x.key == key: return x.value def set_app_data_by_key(msg, key, value): for x in msg.app_data: if x.key == key: x.value = value dms = load_fixture_as_msg("data_message_stanza.json", DataMessageStanza) credentials = load_fixture_as_dict("credentials.json") raw_data = b'{ "foo" : "bar" }' salt_str = get_app_data_by_key(dms, "encryption")[5:] salt = urlsafe_b64decode(salt_str.encode("ascii")) # Random key pair sender_pub = "BAGEFtID7WlmwzQ9pbjdRYAhfPe7Z8lA3ZGIPUh0SE3ikoY2PIrWUP0rmhpE4Kl8ImgMUDjKWrz0WmtLxORIHuw" sender_pri_der = urlsafe_b64decode( "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgwSUpDfIqdJG3XVkn7t1GExHuW3gsqD4-J525w-rnCIihRANCAAQBhBbSA-1pZsM0PaW43UWAIXz3u2fJQN2RiD1IdEhN4pKGNjyK1lD9K5oaROCpfCJoDFA4ylq89FprS8TkSB7s".encode( "ascii" ) + b"========" ) sender_privkey = load_der_private_key( sender_pri_der, password=None, backend=default_backend() ) sender_sec = urlsafe_b64decode( credentials["keys"]["secret"].encode("ascii") + b"========" ) receiver_pub_key = urlsafe_b64decode( credentials["keys"]["public"].encode("ascii") + b"=" ) raw_data_encrypted = encrypt( raw_data, salt=salt, private_key=sender_privkey, dh=receiver_pub_key, version="aesgcm", auth_secret=sender_sec, ) set_app_data_by_key(dms, "crypto-key", "dh=" + sender_pub) raw_data_decrypted = FcmPushClient._decrypt_raw_data( credentials, sender_pub + "=", salt_str, raw_data_encrypted ) assert raw_data_decrypted == raw_data firebase-messaging-0.4.4/uv.lock000066400000000000000000006545611467555115100166110ustar00rootroot00000000000000version = 1 requires-python = ">=3.9.0" [[package]] name = "aiohappyeyeballs" version = "2.4.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c7/d9/e710a5c9e51b4d5a977c823ce323a81d344da8c1b6fba16bb270a8be800d/aiohappyeyeballs-2.4.2.tar.gz", hash = "sha256:4ca893e6c5c1f5bf3888b04cb5a3bee24995398efef6e0b9f747b5e89d84fd74", size = 18391 } wheels = [ { url = "https://files.pythonhosted.org/packages/13/64/40165ff77ade5203284e3015cf88e11acb07d451f6bf83fff71192912a0d/aiohappyeyeballs-2.4.2-py3-none-any.whl", hash = "sha256:8522691d9a154ba1145b157d6d5c15e5c692527ce6a53c5e5f9876977f6dab2f", size = 14105 }, ] [[package]] name = "aiohttp" version = "3.10.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, { name = "attrs" }, { name = "frozenlist" }, { name = "multidict" }, { name = "yarl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/97/15c51bbfcc184bcb4d473b7b02e7b54b6978e0083556a9cd491875cf11f7/aiohttp-3.10.6.tar.gz", hash = "sha256:d2578ef941be0c2ba58f6f421a703527d08427237ed45ecb091fed6f83305336", size = 7538429 } wheels = [ { url = "https://files.pythonhosted.org/packages/00/a5/20d5b4cc1dbf5292434ad968af698c3e25b149394060578c4e83edfe5c56/aiohttp-3.10.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:682836fc672972cc3101cc9e30d49c5f7e8f1d010478d46119fe725a4545acfd", size = 586587 }, { url = "https://files.pythonhosted.org/packages/d6/77/bcb8f5e382d800673c6457cab3cb24143ae30578682687d334a556fe4021/aiohttp-3.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:289fa8a20018d0d5aa9e4b35d899bd51bcb80f0d5f365d9a23e30dac3b79159b", size = 398987 }, { url = "https://files.pythonhosted.org/packages/19/b1/874ca8a6fd581303f1f99efc71aff034e1b955702d54b96a61d97f18387f/aiohttp-3.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8617c96a20dd57e7e9d398ff9d04f3d11c4d28b1767273a5b1a018ada5a654d3", size = 390350 }, { url = "https://files.pythonhosted.org/packages/41/2b/18f60f36d3b0d6b4f9680b00e129058086984af33ab01743d8f8d662ae43/aiohttp-3.10.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdbeff1b062751c2a2a55b171f7050fb7073633c699299d042e962aacdbe1a07", size = 1228449 }, { url = "https://files.pythonhosted.org/packages/d5/77/801a07f67a6ccfc2d6e8c372e196b6019f33d637e6a3abf84f876983dbfd/aiohttp-3.10.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea35d849cdd4a9268f910bff4497baebbc1aa3f2f625fd8ccd9ac99c860c621", size = 1264246 }, { url = "https://files.pythonhosted.org/packages/bd/ff/984219306cbc1fedd689e9cfe7894d0cb2ae0038f2d7079e2788a79383ee/aiohttp-3.10.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473961b3252f3b949bb84873d6e268fb6d8aa0ccc6eb7404fa58c76a326bb8e1", size = 1298031 }, { url = "https://files.pythonhosted.org/packages/25/34/96445dc2db0ff0e7ffe71abb73e298a62c2724b774470d5b232ed8ee89ad/aiohttp-3.10.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d2665c5df629eb2f981dab244c01bfa6cdc185f4ffa026639286c4d56fafb54", size = 1221827 }, { url = "https://files.pythonhosted.org/packages/6d/59/52170050e3e83e476321cce2232c456d55ecf0b67faf9a31b73328d7b65f/aiohttp-3.10.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25d92f794f1332f656e3765841fc2b7ad5c26c3f3d01e8949eeb3495691cf9f4", size = 1193436 }, { url = "https://files.pythonhosted.org/packages/4f/ad/cb020bdb02e41ed4cf0f9a1031c67424d9dd1b1dd3e5fd98053ed3b4f72f/aiohttp-3.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9bd6b2033993d5ae80883bb29b83fb2b432270bbe067c2f53cc73bb57c46065f", size = 1193175 }, { url = "https://files.pythonhosted.org/packages/59/d3/58cf6e9c81064d07173ee0e31743fa18212e3c76d1041a30164e91e91e7d/aiohttp-3.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d7f408c43f5e75ea1edc152fb375e8f46ef916f545fb66d4aebcbcfad05e2796", size = 1192674 }, { url = "https://files.pythonhosted.org/packages/b2/1f/c203e3ff4636885f8d47228a717f248b7acd5761a9fb57650f8ad393cb1a/aiohttp-3.10.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:cf8b8560aa965f87bf9c13bf9fed7025993a155ca0ce8422da74bf46d18c2f5f", size = 1246831 }, { url = "https://files.pythonhosted.org/packages/e2/e4/8534f620113c9922d911271678f6f053192627035bfa7b0b62c9baa48908/aiohttp-3.10.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14477c4e52e2f17437b99893fd220ffe7d7ee41df5ebf931a92b8ca82e6fd094", size = 1263732 }, { url = "https://files.pythonhosted.org/packages/3c/99/d5ada3481146b42312a83b16304b001125df8e8e7751c71a0f26cf4fb38f/aiohttp-3.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb138fbf9f53928e779650f5ed26d0ea1ed8b2cab67f0ea5d63afa09fdc07593", size = 1215377 }, { url = "https://files.pythonhosted.org/packages/82/2d/a5afdfb5c37a7dbb4468ff39a4581a6290b2ced18fb5513981a9154c91c1/aiohttp-3.10.6-cp310-cp310-win32.whl", hash = "sha256:9843d683b8756971797be171ead21511d2215a2d6e3c899c6e3107fbbe826791", size = 362309 }, { url = "https://files.pythonhosted.org/packages/49/2e/d06c4bf365685ba0ea501e5bb5b4a4b0c3f90236f8a38ee0083c56624847/aiohttp-3.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:f8b8e49fe02f744d38352daca1dbef462c3874900bd8166516f6ea8e82b5aacf", size = 380724 }, { url = "https://files.pythonhosted.org/packages/d5/f0/6c921693dd264db370916dab69cc3267ca4bb14296b4ca88b3855f6152cd/aiohttp-3.10.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f52e54fd776ad0da1006708762213b079b154644db54bcfc62f06eaa5b896402", size = 586118 }, { url = "https://files.pythonhosted.org/packages/df/14/12804459bd128ff3c7d60dadaf49be9e7027df5c8800290518113c411d00/aiohttp-3.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:995ab1a238fd0d19dc65f2d222e5eb064e409665c6426a3e51d5101c1979ee84", size = 398614 }, { url = "https://files.pythonhosted.org/packages/49/2c/066640d3c3dd52d4c11dfcff64c6eebe4a7607571bc9cb8ae2c2b4013367/aiohttp-3.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0749c4d5a08a802dd66ecdf59b2df4d76b900004017468a7bb736c3b5a3dd902", size = 390262 }, { url = "https://files.pythonhosted.org/packages/71/50/6db8a9ba23ee4d5621ec2a59427c271cc1ddaf4fc1a9c02c9dcba1ebe671/aiohttp-3.10.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e05b39158f2af0e2438cc2075cfc271f4ace0c3cc4a81ec95b27a0432e161951", size = 1306113 }, { url = "https://files.pythonhosted.org/packages/51/fd/a923745abb24657264b2122c24a296468cf8c16ba68b7b569060d6c32620/aiohttp-3.10.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a9f196c970db2dcde4f24317e06615363349dc357cf4d7a3b0716c20ac6d7bcd", size = 1344288 }, { url = "https://files.pythonhosted.org/packages/f8/7a/5f1397305aa5885a35dce0b10681aa547537348a18d107d96a07e99bebb8/aiohttp-3.10.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:47647c8af04a70e07a2462931b0eba63146a13affa697afb4ecbab9d03a480ce", size = 1378118 }, { url = "https://files.pythonhosted.org/packages/fd/80/4f1c4b5459a27437a8f18f91d6000fdc45b677aee879129deaadc94c1a23/aiohttp-3.10.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:669c0efe7e99f6d94d63274c06344bd0e9c8daf184ce5602a29bc39e00a18720", size = 1292337 }, { url = "https://files.pythonhosted.org/packages/e1/57/cef69e70f18271f86080a3d28571598baf0dccb2fc726fbd74b91a56d51a/aiohttp-3.10.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9721cdd83a994225352ca84cd537760d41a9da3c0eacb3ff534747ab8fba6d0", size = 1251407 }, { url = "https://files.pythonhosted.org/packages/b0/dd/8b718a8ecb271d484c6d43f4ae3d63e684c259367c8c2cda861f1bf12cfd/aiohttp-3.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0b82c8ebed66ce182893e7c0b6b60ba2ace45b1df104feb52380edae266a4850", size = 1271350 }, { url = "https://files.pythonhosted.org/packages/f8/37/c80d05752ecbe7419ec61d39facff8d77914e295c8d45eb250d1fa03ae78/aiohttp-3.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b169f8e755e541b72e714b89a831b315bbe70db44e33fead28516c9e13d5f931", size = 1265888 }, { url = "https://files.pythonhosted.org/packages/4f/44/9862295fabcadcf7d79e9a92eb8528866d602042571c43c333d94c7f3025/aiohttp-3.10.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0be3115753baf8b4153e64f9aa7bf6c0c64af57979aa900c31f496301b374570", size = 1321251 }, { url = "https://files.pythonhosted.org/packages/57/62/5b92e910aa95c2558b418eb68f0d117aab968cdd15019c06ea1c66d0baf2/aiohttp-3.10.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e1f80cd17d81a404b6e70ef22bfe1870bafc511728397634ad5f5efc8698df56", size = 1338856 }, { url = "https://files.pythonhosted.org/packages/7e/e6/bb013958e9fcfb982d8dba12b0c72621427619cd0a11bb3023601c205988/aiohttp-3.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6419728b08fb6380c66a470d2319cafcec554c81780e2114b7e150329b9a9a7f", size = 1298691 }, { url = "https://files.pythonhosted.org/packages/f7/c7/cc2dc01f89d8a0ee2d84d8d0c85b48ec62a427bcd865736f9ceb340c0117/aiohttp-3.10.6-cp311-cp311-win32.whl", hash = "sha256:bd294dcdc1afdc510bb51d35444003f14e327572877d016d576ac3b9a5888a27", size = 361858 }, { url = "https://files.pythonhosted.org/packages/9f/2a/60284a07a0353250cf64db9728980a3bb9a55eeea334d79c48e65801460a/aiohttp-3.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:bf861da9a43d282d6dd9dcd64c23a0fccf2c5aa5cd7c32024513c8c79fb69de3", size = 381204 }, { url = "https://files.pythonhosted.org/packages/41/6b/0db03d1105e5e8564fd39a87729fd910300a8021b2c59f6f57ed963fe896/aiohttp-3.10.6-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2708baccdc62f4b1251e59c2aac725936a900081f079b88843dabcab0feeeb27", size = 583162 }, { url = "https://files.pythonhosted.org/packages/d0/9e/c44dddee462c38853a0c32b50c4deed09790d27496ab9eb3b481614344a5/aiohttp-3.10.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7475da7a5e2ccf1a1c86c8fee241e277f4874c96564d06f726d8df8e77683ef7", size = 395317 }, { url = "https://files.pythonhosted.org/packages/25/0e/c0dfb1604645ab64e2b1210e624f951a024a2e9683feb563bbf979874220/aiohttp-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:02108326574ff60267b7b35b17ac5c0bbd0008ccb942ce4c48b657bb90f0b8aa", size = 390533 }, { url = "https://files.pythonhosted.org/packages/5c/50/8c3eba14ce77fd78f1def3788cbc75b54291dd4d8f5647d721316437f5da/aiohttp-3.10.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:029a019627b37fa9eac5c75cc54a6bb722c4ebbf5a54d8c8c0fb4dd8facf2702", size = 1311699 }, { url = "https://files.pythonhosted.org/packages/bd/02/d0f12cfc7ade482d81c6d2c4c5f2f98964d6305560b7df0b7712212241ca/aiohttp-3.10.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a637d387db6fdad95e293fab5433b775fd104ae6348d2388beaaa60d08b38c4", size = 1350180 }, { url = "https://files.pythonhosted.org/packages/31/2b/f78ff8d84e700a279434dd371ae6e87e12a13f9ed2a5efe9cd6aacd749d4/aiohttp-3.10.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1a16f3fc1944c61290d33c88dc3f09ba62d159b284c38c5331868425aca426", size = 1392281 }, { url = "https://files.pythonhosted.org/packages/a5/f8/a8722a471cbf19e56763545fd5bc0fdf7b61324535f0b35bd6f0548d4016/aiohttp-3.10.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81b292f37969f9cc54f4643f0be7dacabf3612b3b4a65413661cf6c350226787", size = 1305932 }, { url = "https://files.pythonhosted.org/packages/38/a5/897caff83bfe41fd749056b11282504772b34c2dfe730aaf8e84bbd3a660/aiohttp-3.10.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0754690a3a26e819173a34093798c155bafb21c3c640bff13be1afa1e9d421f9", size = 1259884 }, { url = "https://files.pythonhosted.org/packages/e1/75/effbadbf5c9a536f90769544467da311efd6e8c43671bc0729055c59d363/aiohttp-3.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:164ecd32e65467d86843dbb121a6666c3deb23b460e3f8aefdcaacae79eb718a", size = 1270764 }, { url = "https://files.pythonhosted.org/packages/33/34/33e07d1bc34406bfc0877f22eed071060796431488c8eb6d456c583a74a9/aiohttp-3.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438c5863feb761f7ca3270d48c292c334814459f61cc12bab5ba5b702d7c9e56", size = 1279882 }, { url = "https://files.pythonhosted.org/packages/2e/e4/ffed46ce0b45564cbf715b0b97725840468c7c5a9d6e8d560082c29ad4bf/aiohttp-3.10.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ba18573bb1de1063d222f41de64a0d3741223982dcea863b3f74646faf618ec7", size = 1316432 }, { url = "https://files.pythonhosted.org/packages/ce/00/488d68568f60aa5dbf9d41ef60d276ffbafeab553bf79b00225de7133e0b/aiohttp-3.10.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c82a94ddec996413a905f622f3da02c4359952aab8d817c01cf9915419525e95", size = 1343562 }, { url = "https://files.pythonhosted.org/packages/14/3e/3679c1438fcb0aadddff32e97b3b88b1c8aea80276d374ec543a5ed70d0d/aiohttp-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92351aa5363fc3c1f872ca763f86730ced32b01607f0c9662b1fa711087968d0", size = 1305803 }, { url = "https://files.pythonhosted.org/packages/76/48/fe117dffa13c69d9670e107cbf3dea20be9f7fc5d30d2fd3fd6252f28c58/aiohttp-3.10.6-cp312-cp312-win32.whl", hash = "sha256:3e15e33bfc73fa97c228f72e05e8795e163a693fd5323549f49367c76a6e5883", size = 358921 }, { url = "https://files.pythonhosted.org/packages/92/9f/7281a6dae91c9cc3f23dfb865f074151810216f31bdb46843bfde8e39f17/aiohttp-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:fe517113fe4d35d9072b826c3e147d63c5f808ca8167d450b4f96c520c8a1d8d", size = 378938 }, { url = "https://files.pythonhosted.org/packages/12/7f/89eb922fda25d5b9c7c08d14d50c788d998f148210478059b7549040424a/aiohttp-3.10.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:482f74057ea13d387a7549d7a7ecb60e45146d15f3e58a2d93a0ad2d5a8457cd", size = 575722 }, { url = "https://files.pythonhosted.org/packages/84/6d/eb3965c55748f960751b752969983982a995d2aa21f023ed30fe5a471629/aiohttp-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:03fa40d1450ee5196e843315ddf74a51afc7e83d489dbfc380eecefea74158b1", size = 391518 }, { url = "https://files.pythonhosted.org/packages/78/4a/98c9d9cee601477eda8f851376eff88e864e9f3147cbc3a428da47d90ed0/aiohttp-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e52e59ed5f4cc3a3acfe2a610f8891f216f486de54d95d6600a2c9ba1581f4d", size = 387037 }, { url = "https://files.pythonhosted.org/packages/2d/b0/6136aefae0f0d2abe4a435af71a944781e37bbe6fd836a23ff41bbba0682/aiohttp-3.10.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b3935a22c9e41a8000d90588bed96cf395ef572dbb409be44c6219c61d900d", size = 1286703 }, { url = "https://files.pythonhosted.org/packages/cd/8a/a17ec94a7b6394efeeaca16df8d1e9359f0aa83548e40bf16b5853ed7684/aiohttp-3.10.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bef1480ee50f75abcfcb4b11c12de1005968ca9d0172aec4a5057ba9f2b644f", size = 1323244 }, { url = "https://files.pythonhosted.org/packages/35/37/4cf6d2a8dce91ea7ff8b8ed8e1ef5c6a5934e07b4da5993ae95660b7cfbc/aiohttp-3.10.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:671745ea7db19693ce867359d503772177f0b20fa8f6ee1e74e00449f4c4151d", size = 1368034 }, { url = "https://files.pythonhosted.org/packages/0d/d5/e939fcf26bd5c7760a1b71eff7396f6ca0e3c807088086551db28af0c090/aiohttp-3.10.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b50b367308ca8c12e0b50cba5773bc9abe64c428d3fd2bbf5cd25aab37c77bf", size = 1282395 }, { url = "https://files.pythonhosted.org/packages/46/44/85d5d61b3ac50f30766cd2c1d22e6f937f027922621fc91581ead05749f6/aiohttp-3.10.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a504d7cdb431a777d05a124fd0b21efb94498efa743103ea01b1e3136d2e4fb", size = 1236147 }, { url = "https://files.pythonhosted.org/packages/61/35/43eee26590f369906151cea78297554304ed2ceda5a5ed69cc2e907e9903/aiohttp-3.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:66bc81361131763660b969132a22edce2c4d184978ba39614e8f8f95db5c95f8", size = 1249963 }, { url = "https://files.pythonhosted.org/packages/44/b5/e099ad2bf7ad6ab5bb685f66a7599dc7f9fb4879eb987a4bf02ca2886974/aiohttp-3.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:27cf19a38506e2e9f12fc17e55f118f04897b0a78537055d93a9de4bf3022e3d", size = 1248579 }, { url = "https://files.pythonhosted.org/packages/85/81/520348e8ec472679e65deb87c2a2bb2ad2c40e328746245bd35251b7ee4f/aiohttp-3.10.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3468b39f977a11271517c6925b226720e148311039a380cc9117b1e2258a721f", size = 1293005 }, { url = "https://files.pythonhosted.org/packages/e5/a8/1ddd2af786c3b4f30187bc98464b8e3c54c6bbf18062a20291c6b5b03f27/aiohttp-3.10.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9d26da22a793dfd424be1050712a70c0afd96345245c29aced1e35dbace03413", size = 1319740 }, { url = "https://files.pythonhosted.org/packages/0a/6f/a757fdf01ce4d20fcfee35af3b63a2393dbd3478873c4ea9aaad24b093f1/aiohttp-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:844d48ff9173d0b941abed8b2ea6a412f82b56d9ab1edb918c74000c15839362", size = 1281177 }, { url = "https://files.pythonhosted.org/packages/9d/d9/e5866f341cfad4de82caf570218a424f96914192a9230dd6f6dfe4653a93/aiohttp-3.10.6-cp313-cp313-win32.whl", hash = "sha256:2dd56e3c43660ed3bea67fd4c5025f1ac1f9ecf6f0b991a6e5efe2e678c490c5", size = 357148 }, { url = "https://files.pythonhosted.org/packages/57/cc/ba781a170fd4405819cc988026cfa16a9397ffebf5639dc84ad65d518448/aiohttp-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:c91781d969fbced1993537f45efe1213bd6fccb4b37bfae2a026e20d6fbed206", size = 376413 }, { url = "https://files.pythonhosted.org/packages/e3/8c/09c36451df52c753e46be8a1d9533d61d19acdced8424e06575d41285e24/aiohttp-3.10.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5db26bbca8e7968c4c977a0c640e0b9ce7224e1f4dcafa57870dc6ee28e27de6", size = 588214 }, { url = "https://files.pythonhosted.org/packages/2c/90/2e5f130dbac00f615c99a041fbd0734f40d68f94f32e7e5bc74ac148e228/aiohttp-3.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3fb4216e3ec0dbc01db5ba802f02ed78ad8f07121be54eb9e918448cc3f61b7c", size = 399874 }, { url = "https://files.pythonhosted.org/packages/d3/de/b60c688d89c357b23084facc1602a23dcfac812d50175bdd6b0d941e8e08/aiohttp-3.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a976ef488f26e224079deb3d424f29144c6d5ba4ded313198169a8af8f47fb82", size = 391201 }, { url = "https://files.pythonhosted.org/packages/00/b8/a3559410e6fa6e96eec4623a517c84e6774576a276dad5380e1720871760/aiohttp-3.10.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a86610174de8a85a920e956e2d4f9945e7da89f29a00e95ac62a4a414c4ef4e", size = 1233301 }, { url = "https://files.pythonhosted.org/packages/72/cd/62c6c417bc5e49087ae7ae9f66f64c10df6601ead4d2646f5a4a7630ac30/aiohttp-3.10.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:217791c6a399cc4f2e6577bb44344cba1f5714a2aebf6a0bea04cfa956658284", size = 1270683 }, { url = "https://files.pythonhosted.org/packages/57/67/e6dc17dbdefb459ec3e5b6e8b3332f0e11683fac6fa7ac4b74335a9edc7a/aiohttp-3.10.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ba3662d41abe2eab0eeec7ee56f33ef4e0b34858f38abf24377687f9e1fb00a5", size = 1304500 }, { url = "https://files.pythonhosted.org/packages/d0/d3/553e55b6adc881e44e9024d92f9dd70c538d59a19d6a58cb715f0838ce24/aiohttp-3.10.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4dfa5ad4bce9ca30a76117fbaa1c1decf41ebb6c18a4e098df44298941566f9", size = 1225049 }, { url = "https://files.pythonhosted.org/packages/29/a1/f444b1c39039b9f020d02e871c5afd6e0eaeecf34bfcd47ef8f82408c1bf/aiohttp-3.10.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0009258e97502936d3bd5bf2ced15769629097d0abb81e6495fba1047824fe0", size = 1196214 }, { url = "https://files.pythonhosted.org/packages/3b/50/bab30b4bbe1ef7d66d97358129c34379039c69b2b528ff02804a42b0b4da/aiohttp-3.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0a75d5c9fb4f06c41d029ae70ad943c3a844c40c0a769d12be4b99b04f473d3d", size = 1196350 }, { url = "https://files.pythonhosted.org/packages/9b/8a/3731748b1080b2195268c85010727406ac3cee2fa878318d46de5614372f/aiohttp-3.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8198b7c002aae2b40b2d16bfe724b9a90bcbc9b78b2566fc96131ef4e382574d", size = 1196837 }, { url = "https://files.pythonhosted.org/packages/7c/3c/51f9dbdabcdacf54b9e9ec1af210509e1a7e262647a106f720ed683b35ee/aiohttp-3.10.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:4611db8c907f90fe86be112efdc2398cd7b4c8eeded5a4f0314b70fdea8feab0", size = 1250939 }, { url = "https://files.pythonhosted.org/packages/fd/51/e4fde27da37a28c5bdef08d9393115f062c2e198f720172b12bb53b6c4d4/aiohttp-3.10.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ff99ae06eef85c7a565854826114ced72765832ee16c7e3e766c5e4c5b98d20e", size = 1265712 }, { url = "https://files.pythonhosted.org/packages/1c/0d/b9c0d5ad9dc99cdfba665ba9ac6bd7aa9b97c866aef180477fabc54eaa56/aiohttp-3.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7641920bdcc7cd2d3ddfb8bb9133a6c9536b09dbd49490b79e125180b2d25b93", size = 1216963 }, { url = "https://files.pythonhosted.org/packages/83/3e/c9ad8da2750ad9014a3d00be4809d8b96991ebdc4903ab78c2793362e192/aiohttp-3.10.6-cp39-cp39-win32.whl", hash = "sha256:e2e7d5591ea868d5ec82b90bbeb366a198715672841d46281b623e23079593db", size = 362896 }, { url = "https://files.pythonhosted.org/packages/dc/b9/f952f6b156d01a04b6b110ba01f5fed975afdcfaca72ed4d07db964930ce/aiohttp-3.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:b504c08c45623bf5c7ca41be380156d925f00199b3970efd758aef4a77645feb", size = 381395 }, ] [[package]] name = "aioresponses" version = "0.7.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ff/63/bb78ed078e2d514050aadc42a932465a83c43c628746f0e788500ec0bf5d/aioresponses-0.7.6.tar.gz", hash = "sha256:f795d9dbda2d61774840e7e32f5366f45752d1adc1b74c9362afd017296c7ee1", size = 35846 } wheels = [ { url = "https://files.pythonhosted.org/packages/e4/1e/c259a960a4dff46840133ce19682ef14db2922da80a6088283ec9c3f647a/aioresponses-0.7.6-py2.py3-none-any.whl", hash = "sha256:d2c26defbb9b440ea2685ec132e90700907fd10bcca3e85ec2f157219f0d26f7", size = 11875 }, ] [[package]] name = "aiosignal" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } wheels = [ { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] [[package]] name = "alabaster" version = "0.7.16" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/3e/13dd8e5ed9094e734ac430b5d0eb4f2bb001708a8b7856cbf8e084e001ba/alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65", size = 23776 } wheels = [ { url = "https://files.pythonhosted.org/packages/32/34/d4e1c02d3bee589efb5dfa17f88ea08bdb3e3eac12bc475462aec52ed223/alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92", size = 13511 }, ] [[package]] name = "async-timeout" version = "4.0.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 }, ] [[package]] name = "attrs" version = "24.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } wheels = [ { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, ] [[package]] name = "babel" version = "2.16.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } wheels = [ { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, ] [[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 = "cffi" version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } wheels = [ { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, { url = "https://files.pythonhosted.org/packages/b9/ea/8bb50596b8ffbc49ddd7a1ad305035daa770202a6b782fc164647c2673ad/cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", size = 182220 }, { url = "https://files.pythonhosted.org/packages/ae/11/e77c8cd24f58285a82c23af484cf5b124a376b32644e445960d1a4654c3a/cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", size = 178605 }, { url = "https://files.pythonhosted.org/packages/ed/65/25a8dc32c53bf5b7b6c2686b42ae2ad58743f7ff644844af7cdb29b49361/cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", size = 424910 }, { url = "https://files.pythonhosted.org/packages/42/7a/9d086fab7c66bd7c4d0f27c57a1b6b068ced810afc498cc8c49e0088661c/cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", size = 447200 }, { url = "https://files.pythonhosted.org/packages/da/63/1785ced118ce92a993b0ec9e0d0ac8dc3e5dbfbcaa81135be56c69cabbb6/cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", size = 454565 }, { url = "https://files.pythonhosted.org/packages/74/06/90b8a44abf3556599cdec107f7290277ae8901a58f75e6fe8f970cd72418/cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", size = 435635 }, { url = "https://files.pythonhosted.org/packages/bd/62/a1f468e5708a70b1d86ead5bab5520861d9c7eacce4a885ded9faa7729c3/cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", size = 445218 }, { url = "https://files.pythonhosted.org/packages/5b/95/b34462f3ccb09c2594aa782d90a90b045de4ff1f70148ee79c69d37a0a5a/cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", size = 460486 }, { url = "https://files.pythonhosted.org/packages/fc/fc/a1e4bebd8d680febd29cf6c8a40067182b64f00c7d105f8f26b5bc54317b/cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", size = 437911 }, { url = "https://files.pythonhosted.org/packages/e6/c3/21cab7a6154b6a5ea330ae80de386e7665254835b9e98ecc1340b3a7de9a/cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", size = 460632 }, { url = "https://files.pythonhosted.org/packages/cb/b5/fd9f8b5a84010ca169ee49f4e4ad6f8c05f4e3545b72ee041dbbcb159882/cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", size = 171820 }, { url = "https://files.pythonhosted.org/packages/8c/52/b08750ce0bce45c143e1b5d7357ee8c55341b52bdef4b0f081af1eb248c2/cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", size = 181290 }, ] [[package]] name = "cfgv" version = "3.4.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } wheels = [ { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, ] [[package]] name = "charset-normalizer" version = "3.3.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/61/095a0aa1a84d1481998b534177c8566fdc50bb1233ea9a0478cd3cc075bd/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", size = 194219 }, { url = "https://files.pythonhosted.org/packages/cc/94/f7cf5e5134175de79ad2059edf2adce18e0685ebdb9227ff0139975d0e93/charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", size = 122521 }, { url = "https://files.pythonhosted.org/packages/46/6a/d5c26c41c49b546860cc1acabdddf48b0b3fb2685f4f5617ac59261b44ae/charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", size = 120383 }, { url = "https://files.pythonhosted.org/packages/b8/60/e2f67915a51be59d4539ed189eb0a2b0d292bf79270410746becb32bc2c3/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", size = 138223 }, { url = "https://files.pythonhosted.org/packages/05/8c/eb854996d5fef5e4f33ad56927ad053d04dc820e4a3d39023f35cad72617/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", size = 148101 }, { url = "https://files.pythonhosted.org/packages/f6/93/bb6cbeec3bf9da9b2eba458c15966658d1daa8b982c642f81c93ad9b40e1/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", size = 140699 }, { url = "https://files.pythonhosted.org/packages/da/f1/3702ba2a7470666a62fd81c58a4c40be00670e5006a67f4d626e57f013ae/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", size = 142065 }, { url = "https://files.pythonhosted.org/packages/3f/ba/3f5e7be00b215fa10e13d64b1f6237eb6ebea66676a41b2bcdd09fe74323/charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", size = 144505 }, { url = "https://files.pythonhosted.org/packages/33/c3/3b96a435c5109dd5b6adc8a59ba1d678b302a97938f032e3770cc84cd354/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", size = 139425 }, { url = "https://files.pythonhosted.org/packages/43/05/3bf613e719efe68fb3a77f9c536a389f35b95d75424b96b426a47a45ef1d/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", size = 145287 }, { url = "https://files.pythonhosted.org/packages/58/78/a0bc646900994df12e07b4ae5c713f2b3e5998f58b9d3720cce2aa45652f/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", size = 149929 }, { url = "https://files.pythonhosted.org/packages/eb/5c/97d97248af4920bc68687d9c3b3c0f47c910e21a8ff80af4565a576bd2f0/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", size = 141605 }, { url = "https://files.pythonhosted.org/packages/a8/31/47d018ef89f95b8aded95c589a77c072c55e94b50a41aa99c0a2008a45a4/charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", size = 142646 }, { url = "https://files.pythonhosted.org/packages/ae/d5/4fecf1d58bedb1340a50f165ba1c7ddc0400252d6832ff619c4568b36cc0/charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", size = 92846 }, { url = "https://files.pythonhosted.org/packages/a2/a0/4af29e22cb5942488cf45630cbdd7cefd908768e69bdd90280842e4e8529/charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", size = 100343 }, { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, { url = "https://files.pythonhosted.org/packages/f7/9d/bcf4a449a438ed6f19790eee543a86a740c77508fbc5ddab210ab3ba3a9a/charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", size = 194198 }, { url = "https://files.pythonhosted.org/packages/66/fe/c7d3da40a66a6bf2920cce0f436fa1f62ee28aaf92f412f0bf3b84c8ad6c/charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", size = 122494 }, { url = "https://files.pythonhosted.org/packages/2a/9d/a6d15bd1e3e2914af5955c8eb15f4071997e7078419328fee93dfd497eb7/charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", size = 120393 }, { url = "https://files.pythonhosted.org/packages/3d/85/5b7416b349609d20611a64718bed383b9251b5a601044550f0c8983b8900/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", size = 138331 }, { url = "https://files.pythonhosted.org/packages/79/66/8946baa705c588521afe10b2d7967300e49380ded089a62d38537264aece/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", size = 148097 }, { url = "https://files.pythonhosted.org/packages/44/80/b339237b4ce635b4af1c73742459eee5f97201bd92b2371c53e11958392e/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", size = 140711 }, { url = "https://files.pythonhosted.org/packages/98/69/5d8751b4b670d623aa7a47bef061d69c279e9f922f6705147983aa76c3ce/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", size = 142251 }, { url = "https://files.pythonhosted.org/packages/1f/8d/33c860a7032da5b93382cbe2873261f81467e7b37f4ed91e25fed62fd49b/charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", size = 144636 }, { url = "https://files.pythonhosted.org/packages/c2/65/52aaf47b3dd616c11a19b1052ce7fa6321250a7a0b975f48d8c366733b9f/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", size = 139514 }, { url = "https://files.pythonhosted.org/packages/51/fd/0ee5b1c2860bb3c60236d05b6e4ac240cf702b67471138571dad91bcfed8/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", size = 145528 }, { url = "https://files.pythonhosted.org/packages/e1/9c/60729bf15dc82e3aaf5f71e81686e42e50715a1399770bcde1a9e43d09db/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", size = 149804 }, { url = "https://files.pythonhosted.org/packages/53/cd/aa4b8a4d82eeceb872f83237b2d27e43e637cac9ffaef19a1321c3bafb67/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", size = 141708 }, { url = "https://files.pythonhosted.org/packages/54/7f/cad0b328759630814fcf9d804bfabaf47776816ad4ef2e9938b7e1123d04/charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561", size = 142708 }, { url = "https://files.pythonhosted.org/packages/c1/9d/254a2f1bcb0ce9acad838e94ed05ba71a7cb1e27affaa4d9e1ca3958cdb6/charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", size = 92830 }, { url = "https://files.pythonhosted.org/packages/2f/0e/d7303ccae9735ff8ff01e36705ad6233ad2002962e8668a970fc000c5e1b/charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", size = 100376 }, { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] [[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.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/61/eb7ce5ed62bacf21beca4937a90fe32545c91a3c8a42a30c6616d48fc70d/coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16", size = 206690 }, { url = "https://files.pythonhosted.org/packages/7d/73/041928e434442bd3afde5584bdc3f932fb4562b1597629f537387cec6f3d/coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36", size = 207127 }, { url = "https://files.pythonhosted.org/packages/c7/c8/6ca52b5147828e45ad0242388477fdb90df2c6cbb9a441701a12b3c71bc8/coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02", size = 235654 }, { url = "https://files.pythonhosted.org/packages/d5/da/9ac2b62557f4340270942011d6efeab9833648380109e897d48ab7c1035d/coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc", size = 233598 }, { url = "https://files.pythonhosted.org/packages/53/23/9e2c114d0178abc42b6d8d5281f651a8e6519abfa0ef460a00a91f80879d/coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23", size = 234732 }, { url = "https://files.pythonhosted.org/packages/0f/7e/a0230756fb133343a52716e8b855045f13342b70e48e8ad41d8a0d60ab98/coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34", size = 233816 }, { url = "https://files.pythonhosted.org/packages/28/7c/3753c8b40d232b1e5eeaed798c875537cf3cb183fb5041017c1fdb7ec14e/coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c", size = 232325 }, { url = "https://files.pythonhosted.org/packages/57/e3/818a2b2af5b7573b4b82cf3e9f137ab158c90ea750a8f053716a32f20f06/coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959", size = 233418 }, { url = "https://files.pythonhosted.org/packages/c8/fb/4532b0b0cefb3f06d201648715e03b0feb822907edab3935112b61b885e2/coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232", size = 209343 }, { url = "https://files.pythonhosted.org/packages/5a/25/af337cc7421eca1c187cc9c315f0a755d48e755d2853715bfe8c418a45fa/coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0", size = 210136 }, { url = "https://files.pythonhosted.org/packages/ad/5f/67af7d60d7e8ce61a4e2ddcd1bd5fb787180c8d0ae0fbd073f903b3dd95d/coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93", size = 206796 }, { url = "https://files.pythonhosted.org/packages/e1/0e/e52332389e057daa2e03be1fbfef25bb4d626b37d12ed42ae6281d0a274c/coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3", size = 207244 }, { url = "https://files.pythonhosted.org/packages/aa/cd/766b45fb6e090f20f8927d9c7cb34237d41c73a939358bc881883fd3a40d/coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff", size = 239279 }, { url = "https://files.pythonhosted.org/packages/70/6c/a9ccd6fe50ddaf13442a1e2dd519ca805cbe0f1fcd377fba6d8339b98ccb/coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d", size = 236859 }, { url = "https://files.pythonhosted.org/packages/14/6f/8351b465febb4dbc1ca9929505202db909c5a635c6fdf33e089bbc3d7d85/coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6", size = 238549 }, { url = "https://files.pythonhosted.org/packages/68/3c/289b81fa18ad72138e6d78c4c11a82b5378a312c0e467e2f6b495c260907/coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56", size = 237477 }, { url = "https://files.pythonhosted.org/packages/ed/1c/aa1efa6459d822bd72c4abc0b9418cf268de3f60eeccd65dc4988553bd8d/coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234", size = 236134 }, { url = "https://files.pythonhosted.org/packages/fb/c8/521c698f2d2796565fe9c789c2ee1ccdae610b3aa20b9b2ef980cc253640/coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133", size = 236910 }, { url = "https://files.pythonhosted.org/packages/7d/30/033e663399ff17dca90d793ee8a2ea2890e7fdf085da58d82468b4220bf7/coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c", size = 209348 }, { url = "https://files.pythonhosted.org/packages/20/05/0d1ccbb52727ccdadaa3ff37e4d2dc1cd4d47f0c3df9eb58d9ec8508ca88/coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6", size = 210230 }, { url = "https://files.pythonhosted.org/packages/7e/d4/300fc921dff243cd518c7db3a4c614b7e4b2431b0d1145c1e274fd99bd70/coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778", size = 206983 }, { url = "https://files.pythonhosted.org/packages/e1/ab/6bf00de5327ecb8db205f9ae596885417a31535eeda6e7b99463108782e1/coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391", size = 207221 }, { url = "https://files.pythonhosted.org/packages/92/8f/2ead05e735022d1a7f3a0a683ac7f737de14850395a826192f0288703472/coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8", size = 240342 }, { url = "https://files.pythonhosted.org/packages/0f/ef/94043e478201ffa85b8ae2d2c79b4081e5a1b73438aafafccf3e9bafb6b5/coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d", size = 237371 }, { url = "https://files.pythonhosted.org/packages/1f/0f/c890339dd605f3ebc269543247bdd43b703cce6825b5ed42ff5f2d6122c7/coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca", size = 239455 }, { url = "https://files.pythonhosted.org/packages/d1/04/7fd7b39ec7372a04efb0f70c70e35857a99b6a9188b5205efb4c77d6a57a/coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163", size = 238924 }, { url = "https://files.pythonhosted.org/packages/ed/bf/73ce346a9d32a09cf369f14d2a06651329c984e106f5992c89579d25b27e/coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a", size = 237252 }, { url = "https://files.pythonhosted.org/packages/86/74/1dc7a20969725e917b1e07fe71a955eb34bc606b938316bcc799f228374b/coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d", size = 238897 }, { url = "https://files.pythonhosted.org/packages/b6/e9/d9cc3deceb361c491b81005c668578b0dfa51eed02cd081620e9a62f24ec/coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5", size = 209606 }, { url = "https://files.pythonhosted.org/packages/47/c8/5a2e41922ea6740f77d555c4d47544acd7dc3f251fe14199c09c0f5958d3/coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb", size = 210373 }, { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, { url = "https://files.pythonhosted.org/packages/19/d3/d54c5aa83268779d54c86deb39c1c4566e5d45c155369ca152765f8db413/coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255", size = 206688 }, { url = "https://files.pythonhosted.org/packages/a5/fe/137d5dca72e4a258b1bc17bb04f2e0196898fe495843402ce826a7419fe3/coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8", size = 207120 }, { url = "https://files.pythonhosted.org/packages/78/5b/a0a796983f3201ff5485323b225d7c8b74ce30c11f456017e23d8e8d1945/coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2", size = 235249 }, { url = "https://files.pythonhosted.org/packages/4e/e1/76089d6a5ef9d68f018f65411fcdaaeb0141b504587b901d74e8587606ad/coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a", size = 233237 }, { url = "https://files.pythonhosted.org/packages/9a/6f/eef79b779a540326fee9520e5542a8b428cc3bfa8b7c8f1022c1ee4fc66c/coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc", size = 234311 }, { url = "https://files.pythonhosted.org/packages/75/e1/656d65fb126c29a494ef964005702b012f3498db1a30dd562958e85a4049/coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004", size = 233453 }, { url = "https://files.pythonhosted.org/packages/68/6a/45f108f137941a4a1238c85f28fd9d048cc46b5466d6b8dda3aba1bb9d4f/coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb", size = 231958 }, { url = "https://files.pythonhosted.org/packages/9b/e7/47b809099168b8b8c72ae311efc3e88c8d8a1162b3ba4b8da3cfcdb85743/coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36", size = 232938 }, { url = "https://files.pythonhosted.org/packages/52/80/052222ba7058071f905435bad0ba392cc12006380731c37afaf3fe749b88/coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c", size = 209352 }, { url = "https://files.pythonhosted.org/packages/b8/d8/1b92e0b3adcf384e98770a00ca095da1b5f7b483e6563ae4eb5e935d24a1/coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca", size = 210153 }, { url = "https://files.pythonhosted.org/packages/a5/2b/0354ed096bca64dc8e32a7cbcae28b34cb5ad0b1fe2125d6d99583313ac0/coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df", size = 198926 }, ] [package.optional-dependencies] toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] [[package]] name = "cryptography" version = "43.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } wheels = [ { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, { url = "https://files.pythonhosted.org/packages/18/23/4175dcd935e1649865e1af7bd0b827cc9d9769a586dcc84f7cbe96839086/cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034", size = 3152694 }, { url = "https://files.pythonhosted.org/packages/ea/45/967da50269954b993d4484bf85026c7377bd551651ebdabba94905972556/cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d", size = 3713077 }, { url = "https://files.pythonhosted.org/packages/df/e6/ccd29a1f9a6b71294e1e9f530c4d779d5dd37c8bb736c05d5fb6d98a971b/cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289", size = 3915597 }, { url = "https://files.pythonhosted.org/packages/a2/80/fb7d668f1be5e4443b7ac191f68390be24f7c2ebd36011741f62c7645eb2/cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84", size = 2989208 }, { url = "https://files.pythonhosted.org/packages/b2/aa/782e42ccf854943dfce72fb94a8d62220f22084ff07076a638bc3f34f3cc/cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365", size = 3154685 }, { url = "https://files.pythonhosted.org/packages/3e/fd/70f3e849ad4d6cca2118ee6938e0b52326d02406f10912356151dd4b6868/cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96", size = 3713909 }, { url = "https://files.pythonhosted.org/packages/21/b0/4ecefa99519eaa32af49a3ad002bb3e795f9e6eb32221fd87736247fa3cb/cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172", size = 3916544 }, { url = "https://files.pythonhosted.org/packages/8c/42/2948dd87b237565c77b28b674d972c7f983ffa3977dc8b8ad0736f6a7d97/cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2", size = 2989774 }, ] [[package]] name = "distlib" version = "0.3.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c4/91/e2df406fb4efacdf46871c25cde65d3c6ee5e173b7e5a4547a47bae91920/distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64", size = 609931 } wheels = [ { url = "https://files.pythonhosted.org/packages/8e/41/9307e4f5f9976bc8b7fea0b66367734e8faf3ec84bc0d412d8cfabbb66cd/distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", size = 468850 }, ] [[package]] name = "docutils" version = "0.18.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/57/b1/b880503681ea1b64df05106fc7e3c4e3801736cf63deffc6fa7fc5404cf5/docutils-0.18.1.tar.gz", hash = "sha256:679987caf361a7539d76e584cbeddc311e3aee937877c87346f31debc63e9d06", size = 2043249 } wheels = [ { url = "https://files.pythonhosted.org/packages/8d/14/69b4bad34e3f250afe29a854da03acb6747711f3df06c359fa053fae4e76/docutils-0.18.1-py2.py3-none-any.whl", hash = "sha256:23010f129180089fbcd3bc08cfefccb3b890b0050e1ca00c867036e9d161b98c", size = 570050 }, ] [[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 = "filelock" version = "3.16.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/9d/db/3ef5bb276dae18d6ec2124224403d1d67bccdbefc17af4cc8f553e341ab1/filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435", size = 18037 } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 }, ] [[package]] name = "firebase-messaging" version = "0.4.4" source = { editable = "." } dependencies = [ { name = "aiohttp" }, { name = "cryptography" }, { name = "http-ece" }, { name = "protobuf" }, ] [package.optional-dependencies] docs = [ { name = "myst-parser" }, { name = "sphinx" }, { name = "sphinx-autodoc-typehints" }, { name = "sphinx-rtd-theme" }, ] [package.dev-dependencies] dev = [ { name = "aioresponses" }, { name = "async-timeout" }, { name = "mypy" }, { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-mock" }, { name = "pytest-socket" }, { name = "ruff" }, { name = "types-protobuf" }, ] [package.metadata] requires-dist = [ { name = "aiohttp", specifier = ">=3.9.3" }, { name = "cryptography", specifier = ">=2.5" }, { name = "http-ece", specifier = "~=1.1.0" }, { name = "myst-parser", marker = "extra == 'docs'" }, { name = "protobuf", specifier = ">=4.24.3,<6" }, { name = "sphinx", marker = "extra == 'docs'", specifier = "==7.1.2" }, { name = "sphinx-autodoc-typehints", marker = "extra == 'docs'", specifier = "~=1.24" }, { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = "~=1.3" }, ] [package.metadata.requires-dev] dev = [ { name = "aioresponses", specifier = "~=0.7.6" }, { name = "async-timeout", specifier = ">=3.0.0" }, { name = "mypy", specifier = "~=1.0" }, { name = "pre-commit" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-cov" }, { name = "pytest-mock" }, { name = "pytest-socket", specifier = "~=0.7.0" }, { name = "ruff", specifier = ">=0.6.8" }, { name = "types-protobuf", specifier = ">=4.24" }, ] [[package]] name = "frozenlist" version = "1.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/cf/3d/2102257e7acad73efc4a0c306ad3953f68c504c16982bbdfee3ad75d8085/frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", size = 37820 } wheels = [ { url = "https://files.pythonhosted.org/packages/7a/35/1328c7b0f780d34f8afc1d87ebdc2bb065a123b24766a0b475f0d67da637/frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac", size = 94315 }, { url = "https://files.pythonhosted.org/packages/f4/d6/ca016b0adcf8327714ccef969740688808c86e0287bf3a639ff582f24e82/frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868", size = 53805 }, { url = "https://files.pythonhosted.org/packages/ae/83/bcdaa437a9bd693ba658a0310f8cdccff26bd78e45fccf8e49897904a5cd/frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776", size = 52163 }, { url = "https://files.pythonhosted.org/packages/d4/e9/759043ab7d169b74fe05ebfbfa9ee5c881c303ebc838e308346204309cd0/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a", size = 238595 }, { url = "https://files.pythonhosted.org/packages/f8/ce/b9de7dc61e753dc318cf0de862181b484178210c5361eae6eaf06792264d/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad", size = 262428 }, { url = "https://files.pythonhosted.org/packages/36/ce/dc6f29e0352fa34ebe45421960c8e7352ca63b31630a576e8ffb381e9c08/frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c", size = 258867 }, { url = "https://files.pythonhosted.org/packages/51/47/159ac53faf8a11ae5ee8bb9db10327575557504e549cfd76f447b969aa91/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe", size = 229412 }, { url = "https://files.pythonhosted.org/packages/ec/25/0c87df2e53c0c5d90f7517ca0ff7aca78d050a8ec4d32c4278e8c0e52e51/frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a", size = 239539 }, { url = "https://files.pythonhosted.org/packages/97/94/a1305fa4716726ae0abf3b1069c2d922fcfd442538cb850f1be543f58766/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98", size = 253379 }, { url = "https://files.pythonhosted.org/packages/53/82/274e19f122e124aee6d113188615f63b0736b4242a875f482a81f91e07e2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75", size = 245901 }, { url = "https://files.pythonhosted.org/packages/b8/28/899931015b8cffbe155392fe9ca663f981a17e1adc69589ee0e1e7cdc9a2/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5", size = 263797 }, { url = "https://files.pythonhosted.org/packages/6e/4f/b8a5a2f10c4a58c52a52a40cf6cf1ffcdbf3a3b64f276f41dab989bf3ab5/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950", size = 264415 }, { url = "https://files.pythonhosted.org/packages/b0/2c/7be3bdc59dbae444864dbd9cde82790314390ec54636baf6b9ce212627ad/frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc", size = 253964 }, { url = "https://files.pythonhosted.org/packages/2e/ec/4fb5a88f6b9a352aed45ab824dd7ce4801b7bcd379adcb927c17a8f0a1a8/frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1", size = 44559 }, { url = "https://files.pythonhosted.org/packages/61/15/2b5d644d81282f00b61e54f7b00a96f9c40224107282efe4cd9d2bf1433a/frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439", size = 50434 }, { url = "https://files.pythonhosted.org/packages/01/bc/8d33f2d84b9368da83e69e42720cff01c5e199b5a868ba4486189a4d8fa9/frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", size = 97060 }, { url = "https://files.pythonhosted.org/packages/af/b2/904500d6a162b98a70e510e743e7ea992241b4f9add2c8063bf666ca21df/frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", size = 55347 }, { url = "https://files.pythonhosted.org/packages/5b/9c/f12b69997d3891ddc0d7895999a00b0c6a67f66f79498c0e30f27876435d/frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", size = 53374 }, { url = "https://files.pythonhosted.org/packages/ac/6e/e0322317b7c600ba21dec224498c0c5959b2bce3865277a7c0badae340a9/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", size = 273288 }, { url = "https://files.pythonhosted.org/packages/a7/76/180ee1b021568dad5b35b7678616c24519af130ed3fa1e0f1ed4014e0f93/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", size = 284737 }, { url = "https://files.pythonhosted.org/packages/05/08/40159d706a6ed983c8aca51922a93fc69f3c27909e82c537dd4054032674/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", size = 280267 }, { url = "https://files.pythonhosted.org/packages/e0/18/9f09f84934c2b2aa37d539a322267939770362d5495f37783440ca9c1b74/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", size = 258778 }, { url = "https://files.pythonhosted.org/packages/b3/c9/0bc5ee7e1f5cc7358ab67da0b7dfe60fbd05c254cea5c6108e7d1ae28c63/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", size = 272276 }, { url = "https://files.pythonhosted.org/packages/12/5d/147556b73a53ad4df6da8bbb50715a66ac75c491fdedac3eca8b0b915345/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", size = 272424 }, { url = "https://files.pythonhosted.org/packages/83/61/2087bbf24070b66090c0af922685f1d0596c24bb3f3b5223625bdeaf03ca/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", size = 260881 }, { url = "https://files.pythonhosted.org/packages/a8/be/a235bc937dd803258a370fe21b5aa2dd3e7bfe0287a186a4bec30c6cccd6/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", size = 282327 }, { url = "https://files.pythonhosted.org/packages/5d/e7/b2469e71f082948066b9382c7b908c22552cc705b960363c390d2e23f587/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74", size = 281502 }, { url = "https://files.pythonhosted.org/packages/db/1b/6a5b970e55dffc1a7d0bb54f57b184b2a2a2ad0b7bca16a97ca26d73c5b5/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", size = 272292 }, { url = "https://files.pythonhosted.org/packages/1a/05/ebad68130e6b6eb9b287dacad08ea357c33849c74550c015b355b75cc714/frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", size = 44446 }, { url = "https://files.pythonhosted.org/packages/b3/21/c5aaffac47fd305d69df46cfbf118768cdf049a92ee6b0b5cb029d449dcf/frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", size = 50459 }, { url = "https://files.pythonhosted.org/packages/b4/db/4cf37556a735bcdb2582f2c3fa286aefde2322f92d3141e087b8aeb27177/frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", size = 93937 }, { url = "https://files.pythonhosted.org/packages/46/03/69eb64642ca8c05f30aa5931d6c55e50b43d0cd13256fdd01510a1f85221/frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", size = 53656 }, { url = "https://files.pythonhosted.org/packages/3f/ab/c543c13824a615955f57e082c8a5ee122d2d5368e80084f2834e6f4feced/frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", size = 51868 }, { url = "https://files.pythonhosted.org/packages/a9/b8/438cfd92be2a124da8259b13409224d9b19ef8f5a5b2507174fc7e7ea18f/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", size = 280652 }, { url = "https://files.pythonhosted.org/packages/54/72/716a955521b97a25d48315c6c3653f981041ce7a17ff79f701298195bca3/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", size = 286739 }, { url = "https://files.pythonhosted.org/packages/65/d8/934c08103637567084568e4d5b4219c1016c60b4d29353b1a5b3587827d6/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", size = 289447 }, { url = "https://files.pythonhosted.org/packages/70/bb/d3b98d83ec6ef88f9bd63d77104a305d68a146fd63a683569ea44c3085f6/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", size = 265466 }, { url = "https://files.pythonhosted.org/packages/0b/f2/b8158a0f06faefec33f4dff6345a575c18095a44e52d4f10c678c137d0e0/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", size = 281530 }, { url = "https://files.pythonhosted.org/packages/ea/a2/20882c251e61be653764038ece62029bfb34bd5b842724fff32a5b7a2894/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", size = 281295 }, { url = "https://files.pythonhosted.org/packages/4c/f9/8894c05dc927af2a09663bdf31914d4fb5501653f240a5bbaf1e88cab1d3/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", size = 268054 }, { url = "https://files.pythonhosted.org/packages/37/ff/a613e58452b60166507d731812f3be253eb1229808e59980f0405d1eafbf/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", size = 286904 }, { url = "https://files.pythonhosted.org/packages/cc/6e/0091d785187f4c2020d5245796d04213f2261ad097e0c1cf35c44317d517/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", size = 290754 }, { url = "https://files.pythonhosted.org/packages/a5/c2/e42ad54bae8bcffee22d1e12a8ee6c7717f7d5b5019261a8c861854f4776/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", size = 282602 }, { url = "https://files.pythonhosted.org/packages/b6/61/56bad8cb94f0357c4bc134acc30822e90e203b5cb8ff82179947de90c17f/frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", size = 44063 }, { url = "https://files.pythonhosted.org/packages/3e/dc/96647994a013bc72f3d453abab18340b7f5e222b7b7291e3697ca1fcfbd5/frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", size = 50452 }, { url = "https://files.pythonhosted.org/packages/d3/fb/6f2a22086065bc16797f77168728f0e59d5b89be76dd184e06b404f1e43b/frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e", size = 97291 }, { url = "https://files.pythonhosted.org/packages/4d/23/7f01123d0e5adcc65cbbde5731378237dea7db467abd19e391f1ddd4130d/frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d", size = 55249 }, { url = "https://files.pythonhosted.org/packages/8b/c9/a81e9af48291954a883d35686f32308238dc968043143133b8ac9e2772af/frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8", size = 53676 }, { url = "https://files.pythonhosted.org/packages/57/15/172af60c7e150a1d88ecc832f2590721166ae41eab582172fe1e9844eab4/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0", size = 239365 }, { url = "https://files.pythonhosted.org/packages/8c/a4/3dc43e259960ad268ef8f2bf92912c2d2cd2e5275a4838804e03fd6f085f/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b", size = 265592 }, { url = "https://files.pythonhosted.org/packages/a0/c1/458cf031fc8cd29a751e305b1ec773785ce486106451c93986562c62a21e/frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0", size = 261274 }, { url = "https://files.pythonhosted.org/packages/4a/32/21329084b61a119ecce0b2942d30312a34a7a0dccd01dcf7b40bda80f22c/frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897", size = 230787 }, { url = "https://files.pythonhosted.org/packages/70/b0/6f1ebdabfb604e39a0f84428986b89ab55f246b64cddaa495f2c953e1f6b/frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7", size = 240674 }, { url = "https://files.pythonhosted.org/packages/a3/05/50c53f1cdbfdf3d2cb9582a4ea5e12cd939ce33bd84403e6d07744563486/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742", size = 255712 }, { url = "https://files.pythonhosted.org/packages/b8/3d/cbc6f057f7d10efb7f1f410e458ac090f30526fd110ed2b29bb56ec38fe1/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea", size = 247618 }, { url = "https://files.pythonhosted.org/packages/96/86/d5e9cd583aed98c9ee35a3aac2ce4d022ce9de93518e963aadf34a18143b/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5", size = 266868 }, { url = "https://files.pythonhosted.org/packages/0f/6e/542af762beb9113f13614a590cafe661e0e060cddddee6107c8833605776/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9", size = 266439 }, { url = "https://files.pythonhosted.org/packages/ea/db/8b611e23fda75da5311b698730a598df54cfe6236678001f449b1dedb241/frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6", size = 256677 }, { url = "https://files.pythonhosted.org/packages/eb/06/732cefc0c46c638e4426a859a372a50e4c9d62e65dbfa7ddcf0b13e6a4f2/frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932", size = 44825 }, { url = "https://files.pythonhosted.org/packages/29/eb/2110c4be2f622e87864e433efd7c4ee6e4f8a59ff2a93c1aa426ee50a8b8/frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0", size = 50652 }, { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] [[package]] name = "http-ece" version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/1a/60ccc29fccd4789b7cada188b114185e8a5d63aba0d93262adbbe776cfe5/http_ece-1.1.0.tar.gz", hash = "sha256:932ebc2fa7c216954c320a188ae9c1f04d01e67bec9cdce1bfbc912813b0b4f8", size = 4902 } [[package]] name = "identify" version = "2.6.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/29/bb/25024dbcc93516c492b75919e76f389bac754a3e4248682fba32b250c880/identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98", size = 99097 } wheels = [ { url = "https://files.pythonhosted.org/packages/7d/0c/4ef72754c050979fdcc06c744715ae70ea37e734816bb6514f79df77a42f/identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", size = 98972 }, ] [[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 = "imagesize" version = "1.4.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } wheels = [ { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, ] [[package]] name = "importlib-metadata" version = "8.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7", size = 55304 } wheels = [ { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, ] [[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 = "jinja2" version = "3.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } wheels = [ { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, ] [[package]] name = "markdown-it-py" version = "3.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] [[package]] name = "markupsafe" version = "2.1.5" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } wheels = [ { url = "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", size = 18206 }, { url = "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", size = 14079 }, { url = "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", size = 26620 }, { url = "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", size = 25818 }, { url = "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", size = 25493 }, { url = "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", size = 30630 }, { url = "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", size = 29745 }, { url = "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", size = 30021 }, { url = "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", size = 16659 }, { url = "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", size = 17213 }, { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219 }, { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098 }, { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014 }, { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220 }, { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756 }, { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988 }, { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718 }, { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317 }, { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670 }, { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224 }, { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215 }, { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069 }, { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452 }, { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462 }, { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869 }, { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906 }, { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296 }, { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, { url = "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", size = 18193 }, { url = "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", size = 14073 }, { url = "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", size = 26486 }, { url = "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", size = 25685 }, { url = "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", size = 25338 }, { url = "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", size = 30439 }, { url = "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", size = 29531 }, { url = "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", size = 29823 }, { url = "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", size = 16658 }, { url = "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", size = 17211 }, ] [[package]] name = "mdit-py-plugins" version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] [[package]] name = "multidict" version = "6.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } wheels = [ { url = "https://files.pythonhosted.org/packages/29/68/259dee7fd14cf56a17c554125e534f6274c2860159692a414d0b402b9a6d/multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", size = 48628 }, { url = "https://files.pythonhosted.org/packages/50/79/53ba256069fe5386a4a9e80d4e12857ced9de295baf3e20c68cdda746e04/multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", size = 29327 }, { url = "https://files.pythonhosted.org/packages/ff/10/71f1379b05b196dae749b5ac062e87273e3f11634f447ebac12a571d90ae/multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", size = 29689 }, { url = "https://files.pythonhosted.org/packages/71/45/70bac4f87438ded36ad4793793c0095de6572d433d98575a5752629ef549/multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", size = 126639 }, { url = "https://files.pythonhosted.org/packages/80/cf/17f35b3b9509b4959303c05379c4bfb0d7dd05c3306039fc79cf035bbac0/multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", size = 134315 }, { url = "https://files.pythonhosted.org/packages/ef/1f/652d70ab5effb33c031510a3503d4d6efc5ec93153562f1ee0acdc895a57/multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", size = 129471 }, { url = "https://files.pythonhosted.org/packages/a6/64/2dd6c4c681688c0165dea3975a6a4eab4944ea30f35000f8b8af1df3148c/multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", size = 124585 }, { url = "https://files.pythonhosted.org/packages/87/56/e6ee5459894c7e554b57ba88f7257dc3c3d2d379cb15baaa1e265b8c6165/multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", size = 116957 }, { url = "https://files.pythonhosted.org/packages/36/9e/616ce5e8d375c24b84f14fc263c7ef1d8d5e8ef529dbc0f1df8ce71bb5b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db", size = 128609 }, { url = "https://files.pythonhosted.org/packages/8c/4f/4783e48a38495d000f2124020dc96bacc806a4340345211b1ab6175a6cb4/multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", size = 123016 }, { url = "https://files.pythonhosted.org/packages/3e/b3/4950551ab8fc39862ba5e9907dc821f896aa829b4524b4deefd3e12945ab/multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", size = 133542 }, { url = "https://files.pythonhosted.org/packages/96/4d/f0ce6ac9914168a2a71df117935bb1f1781916acdecbb43285e225b484b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", size = 130163 }, { url = "https://files.pythonhosted.org/packages/be/72/17c9f67e7542a49dd252c5ae50248607dfb780bcc03035907dafefb067e3/multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", size = 126832 }, { url = "https://files.pythonhosted.org/packages/71/9f/72d719e248cbd755c8736c6d14780533a1606ffb3fbb0fbd77da9f0372da/multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", size = 26402 }, { url = "https://files.pythonhosted.org/packages/04/5a/d88cd5d00a184e1ddffc82aa2e6e915164a6d2641ed3606e766b5d2f275a/multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", size = 28800 }, { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, { url = "https://files.pythonhosted.org/packages/e7/c9/9e153a6572b38ac5ff4434113af38acf8d5e9957897cdb1f513b3d6614ed/multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c", size = 48550 }, { url = "https://files.pythonhosted.org/packages/76/f5/79565ddb629eba6c7f704f09a09df085c8dc04643b12506f10f718cee37a/multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1", size = 29298 }, { url = "https://files.pythonhosted.org/packages/60/1b/9851878b704bc98e641a3e0bce49382ae9e05743dac6d97748feb5b7baba/multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c", size = 29641 }, { url = "https://files.pythonhosted.org/packages/89/87/d451d45aab9e422cb0fb2f7720c31a4c1d3012c740483c37f642eba568fb/multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c", size = 126202 }, { url = "https://files.pythonhosted.org/packages/fa/b4/27cbe9f3e2e469359887653f2e45470272eef7295139916cc21107c6b48c/multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f", size = 133925 }, { url = "https://files.pythonhosted.org/packages/4d/a3/afc841899face8adfd004235ce759a37619f6ec99eafd959650c5ce4df57/multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875", size = 129039 }, { url = "https://files.pythonhosted.org/packages/5e/41/0d0fb18c1ad574f807196f5f3d99164edf9de3e169a58c6dc2d6ed5742b9/multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255", size = 124072 }, { url = "https://files.pythonhosted.org/packages/00/22/defd7a2e71a44e6e5b9a5428f972e5b572e7fe28e404dfa6519bbf057c93/multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30", size = 116532 }, { url = "https://files.pythonhosted.org/packages/91/25/f7545102def0b1d456ab6449388eed2dfd822debba1d65af60194904a23a/multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057", size = 128173 }, { url = "https://files.pythonhosted.org/packages/45/79/3dbe8d35fc99f5ea610813a72ab55f426cb9cf482f860fa8496e5409be11/multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657", size = 122654 }, { url = "https://files.pythonhosted.org/packages/97/cb/209e735eeab96e1b160825b5d0b36c56d3862abff828fc43999bb957dcad/multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28", size = 133197 }, { url = "https://files.pythonhosted.org/packages/e4/3a/a13808a7ada62808afccea67837a79d00ad6581440015ef00f726d064c2d/multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972", size = 129754 }, { url = "https://files.pythonhosted.org/packages/77/dd/8540e139eafb240079242da8f8ffdf9d3f4b4ad1aac5a786cd4050923783/multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43", size = 126402 }, { url = "https://files.pythonhosted.org/packages/86/99/e82e1a275d8b1ea16d3a251474262258dbbe41c05cce0c01bceda1fc8ea5/multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada", size = 26421 }, { url = "https://files.pythonhosted.org/packages/86/1c/9fa630272355af7e4446a2c7550c259f11ee422ab2d30ff90a0a71cf3d9e/multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a", size = 28791 }, { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, ] [[package]] name = "mypy" version = "1.11.2" 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/5c/86/5d7cbc4974fd564550b80fbb8103c05501ea11aa7835edf3351d90095896/mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79", size = 3078806 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/cd/815368cd83c3a31873e5e55b317551500b12f2d1d7549720632f32630333/mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a", size = 10939401 }, { url = "https://files.pythonhosted.org/packages/f1/27/e18c93a195d2fad75eb96e1f1cbc431842c332e8eba2e2b77eaf7313c6b7/mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef", size = 10111697 }, { url = "https://files.pythonhosted.org/packages/dc/08/cdc1fc6d0d5a67d354741344cc4aa7d53f7128902ebcbe699ddd4f15a61c/mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383", size = 12500508 }, { url = "https://files.pythonhosted.org/packages/64/12/aad3af008c92c2d5d0720ea3b6674ba94a98cdb86888d389acdb5f218c30/mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8", size = 13020712 }, { url = "https://files.pythonhosted.org/packages/03/e6/a7d97cc124a565be5e9b7d5c2a6ebf082379ffba99646e4863ed5bbcb3c3/mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7", size = 9567319 }, { url = "https://files.pythonhosted.org/packages/e2/aa/cc56fb53ebe14c64f1fe91d32d838d6f4db948b9494e200d2f61b820b85d/mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385", size = 10859630 }, { url = "https://files.pythonhosted.org/packages/04/c8/b19a760fab491c22c51975cf74e3d253b8c8ce2be7afaa2490fbf95a8c59/mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca", size = 10037973 }, { url = "https://files.pythonhosted.org/packages/88/57/7e7e39f2619c8f74a22efb9a4c4eff32b09d3798335625a124436d121d89/mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104", size = 12416659 }, { url = "https://files.pythonhosted.org/packages/fc/a6/37f7544666b63a27e46c48f49caeee388bf3ce95f9c570eb5cfba5234405/mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4", size = 12897010 }, { url = "https://files.pythonhosted.org/packages/84/8b/459a513badc4d34acb31c736a0101c22d2bd0697b969796ad93294165cfb/mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6", size = 9562873 }, { url = "https://files.pythonhosted.org/packages/35/3a/ed7b12ecc3f6db2f664ccf85cb2e004d3e90bec928e9d7be6aa2f16b7cdf/mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318", size = 10990335 }, { url = "https://files.pythonhosted.org/packages/04/e4/1a9051e2ef10296d206519f1df13d2cc896aea39e8683302f89bf5792a59/mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36", size = 10007119 }, { url = "https://files.pythonhosted.org/packages/f3/3c/350a9da895f8a7e87ade0028b962be0252d152e0c2fbaafa6f0658b4d0d4/mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987", size = 12506856 }, { url = "https://files.pythonhosted.org/packages/b6/49/ee5adf6a49ff13f4202d949544d3d08abb0ea1f3e7f2a6d5b4c10ba0360a/mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca", size = 12952066 }, { url = "https://files.pythonhosted.org/packages/27/c0/b19d709a42b24004d720db37446a42abadf844d5c46a2c442e2a074d70d9/mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70", size = 9664000 }, { url = "https://files.pythonhosted.org/packages/16/64/bb5ed751487e2bea0dfaa6f640a7e3bb88083648f522e766d5ef4a76f578/mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6", size = 10937294 }, { url = "https://files.pythonhosted.org/packages/a9/a3/67a0069abed93c3bf3b0bebb8857e2979a02828a4a3fd82f107f8f1143e8/mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70", size = 10107707 }, { url = "https://files.pythonhosted.org/packages/2f/4d/0379daf4258b454b1f9ed589a9dabd072c17f97496daea7b72fdacf7c248/mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d", size = 12498367 }, { url = "https://files.pythonhosted.org/packages/3b/dc/3976a988c280b3571b8eb6928882dc4b723a403b21735a6d8ae6ed20e82b/mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d", size = 13018014 }, { url = "https://files.pythonhosted.org/packages/83/84/adffc7138fb970e7e2a167bd20b33bb78958370179853a4ebe9008139342/mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24", size = 9568056 }, { url = "https://files.pythonhosted.org/packages/42/3a/bdf730640ac523229dd6578e8a581795720a9321399de494374afc437ec5/mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12", size = 2619625 }, ] [[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 = "myst-parser" version = "3.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "jinja2" }, { name = "markdown-it-py" }, { name = "mdit-py-plugins" }, { name = "pyyaml" }, { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/64/e2f13dac02f599980798c01156393b781aec983b52a6e4057ee58f07c43a/myst_parser-3.0.1.tar.gz", hash = "sha256:88f0cb406cb363b077d176b51c476f62d60604d68a8dcdf4832e080441301a87", size = 92392 } wheels = [ { url = "https://files.pythonhosted.org/packages/e2/de/21aa8394f16add8f7427f0a1326ccd2b3a2a8a3245c9252bc5ac034c6155/myst_parser-3.0.1-py3-none-any.whl", hash = "sha256:6457aaa33a5d474aca678b8ead9b3dc298e89c68e67012e73146ea6fd54babf1", size = 83163 }, ] [[package]] name = "nodeenv" version = "1.9.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, ] [[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 = "platformdirs" version = "4.3.6" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, ] [[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 = "pre-commit" version = "3.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, { name = "identify" }, { name = "nodeenv" }, { name = "pyyaml" }, { name = "virtualenv" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 } wheels = [ { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643 }, ] [[package]] name = "protobuf" version = "5.28.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b1/a4/4579a61de526e19005ceeb93e478b61d77aa38c8a85ad958ff16a9906549/protobuf-5.28.2.tar.gz", hash = "sha256:59379674ff119717404f7454647913787034f03fe7049cbef1d74a97bb4593f0", size = 422494 } wheels = [ { url = "https://files.pythonhosted.org/packages/e9/30/231764750e0987755b7b8d66771f161e5f002e165d27b72154c776dbabf7/protobuf-5.28.2-cp310-abi3-win32.whl", hash = "sha256:eeea10f3dc0ac7e6b4933d32db20662902b4ab81bf28df12218aa389e9c2102d", size = 419662 }, { url = "https://files.pythonhosted.org/packages/7d/46/3fdf7462160135aee6a530f1ec66665b5b4132fa2e1002ab971bc6ec2589/protobuf-5.28.2-cp310-abi3-win_amd64.whl", hash = "sha256:2c69461a7fcc8e24be697624c09a839976d82ae75062b11a0972e41fd2cd9132", size = 431479 }, { url = "https://files.pythonhosted.org/packages/37/45/d2a760580f8f2ed2825ba44cb370e0a4011ddef85e728f46ea3dd565a8a5/protobuf-5.28.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:a8b9403fc70764b08d2f593ce44f1d2920c5077bf7d311fefec999f8c40f78b7", size = 414736 }, { url = "https://files.pythonhosted.org/packages/e6/23/ed718dc18e6a561445ece1e7a17d2dda0c634ad9cf663102b47f10005d8f/protobuf-5.28.2-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:35cfcb15f213449af7ff6198d6eb5f739c37d7e4f1c09b5d0641babf2cc0c68f", size = 316518 }, { url = "https://files.pythonhosted.org/packages/23/08/a1ce0415a115c2b703bfa798f06f0e43ca91dbe29d6180bf86a9287b15e2/protobuf-5.28.2-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:5e8a95246d581eef20471b5d5ba010d55f66740942b95ba9b872d918c459452f", size = 316605 }, { url = "https://files.pythonhosted.org/packages/2d/27/d10aaae326ffd446893d4d1ef18e22c4ece87eb4273ee560ce4e616f0959/protobuf-5.28.2-cp39-cp39-win32.whl", hash = "sha256:ca53faf29896c526863366a52a8f4d88e69cd04ec9571ed6082fa117fac3ab36", size = 419587 }, { url = "https://files.pythonhosted.org/packages/94/12/af94b0654fa6bde64272b2abab39b221544c32e9e911284745569f65e73a/protobuf-5.28.2-cp39-cp39-win_amd64.whl", hash = "sha256:8ddc60bf374785fb7cb12510b267f59067fa10087325b8e1855b898a0d81d276", size = 431552 }, { url = "https://files.pythonhosted.org/packages/9b/55/f24e3b801d2e108c48aa2b1b59bb791b5cffba89465cbbf66fc98de89270/protobuf-5.28.2-py3-none-any.whl", hash = "sha256:52235802093bd8a2811abbe8bf0ab9c5f54cca0a751fdd3f6ac2a21438bffece", size = 169566 }, ] [[package]] name = "pycparser" version = "2.22" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } wheels = [ { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, ] [[package]] name = "pygments" version = "2.18.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } wheels = [ { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, ] [[package]] name = "pytest" version = "8.3.3" 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/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, ] [[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 = "5.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "coverage", extra = ["toml"] }, { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } wheels = [ { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, ] [[package]] name = "pytest-mock" version = "3.14.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 } wheels = [ { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 }, ] [[package]] name = "pytest-socket" version = "0.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] sdist = { url = "https://files.pythonhosted.org/packages/05/ff/90c7e1e746baf3d62ce864c479fd53410b534818b9437413903596f81580/pytest_socket-0.7.0.tar.gz", hash = "sha256:71ab048cbbcb085c15a4423b73b619a8b35d6a307f46f78ea46be51b1b7e11b3", size = 12389 } wheels = [ { url = "https://files.pythonhosted.org/packages/19/58/5d14cb5cb59409e491ebe816c47bf81423cd03098ea92281336320ae5681/pytest_socket-0.7.0-py3-none-any.whl", hash = "sha256:7e0f4642177d55d317bbd58fc68c6bd9048d6eadb2d46a89307fa9221336ce45", size = 6754 }, ] [[package]] name = "pyyaml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, { url = "https://files.pythonhosted.org/packages/65/d8/b7a1db13636d7fb7d4ff431593c510c8b8fca920ade06ca8ef20015493c5/PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", size = 184777 }, { url = "https://files.pythonhosted.org/packages/0a/02/6ec546cd45143fdf9840b2c6be8d875116a64076218b61d68e12548e5839/PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", size = 172318 }, { url = "https://files.pythonhosted.org/packages/0e/9a/8cc68be846c972bda34f6c2a93abb644fb2476f4dcc924d52175786932c9/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", size = 720891 }, { url = "https://files.pythonhosted.org/packages/e9/6c/6e1b7f40181bc4805e2e07f4abc10a88ce4648e7e95ff1abe4ae4014a9b2/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", size = 722614 }, { url = "https://files.pythonhosted.org/packages/3d/32/e7bd8535d22ea2874cef6a81021ba019474ace0d13a4819c2a4bce79bd6a/PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", size = 737360 }, { url = "https://files.pythonhosted.org/packages/d7/12/7322c1e30b9be969670b672573d45479edef72c9a0deac3bb2868f5d7469/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", size = 699006 }, { url = "https://files.pythonhosted.org/packages/82/72/04fcad41ca56491995076630c3ec1e834be241664c0c09a64c9a2589b507/PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", size = 723577 }, { url = "https://files.pythonhosted.org/packages/ed/5e/46168b1f2757f1fcd442bc3029cd8767d88a98c9c05770d8b420948743bb/PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", size = 144593 }, { url = "https://files.pythonhosted.org/packages/19/87/5124b1c1f2412bb95c59ec481eaf936cd32f0fe2a7b16b97b81c4c017a6a/PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", size = 162312 }, ] [[package]] name = "requests" version = "2.32.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, { name = "idna" }, { name = "urllib3" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } wheels = [ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, ] [[package]] name = "ruff" version = "0.6.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/74/f9/4ce3e765a72ab8fe0f80f48508ea38b4196daab3da14d803c21349b2d367/ruff-0.6.8.tar.gz", hash = "sha256:a5bf44b1aa0adaf6d9d20f86162b34f7c593bfedabc51239953e446aefc8ce18", size = 3084543 } wheels = [ { url = "https://files.pythonhosted.org/packages/db/07/42ee57e8b76ca585297a663a552b4f6d6a99372ca47fdc2276ef72cc0f2f/ruff-0.6.8-py3-none-linux_armv6l.whl", hash = "sha256:77944bca110ff0a43b768f05a529fecd0706aac7bcce36d7f1eeb4cbfca5f0f2", size = 10404327 }, { url = "https://files.pythonhosted.org/packages/eb/51/d42571ff8156d65086acb72d39aa64cb24181db53b497d0ed6293f43f07a/ruff-0.6.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:27b87e1801e786cd6ede4ada3faa5e254ce774de835e6723fd94551464c56b8c", size = 10018797 }, { url = "https://files.pythonhosted.org/packages/c1/d7/fa5514a60b03976af972b67fe345deb0335dc96b9f9a9fa4df9890472427/ruff-0.6.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:cd48f945da2a6334f1793d7f701725a76ba93bf3d73c36f6b21fb04d5338dcf5", size = 9691303 }, { url = "https://files.pythonhosted.org/packages/d6/c4/d812a74976927e51d0782a47539069657ac78535779bfa4d061c4fc8d89d/ruff-0.6.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:677e03c00f37c66cea033274295a983c7c546edea5043d0c798833adf4cf4c6f", size = 10719452 }, { url = "https://files.pythonhosted.org/packages/ec/b6/aa700c4ae6db9b3ee660e23f3c7db596e2b16a3034b797704fba33ddbc96/ruff-0.6.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f1476236b3eacfacfc0f66aa9e6cd39f2a624cb73ea99189556015f27c0bdeb", size = 10161353 }, { url = "https://files.pythonhosted.org/packages/ea/39/0b10075ffcd52ff3a581b9b69eac53579deb230aad300ce8f9d0b58e77bc/ruff-0.6.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f5a2f17c7d32991169195d52a04c95b256378bbf0de8cb98478351eb70d526f", size = 10980630 }, { url = "https://files.pythonhosted.org/packages/c1/af/9eb9efc98334f62652e2f9318f137b2667187851911fac3b395365a83708/ruff-0.6.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5fd0d4b7b1457c49e435ee1e437900ced9b35cb8dc5178921dfb7d98d65a08d0", size = 11768996 }, { url = "https://files.pythonhosted.org/packages/e0/59/8b1369cf7878358952b1c0a1559b4d6b5c824c003d09b0db26d26c9d094f/ruff-0.6.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8034b19b993e9601f2ddf2c517451e17a6ab5cdb1c13fdff50c1442a7171d87", size = 11317469 }, { url = "https://files.pythonhosted.org/packages/b9/6d/e252e9b11bbca4114c386ee41ad559d0dac13246201d77ea1223c6fea17f/ruff-0.6.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6cfb227b932ba8ef6e56c9f875d987973cd5e35bc5d05f5abf045af78ad8e098", size = 12467185 }, { url = "https://files.pythonhosted.org/packages/48/44/7caa223af7d4ea0f0b2bd34acca65a7694a58317714675a2478815ab3f45/ruff-0.6.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef0411eccfc3909269fed47c61ffebdcb84a04504bafa6b6df9b85c27e813b0", size = 10887766 }, { url = "https://files.pythonhosted.org/packages/81/ed/394aff3a785f171869158b9d5be61eec9ffb823c3ad5d2bdf2e5f13cb029/ruff-0.6.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:007dee844738c3d2e6c24ab5bc7d43c99ba3e1943bd2d95d598582e9c1b27750", size = 10711609 }, { url = "https://files.pythonhosted.org/packages/47/31/f31d04c842e54699eab7e3b864538fea26e6c94b71806cd10aa49f13e1c1/ruff-0.6.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:ce60058d3cdd8490e5e5471ef086b3f1e90ab872b548814e35930e21d848c9ce", size = 10237621 }, { url = "https://files.pythonhosted.org/packages/20/95/a764e84acf11d425f2f23b8b78b4fd715e9c20be4aac157c6414ca859a67/ruff-0.6.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1085c455d1b3fdb8021ad534379c60353b81ba079712bce7a900e834859182fa", size = 10558329 }, { url = "https://files.pythonhosted.org/packages/2a/76/d4e38846ac9f6dd62dce858a54583911361b5339dcf8f84419241efac93a/ruff-0.6.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:70edf6a93b19481affd287d696d9e311388d808671bc209fb8907b46a8c3af44", size = 10954102 }, { url = "https://files.pythonhosted.org/packages/e7/36/f18c678da6c69f8d022480f3e8ddce6e4a52e07602c1d212056fbd234f8f/ruff-0.6.8-py3-none-win32.whl", hash = "sha256:792213f7be25316f9b46b854df80a77e0da87ec66691e8f012f887b4a671ab5a", size = 8511090 }, { url = "https://files.pythonhosted.org/packages/4c/c4/0ca7d8ffa358b109db7d7d045a1a076fd8e5d9cbeae022242d3c060931da/ruff-0.6.8-py3-none-win_amd64.whl", hash = "sha256:ec0517dc0f37cad14a5319ba7bba6e7e339d03fbf967a6d69b0907d61be7a263", size = 9350079 }, { url = "https://files.pythonhosted.org/packages/d9/bd/a8b0c64945a92eaeeb8d0283f27a726a776a1c9d12734d990c5fc7a1278c/ruff-0.6.8-py3-none-win_arm64.whl", hash = "sha256:8d3bb2e3fbb9875172119021a13eed38849e762499e3cfde9588e4b4d70968dc", size = 8669595 }, ] [[package]] name = "snowballstemmer" version = "2.2.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } wheels = [ { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, ] [[package]] name = "sphinx" version = "7.1.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "alabaster" }, { name = "babel" }, { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "docutils" }, { name = "imagesize" }, { name = "importlib-metadata", marker = "python_full_version < '3.10'" }, { name = "jinja2" }, { name = "packaging" }, { name = "pygments" }, { name = "requests" }, { name = "snowballstemmer" }, { name = "sphinxcontrib-applehelp" }, { name = "sphinxcontrib-devhelp" }, { name = "sphinxcontrib-htmlhelp" }, { name = "sphinxcontrib-jsmath" }, { name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-serializinghtml" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/01/688bdf9282241dca09fe6e3a1110eda399fa9b10d0672db609e37c2e7a39/sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f", size = 6828258 } wheels = [ { url = "https://files.pythonhosted.org/packages/48/17/325cf6a257d84751a48ae90752b3d8fe0be8f9535b6253add61c49d0d9bc/sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe", size = 3169543 }, ] [[package]] name = "sphinx-autodoc-typehints" version = "1.25.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/19/1131e37f815864efbdb6498cc41f5ce3da82b7e952456900968132c7dcba/sphinx_autodoc_typehints-1.25.3.tar.gz", hash = "sha256:70db10b391acf4e772019765991d2de0ff30ec0899b9ba137706dc0b3c4835e0", size = 37709 } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/d3/8c375e2a6ce21c29021d413e5ebb4d285431acd209f82b89101f157d4b9b/sphinx_autodoc_typehints-1.25.3-py3-none-any.whl", hash = "sha256:d3da7fa9a9761eff6ff09f8b1956ae3090a2d4f4ad54aebcade8e458d6340835", size = 19239 }, ] [[package]] name = "sphinx-rtd-theme" version = "1.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "docutils" }, { name = "sphinx" }, { name = "sphinxcontrib-jquery" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/3e/477c5b3ed78b6818d673f63512db12ace8c89e83eb9eecc913f9e2cc8416/sphinx_rtd_theme-1.3.0.tar.gz", hash = "sha256:590b030c7abb9cf038ec053b95e5380b5c70d61591eb0b552063fbe7c41f0931", size = 2785069 } wheels = [ { url = "https://files.pythonhosted.org/packages/18/01/76f40a18e9209bb098c1c1313c823dbbd001b23a2db71e7fd4eb5a48559c/sphinx_rtd_theme-1.3.0-py2.py3-none-any.whl", hash = "sha256:46ddef89cc2416a81ecfbeaceab1881948c014b1b6e4450b815311a89fb977b0", size = 2824803 }, ] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } wheels = [ { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, ] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } wheels = [ { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, ] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } wheels = [ { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, ] [[package]] name = "sphinxcontrib-jquery" version = "4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sphinx" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 } wheels = [ { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 }, ] [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } wheels = [ { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, ] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } wheels = [ { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, ] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, ] [[package]] name = "tomli" version = "2.0.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c0/3f/d7af728f075fb08564c5949a9c95e44352e23dee646869fa104a3b2060a3/tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f", size = 15164 } wheels = [ { url = "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", size = 12757 }, ] [[package]] name = "types-protobuf" version = "5.28.0.20240924" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/90/c3/217fe2c6a4b8ed75c5ecbd27ae8dedd7bc8e8728ac4b29d16005d3a3aba2/types-protobuf-5.28.0.20240924.tar.gz", hash = "sha256:d181af8a256e5a91ce8d5adb53496e880efd9144c7d54483e3653332b60296f0", size = 54324 } wheels = [ { url = "https://files.pythonhosted.org/packages/61/2b/98bfe67a73b15964513b471ce10b610ab0df28825900e0e7517b2bf23952/types_protobuf-5.28.0.20240924-py3-none-any.whl", hash = "sha256:5cecf612ccdefb7dc95f7a51fb502902f20fc2e6681cd500184aaa1b3931d6a7", size = 68761 }, ] [[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 = "urllib3" version = "2.2.3" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } wheels = [ { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, ] [[package]] name = "virtualenv" version = "20.26.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bf/4c/66ce54c8736ff164e85117ca36b02a1e14c042a6963f85eeda82664fda4e/virtualenv-20.26.5.tar.gz", hash = "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4", size = 9371932 } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/1d/e1a44fdd6d30829ba21fc58b5d98a67e7aae8f4165f11d091e53aec12560/virtualenv-20.26.5-py3-none-any.whl", hash = "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6", size = 5999288 }, ] [[package]] name = "yarl" version = "1.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, ] sdist = { url = "https://files.pythonhosted.org/packages/27/6e/b26e831b6abede32fba3763131eb2c52987f574277daa65e10a5fda6021c/yarl-1.13.0.tar.gz", hash = "sha256:02f117a63d11c8c2ada229029f8bb444a811e62e5041da962de548f26ac2c40f", size = 165688 } wheels = [ { url = "https://files.pythonhosted.org/packages/9b/e8/5eb11fc80f93aadb4da491bff2f8ad8fced64fd4415dd4ecd32252fe3c12/yarl-1.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:66c028066be36d54e7a0a38e832302b23222e75db7e65ed862dc94effc8ef062", size = 189620 }, { url = "https://files.pythonhosted.org/packages/ee/93/bd1545ff3d1d2087ac769d5b4b03204b03591136409e5188b73a5689f575/yarl-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:517f9d90ca0224bb7002266eba6e70d8fcc8b1d0c9321de2407e41344413ed46", size = 115525 }, { url = "https://files.pythonhosted.org/packages/50/a1/9cf139b0e89c1a8deed77b5d40b998bee707b0e53629487f2c34348a72f4/yarl-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5378cb60f4209505f6aa60423c174336bd7b22e0d8beb87a2a99ad50787f1341", size = 113695 }, { url = "https://files.pythonhosted.org/packages/e4/3f/45a2ed60a32db65cf6d3dcdc3b37c235f44728a1d49d4fc14a16ac1e0a0e/yarl-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0675a9cf65176e11692b20a516d5f744849251aa24024f422582d2d1bf7c8c82", size = 443623 }, { url = "https://files.pythonhosted.org/packages/f2/48/1321e9c514e798c89446b1ff6867e8cc6285ce014a4dac6de68de04fd71a/yarl-1.13.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:419c22b419034b4ee3ba1c27cbbfef01ca8d646f9292f614f008093143334cdc", size = 469118 }, { url = "https://files.pythonhosted.org/packages/a0/d4/2e401fc232de4dc566b02e6c19cb043b33ecd249663f6ace3654f484dc4e/yarl-1.13.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf10e525e461f43831d82149d904f35929d89f3ccd65beaf7422aecd500dd39", size = 463210 }, { url = "https://files.pythonhosted.org/packages/e8/98/cb9082e0270f47678ac155f41fa1f0a1b607181bcb923dacd542595c6520/yarl-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d78ebad57152d301284761b03a708aeac99c946a64ba967d47cbcc040e36688b", size = 447903 }, { url = "https://files.pythonhosted.org/packages/ad/bd/371a1824a185923b3829cb3f50328012269d86b3a17644e9a0b36e3ea0d5/yarl-1.13.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e480a12cec58009eeaeee7f48728dc8f629f8e0f280d84957d42c361969d84da", size = 432828 }, { url = "https://files.pythonhosted.org/packages/28/6a/f5b6cbf40012974cf86c1174d23cae0cadc0bf78ead244222cb5f22f3bec/yarl-1.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e5462756fb34c884ca9d4875b6d2ec80957a767123151c467c97a9b423617048", size = 444771 }, { url = "https://files.pythonhosted.org/packages/3b/34/370e8ce2763c4d2328ee12a0b0ada01d480ad1f9f6019489cf36dfe98595/yarl-1.13.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bff0d468664cdf7b2a6bfd5e17d4a7025edb52df12e0e6e17223387b421d425c", size = 449360 }, { url = "https://files.pythonhosted.org/packages/06/70/5d565edeb49ea5321a5cdf95824ba61b02802e0e082b9e36f10ef849ac5e/yarl-1.13.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ffd8a9758b5df7401a49d50e76491f4c582cf7350365439563062cdff45bf16", size = 472735 }, { url = "https://files.pythonhosted.org/packages/82/c1/9b65e5771ddff3838241f6c9b1dcd65620d6a218fad9a4aeb62a99867a16/yarl-1.13.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ca71238af0d247d07747cb7202a9359e6e1d6d9e277041e1ad2d9f36b3a111a6", size = 470916 }, { url = "https://files.pythonhosted.org/packages/e6/2f/d9f7a79cb1d079d947f1202d778f75063102146c7b06597c168d8dcb063a/yarl-1.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fda4404bbb6f91e327827f4483d52fe24f02f92de91217954cf51b1cb9ee9c41", size = 458737 }, { url = "https://files.pythonhosted.org/packages/59/d6/08ec9b926e6a6254ed1b6178817193c5a93d43ba01888df037c3470b3973/yarl-1.13.0-cp310-cp310-win32.whl", hash = "sha256:e557e2681b47a0ecfdfbea44743b3184d94d31d5ce0e4b13ff64ce227a40f86e", size = 102349 }, { url = "https://files.pythonhosted.org/packages/6b/9a/2980744994bbbf3a04c3b487044978a9c174367ca9a81c676ced01f5b12f/yarl-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:3590ed9c7477059aea067a58ec87b433bbd47a2ceb67703b1098cca1ba075f0d", size = 111343 }, { url = "https://files.pythonhosted.org/packages/d5/78/59418fa1cc0ef69cef153b4e6163b1a3850d129a45b92aad8f9d244ac879/yarl-1.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8986fa2be78193dc8b8c27bd0d3667fe612f7232844872714c4200499d5225ca", size = 189559 }, { url = "https://files.pythonhosted.org/packages/9a/41/af4aa6046a4da16b32768bd788ac331c8397ac264b336ed5695c591f198b/yarl-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0db15ce35dfd100bc9ab40173f143fbea26c84d7458d63206934fe5548fae25d", size = 115451 }, { url = "https://files.pythonhosted.org/packages/8a/50/1496bff64799e82c06852d5b60d29d9d60d4c4fdebf8f5b1fae505d1a10a/yarl-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:49bee8c99586482a238a7b2ec0ef94e5f186bfdbb8204d14a3dd31867b3875ce", size = 113706 }, { url = "https://files.pythonhosted.org/packages/ff/17/a68f080c08edb27b8b5a62d418ed9ba1d90242af6792c6c2138180923265/yarl-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c73e0f8375b75806b8771890580566a2e6135e6785250840c4f6c45b69eb72d", size = 486063 }, { url = "https://files.pythonhosted.org/packages/ed/2e/fce9be4ff0df5a112e9007e587acee326ec89b98286fba221e8337e969fe/yarl-1.13.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ab16c9e94726fdfcbf5b37a641c9d9d0b35cc31f286a2c3b9cad6451cb53b2b", size = 505935 }, { url = "https://files.pythonhosted.org/packages/f0/c9/a797a46a28c2d68a600ec02c601014cd545a2ca33db34d1b8fc0ae854396/yarl-1.13.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:784d6e50ea96b3bbb078eb7b40d8c0e3674c2f12da4f0061f889b2cfdbab8f37", size = 500357 }, { url = "https://files.pythonhosted.org/packages/33/64/9ff1dd2c6acffd739adca70d6b16b059aea2a4ba750c4444aa5d59197e26/yarl-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:580fdb2ea48a40bcaa709ee0dc71f64e7a8f23b44356cc18cd9ce55dc3bc3212", size = 488873 }, { url = "https://files.pythonhosted.org/packages/5a/d1/a9c696e15311f2b32028f8ff3b447c8334316a6029d30d13f73a081517a4/yarl-1.13.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9d2845f1a37438a8e11e4fcbbf6ffd64bc94dc9cb8c815f72d0eb6f6c622deb0", size = 471532 }, { url = "https://files.pythonhosted.org/packages/d2/ca/accf33604a178cf785c71c8cce9956f37638e2e72cea23543fe4adaa9595/yarl-1.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bcb374db7a609484941c01380c1450728ec84d9c3e68cd9a5feaecb52626c4be", size = 485599 }, { url = "https://files.pythonhosted.org/packages/ff/25/d92abf667d068103b912a56b39d889615a8b07fb8d9ae922cf8fdbe52ede/yarl-1.13.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:561a5f6c054927cf5a993dd7b032aeebc10644419e65db7dd6bdc0b848806e65", size = 483480 }, { url = "https://files.pythonhosted.org/packages/ef/94/8a058039537682febfda57fb5d333f8bf7237dad5eab9323f5380325308a/yarl-1.13.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b536c2ac042add7f276d4e5857b08364fc32f28e02add153f6f214de50f12d07", size = 514004 }, { url = "https://files.pythonhosted.org/packages/8c/ed/8253a619335c6a692f909b6406e1764369733eed5af3991bbb91bf4a3b24/yarl-1.13.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:52b7bb09bb48f7855d574480e2efc0c30d31cab4e6ffc6203e2f7ffbf2e4496a", size = 516259 }, { url = "https://files.pythonhosted.org/packages/e2/17/e8ec3b51d5d02a768a75d6aee5edb8e303483fe3d0bf1f49c1dacf48fe47/yarl-1.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e4dddf99a853b3f60f3ce6363fb1ad94606113743cf653f116a38edd839a4461", size = 498386 }, { url = "https://files.pythonhosted.org/packages/df/09/2c631d07df653b53c4880416ceb138e1ed7d079329430ef5bc363f02e8c4/yarl-1.13.0-cp311-cp311-win32.whl", hash = "sha256:0b489858642e4e92203941a8fdeeb6373c0535aa986200b22f84d4b39cd602ba", size = 102394 }, { url = "https://files.pythonhosted.org/packages/df/a0/362619ab4141c2229eb43fa0a62447b14845a4ea50e362a40fd7c934c4aa/yarl-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:31748bee7078db26008bf94d39693c682a26b5c3a80a67194a4c9c8fe3b5cf47", size = 111636 }, { url = "https://files.pythonhosted.org/packages/11/21/09da58324fca4a9b6ff5710109bd26217b40dee9e6729adb3786e82831c7/yarl-1.13.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3a9b2650425b2ab9cc68865978963601b3c2414e1d94ef04f193dd5865e1bd79", size = 190212 }, { url = "https://files.pythonhosted.org/packages/83/9d/3a703336f3b8bbb907ad12bc46fe1f4b795e924b7b923dbcf604212ac3e1/yarl-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:73777f145cd591e1377bf8d8a97e5f8e39c9742ad0f100c898bba1f963aef662", size = 116036 }, { url = "https://files.pythonhosted.org/packages/42/06/bb53625353041364ba2a8a0ca6bbfe2dafcfeec846d038f44d20746ebc70/yarl-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:144b9e9164f21da81731c970dbda52245b343c0f67f3609d71013dd4d0db9ebf", size = 113890 }, { url = "https://files.pythonhosted.org/packages/4b/1f/e4c00883ea4debfd34b1c812887f897760c5bdb49de7fc4862df12d2599b/yarl-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3628e4e572b1db95285a72c4be102356f2dfc6214d9f126de975fd51b517ae55", size = 483935 }, { url = "https://files.pythonhosted.org/packages/af/93/7ff1c47e5530d79b2e1dc55a38641b079361c7cf5fa754bc50250ca15445/yarl-1.13.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0bd3caf554a52da78ec08415ebedeb6b9636436ca2afda9b5b9ff4a533478940", size = 499696 }, { url = "https://files.pythonhosted.org/packages/ee/ad/a2d9a167460b2043123fc1aeef908131f8d47aa939a0563e4ae44015cb89/yarl-1.13.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d7a44ae252efb0fcd79ac0997416721a44345f53e5aec4a24f489d983aa00e3", size = 497233 }, { url = "https://files.pythonhosted.org/packages/5f/6f/0fc937394438542790290416a69bd26e4c91d5cb16d2288ef03518f5ec81/yarl-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b78a1f57780eeeb17f5e1be851ab9fa951b98811e1bb4b5a53f74eec3e2666", size = 490132 }, { url = "https://files.pythonhosted.org/packages/e5/d0/a7b4e6af60aba824cc8528e870fc41bb84f59fa5e6eecde5fb9908d1793c/yarl-1.13.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79de5f8432b53d1261d92761f71dfab5fc7e1c75faa12a3535c27e681dacfa9d", size = 469328 }, { url = "https://files.pythonhosted.org/packages/db/95/3ed41ceaf3bc6ce48eacc0313054223436b4cf66c825f92d5cb806a1b37f/yarl-1.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f603216d62e9680bfac7fb168ef9673fd98abbb50c43e73d97615dfa1afebf57", size = 485630 }, { url = "https://files.pythonhosted.org/packages/37/9c/b0ae1c3253c9b910abd5c20d4ee4f15b547fea61eaef6ae9f5b9e1b7bf0d/yarl-1.13.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:acf27399c94270103d68f86118a183008d601e4c2c3a7e98dcde0e3b0163132f", size = 485996 }, { url = "https://files.pythonhosted.org/packages/7e/23/51879b22108fa24ea5b9f96a225016f73a8b148bdd70adad510a5536abe5/yarl-1.13.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:08037790f973367431b9406a7b9d940e872cca12e081bce3b7cea068daf81f0a", size = 506685 }, { url = "https://files.pythonhosted.org/packages/f5/ed/2e3034d7adb7fdeb6b64789d3e92408a45db5ca31e707dd2114758e8f7d9/yarl-1.13.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33e2f5ef965e69a1f2a1b0071a70c4616157da5a5478f3c2f6e185e06c56a322", size = 516992 }, { url = "https://files.pythonhosted.org/packages/1d/7d/b091b5b444d522f80a5cd54208cf20a99aa7450a3218afc83f6f4a1001ca/yarl-1.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:38a3b742c923fe2cab7d2e2c67220d17da8d0433e8bfe038356167e697ef5524", size = 502349 }, { url = "https://files.pythonhosted.org/packages/99/ce/e4e14c485086be114ddfdc11b192190a6f0d680d26d66929da42ca51b5bd/yarl-1.13.0-cp312-cp312-win32.whl", hash = "sha256:ab3ee57b25ce15f79ade27b7dfb5e678af26e4b93be5a4e22655acd9d40b81ba", size = 102301 }, { url = "https://files.pythonhosted.org/packages/72/2f/d5657e841b51e1855a752cb6cea5c7e266e2e61d8784e8bf6d241ae38b39/yarl-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:26214b0a9b8f4b7b04e67eee94a82c9b4e5c721f4d1ce7e8c87c78f0809b7684", size = 111676 }, { url = "https://files.pythonhosted.org/packages/3c/9d/62e0325479f6e225c006db065b81d92a214e15dbd9d5f08b7f58cbea2a1d/yarl-1.13.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:91251614cca1ba4ab0507f1ba5f5a44e17a5e9a4c7f0308ea441a994bdac3fc7", size = 186212 }, { url = "https://files.pythonhosted.org/packages/33/e6/216ca46bb456cc6942f0098abb67b192c52733292d37cb4f230889c8c826/yarl-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe6946c3cbcfbed67c5e50dae49baff82ad054aaa10ff7a4db8dfac646b7b479", size = 114218 }, { url = "https://files.pythonhosted.org/packages/c4/9d/1e937ba8820129effa4fcb8d7188e990711d73f6eaff0888a9205e33cecd/yarl-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:de97ee57e00a82ebb8c378fc73c5d9a773e4c2cec8079ff34ebfef61c8ba5b11", size = 112118 }, { url = "https://files.pythonhosted.org/packages/62/19/9f60d2c8bfd9820708268c4466e4d52d64b6ecec26557a26d9a7c3d60991/yarl-1.13.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1129737da2291c9952a93c015e73583dd66054f3ae991c8674f6e39c46d95dd3", size = 471387 }, { url = "https://files.pythonhosted.org/packages/4c/a9/d6936a780b35a202a9eb93905d283da4243fcfca85f464571d7ce6f5759e/yarl-1.13.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37049eb26d637a5b2f00562f65aad679f5d231c4c044edcd88320542ad66a2d9", size = 485837 }, { url = "https://files.pythonhosted.org/packages/f1/62/1903cb89c2b069c985fb0577a152652b80a8700b6f96a72c2b127c00cac3/yarl-1.13.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d15aff3477fecb7a469d1fdf5939a686fbc5a16858022897d3e9fc99301f19", size = 486662 }, { url = "https://files.pythonhosted.org/packages/ea/70/17a1092eec93b9b2ca2fe7e9c854b52f968a5457a16c0192cb1684f666e9/yarl-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa187a8599e0425f26b25987d884a8b67deb5565f1c450c3a6e8d3de2cdc8715", size = 478867 }, { url = "https://files.pythonhosted.org/packages/3e/ab/20d8b6ff384b126e2aca1546b8ba93e4a4aee35cfa68043b8015cf2fb309/yarl-1.13.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d95fcc9508390db73a0f1c7e78d9a1b1a3532a3f34ceff97c0b3b04140fbe6e4", size = 456455 }, { url = "https://files.pythonhosted.org/packages/6a/31/66bebe242af5f0615b2a6f7ae9ac37633983c621eb333367830500f8f954/yarl-1.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d04ea92a3643a9bb28aa6954fff718342caab2cc3d25d0160fe16e26c4a9acb7", size = 474964 }, { url = "https://files.pythonhosted.org/packages/69/02/67d94189a94d191edf47b8a34721e0e7265556e821e9bb2f856da7f8af39/yarl-1.13.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2842a89b697d8ca3dda6a25b4e4d835d14afe25a315c8a79dbdf5f70edfd0960", size = 477474 }, { url = "https://files.pythonhosted.org/packages/60/33/a746b05fedc340e8055d38b3f892418577252b1dbd6be474faebe1ceb9f3/yarl-1.13.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db463fce425f935eee04a9182c74fdf9ed90d3bd2079d4a17f8fb7a2d7c11009", size = 491950 }, { url = "https://files.pythonhosted.org/packages/5b/75/9759d92dc66108264f305f1ddb3ae02bcc247849a6673ebb678a082d398e/yarl-1.13.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3ff602aa84420b301c083ae7f07df858ae8e371bf3be294397bda3e0b27c6290", size = 502141 }, { url = "https://files.pythonhosted.org/packages/e8/8d/4d9f6fa810eca7e07ae7bc6eea0136a4268a32439e6ce6e7454470c51dac/yarl-1.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a9a1a600e8449f3a24bc7dca513be8d69db173fe842e8332a7318b5b8757a6af", size = 492846 }, { url = "https://files.pythonhosted.org/packages/77/b1/da12907ccb4cea4781357ec027e81e141251726aeffa6ea2c8d1f62cc117/yarl-1.13.0-cp313-cp313-win32.whl", hash = "sha256:5540b4896b244a6539f22b613b32b5d1b737e08011aa4ed56644cb0519d687df", size = 486417 }, { url = "https://files.pythonhosted.org/packages/66/9e/05d133e7523035517e0dc912a59779dcfd5e978aff32c1c2a3cbc1fd4e7c/yarl-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:08a3b0b8d10092dade46424fe775f2c9bc32e5a985fdd6afe410fe28598db6b2", size = 493756 }, { url = "https://files.pythonhosted.org/packages/47/44/3b6725635d226feb5e0263716a05186657afb548e7ef7ac1e11c0e255b9a/yarl-1.13.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:92abbe37e3fb08935e0e95ac5f83f7b286a6f2575f542225ec7afde405ed1fa1", size = 192323 }, { url = "https://files.pythonhosted.org/packages/82/d7/d03fef722c92b07f9b91832a55e7fa624ec8dbc1700f146168461d0be425/yarl-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1932c7bfa537f89ad5ca3d1e7e05de3388bb9e893230a384159fb974f6e9f90c", size = 117070 }, { url = "https://files.pythonhosted.org/packages/4a/52/19eef59dde0dc4e6bc73376dca047757cd6b39872b9fba690fbf33dc1fc2/yarl-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4483680e129b2a4250be20947b554cd5f7140fa9e5a1e4f1f42717cf91f8676a", size = 114997 }, { url = "https://files.pythonhosted.org/packages/c7/f0/830618cabed258962ca81325f41216cb99ece2297d5c1744b5f3f7acfbea/yarl-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f6f4a352d0beea5dd39315ab16fc26f0122d13457a7e65ad4f06c7961dcf87a", size = 450259 }, { url = "https://files.pythonhosted.org/packages/70/30/18c2a2ec41d2af39e99b7589b019622d2c4abf1f7e44fff5455ebcf6925f/yarl-1.13.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a67f20e97462dee8a89e9b997a78932959d2ed991e8f709514cb4160143e7b1", size = 477472 }, { url = "https://files.pythonhosted.org/packages/11/cf/ce66ab9a022d824592e387b63d18b3fc19ba31731187201ae4b4ef2e199c/yarl-1.13.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf4f3a87bd52f8f33b0155cd0f6f22bdf2092d88c6c6acbb1aee3bc206ecbe35", size = 470167 }, { url = "https://files.pythonhosted.org/packages/bd/7c/a7c60205831a8bb3dcafe350650936e69c01b45575c8d971e835a10ae585/yarl-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:deb70c006be548076d628630aad9a3ef3a1b2c28aaa14b395cf0939b9124252e", size = 455050 }, { url = "https://files.pythonhosted.org/packages/0b/88/b5d1013311f2f0552b7186033fa02eb14501c87f55c042f15b0267382f0c/yarl-1.13.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf7a9b31729b97985d4a796808859dfd0e37b55f1ca948d46a568e56e51dd8fb", size = 439771 }, { url = "https://files.pythonhosted.org/packages/c3/f8/83ea7ef4f67ab9f930440bca4f9ea84f3f616876d3589df3e546b3fc2a14/yarl-1.13.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d807417ceebafb7ce18085a1205d28e8fcb1435a43197d7aa3fab98f5bfec5ef", size = 452000 }, { url = "https://files.pythonhosted.org/packages/23/f2/dc0d49343fa4d0bedd06df4f6665c8438e49108ba3b443d1e245d779750b/yarl-1.13.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9671d0d65f86e0a0eee59c5b05e381c44e3d15c36c2a67da247d5d82875b4e4e", size = 455543 }, { url = "https://files.pythonhosted.org/packages/06/40/b9dc6e2da5ff8c07470b4f8643589c9d55381900c317f4a1dfc67e269a47/yarl-1.13.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:13a9cd39e47ca4dc25139d3c63fe0dc6acf1b24f9d94d3b5197ac578fbfd84bf", size = 481106 }, { url = "https://files.pythonhosted.org/packages/90/27/6e6c709ee54374494b8580c26ca3daac6039ba6c7f1b12214d99cf16fabc/yarl-1.13.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:acf8c219a59df22609cfaff4a7158a0946f273e3b03a5385f1fdd502496f0cff", size = 478299 }, { url = "https://files.pythonhosted.org/packages/da/f3/62bdf7d9fbddbf13cc99c1d941b1687d2890034160cbf76dc6579ab62416/yarl-1.13.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:12c92576633027f297c26e52aba89f6363b460f483d85cf7c14216eb55d06d02", size = 466354 }, { url = "https://files.pythonhosted.org/packages/42/e2/56a217a01e2ea0f963fe4a4af68c9af745a090d999704a677a5fe9f5403e/yarl-1.13.0-cp39-cp39-win32.whl", hash = "sha256:c2518660bd8166e770b76ce92514b491b8720ae7e7f5f975cd888b1592894d2c", size = 103369 }, { url = "https://files.pythonhosted.org/packages/46/91/e3ea08a1770f7ba9822e391f1561d6505c4a7e313c3ea8ec65f26182ab93/yarl-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:db90702060b1cdb7c7609d04df5f68a12fd5581d013ad379e58e0c2e651d92b8", size = 112502 }, { url = "https://files.pythonhosted.org/packages/10/ae/c3c059042053b92ae25363818901d0634708a3a85048e5ac835bd547107e/yarl-1.13.0-py3-none-any.whl", hash = "sha256:c7d35ff2a5a51bc6d40112cdb4ca3fd9636482ce8c6ceeeee2301e34f7ed7556", size = 39813 }, ] [[package]] name = "zipp" version = "3.20.2" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29", size = 24199 } wheels = [ { url = "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350", size = 9200 }, ]