pax_global_header00006660000000000000000000000064150311220570014506gustar00rootroot0000000000000052 comment=e42bfe589b1bbae281c3a4d9584d3de36dd6b1f0 bluetooth-data-tools-1.28.2/000077500000000000000000000000001503112205700156525ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/.all-contributorsrc000066400000000000000000000004501503112205700215020ustar00rootroot00000000000000{ "projectName": "bluetooth-data-tools", "projectOwner": "bdraco", "repoType": "github", "repoHost": "https://github.com", "files": ["README.md"], "imageSize": 80, "commit": true, "commitConvention": "angular", "contributors": [], "contributorsPerLine": 7, "skipCi": true } bluetooth-data-tools-1.28.2/.editorconfig000066400000000000000000000004441503112205700203310ustar00rootroot00000000000000# http://editorconfig.org root = true [*] indent_style = space indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 end_of_line = lf [*.bat] indent_style = tab end_of_line = crlf [LICENSE] insert_final_newline = false [Makefile] indent_style = tab bluetooth-data-tools-1.28.2/.github/000077500000000000000000000000001503112205700172125ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/.github/ISSUE_TEMPLATE/000077500000000000000000000000001503112205700213755ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/.github/ISSUE_TEMPLATE/1-bug_report.md000066400000000000000000000004221503112205700242230ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve labels: bug --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: **Additional context** Add any other context about the problem here. bluetooth-data-tools-1.28.2/.github/ISSUE_TEMPLATE/2-feature-request.md000066400000000000000000000006721503112205700252040ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project labels: enhancement --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Additional context** Add any other context or screenshots about the feature request here. bluetooth-data-tools-1.28.2/.github/dependabot.yml000066400000000000000000000013441503112205700220440ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" commit-message: prefix: "chore(ci): " groups: github-actions: patterns: - "*" - package-ecosystem: "pip" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" bluetooth-data-tools-1.28.2/.github/labels.toml000066400000000000000000000035151503112205700213550ustar00rootroot00000000000000[breaking] color = "ffcc00" name = "breaking" description = "Breaking change." [bug] color = "d73a4a" name = "bug" description = "Something isn't working" [dependencies] color = "0366d6" name = "dependencies" description = "Pull requests that update a dependency file" [github_actions] color = "000000" name = "github_actions" description = "Update of github actions" [documentation] color = "1bc4a5" name = "documentation" description = "Improvements or additions to documentation" [duplicate] color = "cfd3d7" name = "duplicate" description = "This issue or pull request already exists" [enhancement] color = "a2eeef" name = "enhancement" description = "New feature or request" ["good first issue"] color = "7057ff" name = "good first issue" description = "Good for newcomers" ["help wanted"] color = "008672" name = "help wanted" description = "Extra attention is needed" [invalid] color = "e4e669" name = "invalid" description = "This doesn't seem right" [nochangelog] color = "555555" name = "nochangelog" description = "Exclude pull requests from changelog" [question] color = "d876e3" name = "question" description = "Further information is requested" [removed] color = "e99695" name = "removed" description = "Removed piece of functionalities." [tests] color = "bfd4f2" name = "tests" description = "CI, CD and testing related changes" [wontfix] color = "ffffff" name = "wontfix" description = "This will not be worked on" [discussion] color = "c2e0c6" name = "discussion" description = "Some discussion around the project" [hacktoberfest] color = "ffa663" name = "hacktoberfest" description = "Good issues for Hacktoberfest" [answered] color = "0ee2b6" name = "answered" description = "Automatically closes as answered after a delay" [waiting] color = "5f7972" name = "waiting" description = "Automatically closes if no answer after a delay" bluetooth-data-tools-1.28.2/.github/workflows/000077500000000000000000000000001503112205700212475ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/.github/workflows/ci.yml000066400000000000000000000206541503112205700223740ustar00rootroot00000000000000name: CI on: push: branches: - main pull_request: concurrency: group: ${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.10" - uses: pre-commit/action@v3.0.1 # Make sure commit messages follow the conventional commits convention: # https://www.conventionalcommits.org commitlint: name: Lint Commit Messages runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: wagoid/commitlint-github-action@v6 test: strategy: fail-fast: false matrix: python-version: - "3.10" - "3.11" - "3.12" - "3.13" os: - ubuntu-latest - macOS-latest - windows-latest extension: - "skip_cython" - "use_cython" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - uses: snok/install-poetry@v1.4.1 - name: Install Dependencies run: | if [ "${{ matrix.extension }}" = "skip_cython" ]; then SKIP_CYTHON=1 poetry install --only=main,dev else poetry install --only=main,dev fi shell: bash - name: Test with Pytest run: poetry run pytest --cov-report=xml -v -Wdefault --cov=bluetooth_data_tools --cov-report=term-missing:skip-covered tests shell: bash - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} benchmark: strategy: fail-fast: false matrix: python-version: - "3.13" os: - ubuntu-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: snok/install-poetry@v1.4.1 - name: Install Dependencies run: poetry install --only=main,dev,benchmark env: REQUIRE_CYTHON: 1 - name: Run benchmarks run: | poetry run pytest bench --benchmark-autosave echo '# Benchmark Results' >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY poetry run pytest-benchmark compare --columns=mean,ops >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY shell: bash codspeed_benchmark: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Python 3.13 uses: actions/setup-python@v5 with: python-version: 3.13 - uses: snok/install-poetry@v1.4.1 - name: Install Dependencies run: | REQUIRE_CYTHON=1 poetry install --only=main,dev shell: bash - name: Run benchmarks uses: CodSpeedHQ/action@v3 with: token: ${{ secrets.CODSPEED_TOKEN }} run: poetry run pytest --no-cov -vvvvv --codspeed tests/benchmarks release: needs: - test - lint - commitlint runs-on: ubuntu-latest environment: release concurrency: release permissions: id-token: write contents: write outputs: released: ${{ steps.release.outputs.released }} newest_release_tag: ${{ steps.release.outputs.tag }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 ref: ${{ github.head_ref || github.ref_name }} # Do a dry run of PSR - name: Test release uses: python-semantic-release/python-semantic-release@v9.21.0 if: github.ref_name != 'main' with: root_options: --noop # On main branch: actual PSR + upload to PyPI & GitHub - name: Release uses: python-semantic-release/python-semantic-release@v9.21.0 id: release if: github.ref_name == 'main' with: github_token: ${{ secrets.GITHUB_TOKEN }} - name: Publish package distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1 if: steps.release.outputs.released == 'true' - name: Publish package distributions to GitHub Releases uses: python-semantic-release/upload-to-gh-release@main if: steps.release.outputs.released == 'true' with: github_token: ${{ secrets.GITHUB_TOKEN }} build_wheels: needs: [release] if: needs.release.outputs.released == 'true' name: Wheels for ${{ matrix.os }} (${{ matrix.musl == 'musllinux' && 'musllinux' || 'manylinux' }}) ${{ matrix.qemu }} ${{ matrix.pyver }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ windows-latest, ubuntu-24.04-arm, ubuntu-latest, macos-13, macos-latest, ] qemu: [""] musl: [""] pyver: [""] include: - os: ubuntu-latest musl: "musllinux" - os: ubuntu-24.04-arm musl: "musllinux" # qemu is slow, make a single # runner per Python version - os: ubuntu-latest qemu: armv7l musl: "musllinux" pyver: cp310 - os: ubuntu-latest qemu: armv7l musl: "musllinux" pyver: cp311 - os: ubuntu-latest qemu: armv7l musl: "musllinux" pyver: cp312 - os: ubuntu-latest qemu: armv7l musl: "musllinux" pyver: cp313 # qemu is slow, make a single # runner per Python version - os: ubuntu-latest qemu: armv7l musl: "" pyver: cp310 - os: ubuntu-latest qemu: armv7l musl: "" pyver: cp311 - os: ubuntu-latest qemu: armv7l musl: "" pyver: cp312 - os: ubuntu-latest qemu: armv7l musl: "" pyver: cp313 steps: - uses: actions/checkout@v4 with: ref: ${{ needs.release.outputs.newest_release_tag }} fetch-depth: 0 # Used to host cibuildwheel - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.12" - name: Set up QEMU if: ${{ matrix.qemu }} uses: docker/setup-qemu-action@v3 with: platforms: all # This should be temporary # xref https://github.com/docker/setup-qemu-action/issues/188 # xref https://github.com/tonistiigi/binfmt/issues/215 image: tonistiigi/binfmt:qemu-v8.1.5 id: qemu - name: Prepare emulation if: ${{ matrix.qemu }} run: | if [[ -n "${{ matrix.qemu }}" ]]; then # Build emulated architectures only if QEMU is set, # use default "auto" otherwise echo "CIBW_ARCHS_LINUX=${{ matrix.qemu }}" >> $GITHUB_ENV fi - name: Limit to a specific Python version on slow QEMU if: ${{ matrix.pyver }} run: | if [[ -n "${{ matrix.pyver }}" ]]; then echo "CIBW_BUILD=${{ matrix.pyver }}*" >> $GITHUB_ENV fi - name: Build wheels uses: pypa/cibuildwheel@v2.23.3 env: CIBW_SKIP: cp36-* cp37-* cp38-* cp39-* pp* ${{ matrix.musl == 'musllinux' && '*manylinux*' || '*musllinux*' }} REQUIRE_CYTHON: 1 - uses: actions/upload-artifact@v4 with: name: wheels-${{ matrix.os }}-${{ matrix.musl }}-${{ matrix.pyver }}-${{ matrix.qemu }} path: ./wheelhouse/*.whl upload_pypi: needs: [build_wheels] runs-on: ubuntu-latest environment: release permissions: id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - uses: actions/download-artifact@v4 with: # unpacks default artifact into dist/ # if `name: artifact` is omitted, the action will create extra parent dir path: dist pattern: wheels-* merge-multiple: true - uses: pypa/gh-action-pypi-publish@v1.12.4 # To test: repository_url: https://test.pypi.org/legacy/ bluetooth-data-tools-1.28.2/.github/workflows/hacktoberfest.yml000066400000000000000000000005341503112205700246200ustar00rootroot00000000000000name: Hacktoberfest on: schedule: # Run every day in October - cron: "0 0 * 10 *" # Run on the 1st of November to revert - cron: "0 13 1 11 *" jobs: hacktoberfest: runs-on: ubuntu-latest steps: - uses: browniebroke/hacktoberfest-labeler-action@v2.3.0 with: github_token: ${{ secrets.GH_PAT }} bluetooth-data-tools-1.28.2/.github/workflows/issue-manager.yml000066400000000000000000000013401503112205700245300ustar00rootroot00000000000000name: Issue Manager on: schedule: - cron: "0 0 * * *" issue_comment: types: - created issues: types: - labeled pull_request_target: types: - labeled workflow_dispatch: jobs: issue-manager: runs-on: ubuntu-latest steps: - uses: tiangolo/issue-manager@0.5.1 with: token: ${{ secrets.GITHUB_TOKEN }} config: > { "answered": { "message": "Assuming the original issue was solved, it will be automatically closed now." }, "waiting": { "message": "Automatically closing. To re-open, please provide the additional information requested." } } bluetooth-data-tools-1.28.2/.github/workflows/labels.yml000066400000000000000000000007741503112205700232440ustar00rootroot00000000000000name: Sync Github labels on: push: branches: - main paths: - ".github/**" jobs: labels: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.8 - name: Install labels run: pip install labels - name: Sync config with Github run: labels -u ${{ github.repository_owner }} -t ${{ secrets.GITHUB_TOKEN }} sync -f .github/labels.toml bluetooth-data-tools-1.28.2/.gitignore000066400000000000000000000041231503112205700176420ustar00rootroot00000000000000# Created by .ignore support plugin (hsz.mobi) ### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # IDEA project files .idea/ bluetooth-data-tools-1.28.2/.gitpod.yml000066400000000000000000000003061503112205700177400ustar00rootroot00000000000000tasks: - command: | pip install poetry PIP_USER=false poetry install - command: | pip install pre-commit pre-commit install PIP_USER=false pre-commit install-hooks bluetooth-data-tools-1.28.2/.pre-commit-config.yaml000066400000000000000000000026141503112205700221360ustar00rootroot00000000000000# See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks exclude: "CHANGELOG.md" default_stages: [pre-commit] ci: autofix_commit_msg: "chore(pre-commit.ci): auto fixes" autoupdate_commit_msg: "chore(pre-commit.ci): pre-commit autoupdate" repos: - repo: https://github.com/commitizen-tools/commitizen rev: v4.8.3 hooks: - id: commitizen stages: [commit-msg] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: debug-statements - id: check-builtin-literals - id: check-case-conflict - id: check-docstring-first - id: check-json - id: check-toml - id: check-xml - id: check-yaml - id: detect-private-key - id: end-of-file-fixer - id: trailing-whitespace - id: debug-statements - repo: https://github.com/pre-commit/mirrors-prettier rev: v4.0.0-alpha.8 hooks: - id: prettier args: ["--tab-width", "2"] - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.12.1 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] - id: ruff-format - repo: https://github.com/codespell-project/codespell rev: v2.4.1 hooks: - id: codespell - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.16.1 hooks: - id: mypy additional_dependencies: [] bluetooth-data-tools-1.28.2/.readthedocs.yml000066400000000000000000000010511503112205700207350ustar00rootroot00000000000000# Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-20.04 tools: python: "3.12" jobs: post_create_environment: # Install poetry - pip install poetry post_install: # Install dependencies - VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs # Build documentation in the docs directory with Sphinx sphinx: configuration: docs/conf.py bluetooth-data-tools-1.28.2/CHANGELOG.md000066400000000000000000001334741503112205700174770ustar00rootroot00000000000000# CHANGELOG ## v1.28.2 (2025-07-02) ### Bug Fixes - Parse multiple 16-bit and 32-bit Service UUIDs in BLE advertisement data ([#155](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/155), [`4b1d6e2`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/4b1d6e2f0c209d201973007f2a863efdd98ddf82)) ### Chores - **ci**: Bump pypa/cibuildwheel from 2.23.2 to 2.23.3 in the github-actions group ([#142](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/142), [`68fc83f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/68fc83f6a8e48fdaa130b9acc3fa0ce1bfc8cfbb)) - **deps**: Bump cryptography from 44.0.2 to 44.0.3 ([#143](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/143), [`94532d9`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/94532d999cf086cd85383d1da12f3ca321427675)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump cryptography from 44.0.3 to 45.0.2 ([#146](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/146), [`c8661a5`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/c8661a59ae9d53c8d663833d0c07ea5aa92f07e3)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump cryptography from 45.0.2 to 45.0.3 ([#147](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/147), [`21cf466`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/21cf46698826410318019204103da2b53a8aeab3)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump cryptography from 45.0.3 to 45.0.4 ([#152](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/152), [`2cca2de`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2cca2deb00d8ea808d0878c40d3d9947ecca1cc0)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump requests from 2.32.3 to 2.32.4 in the pip group ([#150](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/150), [`67c1724`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/67c1724545f024ceefc1eea64ce1050742def146)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump urllib3 from 2.3.0 to 2.5.0 in the pip group ([#156](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/156), [`16e1dad`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/16e1dadaf37af3d2c3561c0fb4484409ce5ed522)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest from 8.3.5 to 8.4.1 ([#153](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/153), [`f68a58f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/f68a58fb4f054f004cbef5f080f9f42d29268b5c)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest-cov from 6.0.0 to 6.1.1 ([#139](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/139), [`9b2dc3c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9b2dc3c7fb495180cb6542886765b41672ba5aa2)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest-cov from 6.1.1 to 6.2.1 ([#151](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/151), [`45fe00b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/45fe00bb31058b1fbd4e8ef23be94c08e6291415)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#141](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/141), [`be5a29f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/be5a29fb00136763c48002d9fcf4ddceb1d7eaf8)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#144](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/144), [`b5c8d16`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/b5c8d16ebedc97f4cf286a333a939e6916e1afdf)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#145](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/145), [`20cc9ab`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/20cc9abd4023f2009fcd33c919c20cf3136c3904)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ## v1.28.1 (2025-04-28) ### Bug Fixes - Restore lru size to 1024 ([#140](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/140), [`647e04f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/647e04fa23a1a07aa96adcbac48ebac6b2fe930f)) ## v1.28.0 (2025-04-27) ### Chores - **deps-dev**: Bump h11 from 0.14.0 to 0.16.0 in the pip group ([#138](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/138), [`c51e7ab`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/c51e7ab700fe32ef5003762d1e449d2f81fa1553)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#135](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/135), [`9102a5e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9102a5e55a0213daa1c2dc570e8c65d189e942b9)) updates: - [github.com/commitizen-tools/commitizen: v4.4.1 → v4.5.0](https://github.com/commitizen-tools/commitizen/compare/v4.4.1...v4.5.0) - [github.com/astral-sh/ruff-pre-commit: v0.11.2 → v0.11.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.2...v0.11.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#136](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/136), [`215a267`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/215a267382e5ba61d723a8c101b018eb0c03c2c5)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#137](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/137), [`88bfed3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/88bfed3314f9b96b7d5d34e62d728e04f7882705)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ### Features - Add parse_advertisement_data_bytes method ([#121](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/121), [`ce07c1c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ce07c1c9229eabfbcc1241572e7bd2a4550c1c54)) ## v1.27.0 (2025-04-03) ### Chores - Add gap fuzzer test ([#133](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/133), [`298e733`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/298e733e6185ca3e70ce9275662edb63802043ab)) ### Features - Improve performance of parsing manufacturer_data ([#134](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/134), [`f853955`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/f853955411d8c68a20fab58465b8966b76f3f21a)) ## v1.26.5 (2025-04-02) ### Bug Fixes - Reject data where the splice start position would be greater than end of the data ([#132](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/132), [`028f696`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/028f6965abd1f4d6d85fd895ad95198e74e36ca5)) ## v1.26.4 (2025-04-02) ### Bug Fixes - Add more test coverage for out of bound data ([#131](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/131), [`5249fe9`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5249fe9374d173cf32c96c3755702f026c780457)) ## v1.26.3 (2025-04-02) ### Bug Fixes - Reduce code complexity ([#130](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/130), [`8491346`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/849134609ab511d446f24e6b596ada503ba3a23a)) ### Chores - **ci**: Bump pypa/cibuildwheel from 2.23.0 to 2.23.2 in the github-actions group ([#129](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/129), [`78a83c6`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/78a83c60ae35525ce2e3e4d1e6fe0513bab81bb9)) chore(ci): bump pypa/cibuildwheel in the github-actions group Bumps the github-actions group with 1 update: [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel). Updates `pypa/cibuildwheel` from 2.23.0 to 2.23.2 - [Release notes](https://github.com/pypa/cibuildwheel/releases) - [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md) - [Commits](https://github.com/pypa/cibuildwheel/compare/v2.23.0...v2.23.2) --- updated-dependencies: - dependency-name: pypa/cibuildwheel dependency-version: 2.23.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#128](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/128), [`f28d99e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/f28d99ec17b0643a5f032a6bf0300ce7d8051e66)) updates: - [github.com/astral-sh/ruff-pre-commit: v0.11.0 → v0.11.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.0...v0.11.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ## v1.26.2 (2025-03-22) ### Bug Fixes - Use project.license key ([#127](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/127), [`6aa523e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/6aa523efe000a32d20f7b8e86bc48cd7251998f1)) ### Chores - **pre-commit.ci**: Pre-commit autoupdate ([#126](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/126), [`d28efe3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/d28efe360636966287066d01c498b8607cb27596)) ## v1.26.1 (2025-03-15) ### Bug Fixes - Increase size of parse_advertisement_data_tuple cache to 1024 ([#124](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/124), [`00076dc`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/00076dc4b3f51cdbfa15ef5b2a8a1dc420dccb36)) fixes #123 This one churns quite a bit and from how often its called, its a drain on performance having it so small. ### Chores - Update deps ([#125](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/125), [`0e6492a`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0e6492a35a3f5055b15167e15aa2e6f875fbfdc0)) - Updating coverage (7.6.10 -> 7.6.12) - Updating pytest (8.3.4 -> 8.3.5) - Updating cryptography (44.0.1 -> 44.0.2) - **pre-commit.ci**: Pre-commit autoupdate ([#120](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/120), [`e45380e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/e45380edd13e155372917a30362661e1b7686e65)) ## v1.26.0 (2025-03-10) ### Features - Reduce gap bytes slicing overhead ([#119](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/119), [`577561c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/577561c3318f17fc02e7cdd20935290181f1b0fd)) ## v1.25.1 (2025-03-05) ### Bug Fixes - Use trusted publishing for wheel uploads ([#118](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/118), [`2bddddf`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2bddddf888b9efe28b3ba25fefad10ccd5ff2dcb)) ## v1.25.0 (2025-03-05) ### Features - Reduce size of wheels ([#117](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/117), [`cc720fc`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/cc720fcc0cf6a4b68bc46895396fd32628aa1d52)) ## v1.24.1 (2025-03-05) ### Bug Fixes - Ensure Python 3.10 wheels build ([#116](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/116), [`91725a9`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/91725a9a74e3efd36f3091368179fe2cbf0b2e7d)) ## v1.24.0 (2025-03-05) ### Chores - Update release workflow for newer PSR ([#114](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/114), [`93eabee`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/93eabee3d0a0f58be29b6486a181ab3237687147)) - **ci**: Bump python-semantic-release/python-semantic-release from 9.17.0 to 9.21.0 in the github-actions group ([#113](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/113), [`bbcc3b3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/bbcc3b3347e18119fce258ec2d9508212ec30903)) - **pre-commit.ci**: Pre-commit autoupdate ([#111](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/111), [`1a45dae`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1a45dae9cd5bb10ced6edc306ce3f6d4274e1642)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#112](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/112), [`dc9f71f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/dc9f71fff7f478b48fe3f1fd10ea53cb245e7c96)) updates: - [github.com/commitizen-tools/commitizen: v4.2.1 → v4.4.1](https://github.com/commitizen-tools/commitizen/compare/v4.2.1...v4.4.1) - [github.com/astral-sh/ruff-pre-commit: v0.9.6 → v0.9.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.9.6...v0.9.9) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ### Features - Add new wheel builds ([#115](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/115), [`37369e8`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/37369e8f3f70e3734ad5b1912c7cab4f0a1582b6)) * feat: optimize wheel builds Reduce size of objects * chore: armv7l wheels ## v1.23.4 (2025-02-04) ### Bug Fixes - Update poetry to v2 + add license to metadata ([#110](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/110), [`9cce169`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9cce16967d35170770d8d62cb1c3d8dd66b36688)) ### Chores - **pre-commit.ci**: Pre-commit autoupdate ([#109](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/109), [`2edb0ed`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2edb0edcd5fb75d9e440edd8298fca2f09f2b97f)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ## v1.23.3 (2025-02-02) ### Bug Fixes - Migrate to trusted publishing ([#108](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/108), [`38023b0`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/38023b02ee67709007d5f513131de6948df3acf3)) ## v1.23.2 (2025-02-02) ### Bug Fixes - Missing wheels ([#107](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/107), [`a7ace68`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/a7ace6842165e610610ebd65521548a5953bc5c4)) ### Chores - Fix CI badge ([#106](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/106), [`cd32f09`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/cd32f09231d2263cafe2acf249b5e88b67394756)) ## v1.23.1 (2025-02-02) ### Bug Fixes - Adjust poetry groups to fix docs build ([#104](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/104), [`b74c2bf`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/b74c2bffdc5278dc6751999ed39ec7e289cac15e)) ### Build System - **deps-dev**: Bump pytest-codspeed from 3.1.2 to 3.2.0 ([#101](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/101), [`9973926`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9973926f18fa669b06e74a332939a66baeb0ce42)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ### Chores - Bump some GHA deps ([#103](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/103), [`85cc71f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/85cc71f02c66f2d56c5dd3615fc95b3497736b98)) - Fix docs build ([#100](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/100), [`4f0903e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/4f0903e4a226823ce341793ed9a41f3b2635b0fa)) - Update dependabot.yml to include GHA ([`ef9f356`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ef9f3564f198069b4e93ecba86abc4a6f2c9ec4f)) - **ci**: Bump the github-actions group across 1 directory with 5 updates ([#105](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/105), [`268c0f4`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/268c0f46c7bd6cbfd42b748dbca27fa1817d1cc0)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ## v1.23.0 (2025-02-02) ### Chores - Bump upload/download actions to v4 ([#97](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/97), [`82e5d05`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/82e5d0563cb4c7b407e5db5dc82bee864c052549)) - **pre-commit.ci**: Pre-commit autoupdate ([#96](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/96), [`55b134e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/55b134e587ffbd26c57d7a1637059d01d5f8a1f5)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#98](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/98), [`3a6e50c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/3a6e50ca688a2576ab897c7bc46331cfe6aed387)) ### Features - Improve cache performance ([#99](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/99), [`0dcf7ff`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0dcf7ffba7c278bf10453c92464d8b0adcfd09d5)) ## v1.22.0 (2025-01-17) ### Features - Migrate benchmarks to use Python 3.13 ([#95](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/95), [`949684e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/949684ec43507bac7f5513c636cf7bb58222d957)) ## v1.21.0 (2025-01-17) ### Build System - **deps**: Bump cryptography from 43.0.0 to 43.0.1 ([#69](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/69), [`5dec99c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5dec99cad1c56d7db6cf5fc489a0a000b27bd303)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump cryptography from 43.0.1 to 43.0.3 in the pip group ([#73](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/73), [`dc234ae`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/dc234ae8da9ad1eff8671c858954e7af49d7d12a)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump cryptography from 43.0.3 to 44.0.0 ([#86](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/86), [`5e2b7c8`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5e2b7c80f933e3cceb45220c923a4e13b95aa3da)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump jinja2 from 3.1.4 to 3.1.5 in the pip group ([#88](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/88), [`e1fc660`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/e1fc660567f8988cbef6530eb25c928cff7b8c0a)) - **deps**: Bump myst-parser from 1.0.0 to 3.0.1 ([#74](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/74), [`02fa6ae`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/02fa6aed518c1b6a1ecc51c14eaf834ef5d9bb37)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump myst-parser from 3.0.1 to 4.0.0 ([#89](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/89), [`b2cf3d4`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/b2cf3d4c04a7c6fff74b89aedb7231b80825eb95)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump sphinx from 5.3.0 to 6.2.1 ([#65](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/65), [`8fdc7ca`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/8fdc7cade9c3b87dfdd77cb741d1fd83fbc154ea)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump sphinx from 6.2.1 to 7.4.7 ([#87](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/87), [`ba46d70`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ba46d700817d7fffa9c3bbc6a83593a99bc55c29)) Bumps [sphinx](https://github.com/sphinx-doc/sphinx) from 6.2.1 to 7.4.7. - [Release notes](https://github.com/sphinx-doc/sphinx/releases) - [Changelog](https://github.com/sphinx-doc/sphinx/blob/v7.4.7/CHANGES.rst) - [Commits](https://github.com/sphinx-doc/sphinx/compare/v6.2.1...v7.4.7) --- updated-dependencies: - dependency-name: sphinx dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump sphinx from 7.4.7 to 8.1.3 ([#92](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/92), [`2f563b2`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2f563b236150097c94670a83c8b4e598d7d39e43)) - **deps**: Bump sphinx-rtd-theme from 1.2.0 to 2.0.0 ([#58](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/58), [`e9c06db`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/e9c06db989f1a49664e83dd9fd73734e2df9904c)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump sphinx-rtd-theme from 2.0.0 to 3.0.1 ([#75](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/75), [`3ab4688`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/3ab468886fc9405ba78958a28cc6d40f2cb37f93)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump sphinx-rtd-theme from 3.0.1 to 3.0.2 ([#81](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/81), [`17c43a6`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/17c43a69a58e52a270f01cfc9ecba90aa24ed5c6)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest from 8.3.2 to 8.3.3 ([#71](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/71), [`d0d69a5`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/d0d69a519aeb8608f6aee02b61a75fd070c852a3)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest from 8.3.3 to 8.3.4 ([#84](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/84), [`93a3bdf`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/93a3bdfa8695db95784f7d8addac06ac657f9c75)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest-benchmark from 4.0.0 to 5.1.0 ([#80](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/80), [`733077b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/733077bcc040346e531a1e5e01eeed331a602426)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest-cov from 5.0.0 to 6.0.0 ([#79](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/79), [`0dc38f7`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0dc38f793247f326a16cee588034f872c7a3f95f)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ### Chores - Add codspeed benchmarks ([#91](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/91), [`05fa2c7`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/05fa2c7a3fc29eb12e1b44d110470441f57ca738)) - **pre-commit.ci**: Pre-commit autoupdate ([#66](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/66), [`7b041ce`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7b041ce4c82fa4545ea61a8f761d6facf8a232a0)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#67](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/67), [`fd49b0f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/fd49b0fa4ef7918787b70a2d8b1191d5b879e1ea)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#70](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/70), [`5b0c528`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5b0c528118f4d3984f6a3cfa7e6a15135d027b82)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#72](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/72), [`da219f4`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/da219f4eac7b20bc20e5d57b12e2a4eb3d95fb91)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#76](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/76), [`1da6085`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1da608594010fd5c0e923fef8167e1d9d60e08ab)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#78](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/78), [`0ca9d53`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0ca9d5330f4da6ef8afdbeb23756f374f4567ea8)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#82](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/82), [`9d1907e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9d1907e09285e0654f55071ace3c3a0b08f464ae)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#83](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/83), [`9433456`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9433456c4b2715610769252d72ba02e07b9a0aca)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#85](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/85), [`7c1eb08`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7c1eb08ddf65acaf2675d2c277a3c0544d634ff3)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#90](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/90), [`dbdd4a3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/dbdd4a3e9544891e29a02d545e5ff1f5870f7952)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#93](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/93), [`8f4e202`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/8f4e20288fd1e76681ae9e6a1bb12c87baaef8ae)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ### Features - Add aarch64 wheels ([#94](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/94), [`88d134b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/88d134b1ac5377c515f613d5481cc35c969493e0)) ## v1.20.0 (2024-08-24) ### Build System - **deps**: Bump cryptography from 41.0.3 to 43.0.0 ([#61](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/61), [`97317cc`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/97317ccbca8d7c44db8c13f0375e883b74de2685)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps**: Bump myst-parser from 0.18.1 to 1.0.0 ([#60](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/60), [`aa46cee`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/aa46ceef5d365c658079e06db31f90fc45f8030f)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> - **deps-dev**: Bump pytest from 7.3.1 to 8.3.2 ([#59](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/59), [`950f182`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/950f1828e3e545b02576774f2093b602e45ca6b2)) - **deps-dev**: Bump pytest-cov from 3.0.0 to 5.0.0 ([#62](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/62), [`4b2d18b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/4b2d18b5a2206f61328c78c15693c21df1404429)) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> ### Chores - Bump deps for py3.13 ([#64](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/64), [`9cb11ad`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9cb11adbaa37030c4853dc426511dbe395a3410b)) - Create dependabot.yml ([`f292e9a`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/f292e9a1d0162e797790c9033d69849faeb6f7fd)) - **pre-commit.ci**: Pre-commit autoupdate ([#54](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/54), [`8931368`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/8931368a38cd4e79b3c2bccbc82d6451f0690250)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#55](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/55), [`66b7913`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/66b79139325af943bcef6978c10566fd673eef1c)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#56](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/56), [`e8162e3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/e8162e361c0a1822484205eb9b34a383552d33e4)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ### Features - Python 3.13 support ([#57](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/57), [`468014e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/468014ee5e69253eb4534013ee8cebf1ffe06c70)) ## v1.19.4 (2024-07-29) ### Bug Fixes - Speed up int_to_bluetooth_address C implementation ([#52](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/52), [`7d46575`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7d4657515cd313aff84fee17bd027d092bd3ae3c)) ### Chores - Fix CI ([#50](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/50), [`434460c`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/434460ca1cbb379b0000c6f88b546ac4659df1bd)) - Fix commitlint configuration ([#51](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/51), [`7a68c25`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7a68c2534b59a8c8bf9c2bbb40ddbbc125f69cc9)) - Make benchmarks runnable in CI ([#49](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/49), [`daac28d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/daac28de645075625410138988832c8d0f644aea)) - Remove IDEA configuration from repository ([#47](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/47), [`3dbabf7`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/3dbabf76a0c9d07ef7baceb770f8152e8d958ece)) - Switch linting & formatting to Ruff ([#48](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/48), [`3ae1bcd`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/3ae1bcda5e65801bdadc87ab9179fbac9ab74520)) - **pre-commit.ci**: Pre-commit autoupdate ([#45](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/45), [`9a4466d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/9a4466da63f6c8377b9ed6ccbc664813d9ff925a)) * chore(pre-commit.ci): pre-commit autoupdate updates: - [github.com/commitizen-tools/commitizen: v2.28.0 → v3.27.0](https://github.com/commitizen-tools/commitizen/compare/v2.28.0...v3.27.0) - [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.6.0) - [github.com/pre-commit/mirrors-prettier: v2.7.1 → v4.0.0-alpha.8](https://github.com/pre-commit/mirrors-prettier/compare/v2.7.1...v4.0.0-alpha.8) - [github.com/asottile/pyupgrade: v2.37.1 → v3.16.0](https://github.com/asottile/pyupgrade/compare/v2.37.1...v3.16.0) - [github.com/PyCQA/isort: 5.12.0 → 5.13.2](https://github.com/PyCQA/isort/compare/5.12.0...5.13.2) - [github.com/psf/black: 22.6.0 → 24.4.2](https://github.com/psf/black/compare/22.6.0...24.4.2) - [github.com/codespell-project/codespell: v2.1.0 → v2.3.0](https://github.com/codespell-project/codespell/compare/v2.1.0...v2.3.0) - [github.com/PyCQA/flake8: 4.0.1 → 7.1.0](https://github.com/PyCQA/flake8/compare/4.0.1...7.1.0) - [github.com/pre-commit/mirrors-mypy: v0.931 → v1.10.1](https://github.com/pre-commit/mirrors-mypy/compare/v0.931...v1.10.1) - [github.com/PyCQA/bandit: 1.7.4 → 1.7.9](https://github.com/PyCQA/bandit/compare/1.7.4...1.7.9) * chore(pre-commit.ci): auto fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> - **pre-commit.ci**: Pre-commit autoupdate ([#46](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/46), [`8995d2e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/8995d2e550ffd3ade458b2b144fed7fa7b1dfc18)) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> ## v1.19.3 (2024-06-24) ### Bug Fixes - Wheel builds on macos ([#44](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/44), [`07f423b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/07f423bc4ce88a357e7a06b5b48fb36dfc8b916a)) ## v1.19.2 (2024-06-24) ### Bug Fixes - Build cibuildwheel ([#43](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/43), [`fc8c1a1`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/fc8c1a182b189f115a687173abc20e2fe1ba2219)) ## v1.19.1 (2024-06-24) ### Bug Fixes - Fix license classifier ([#42](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/42), [`71d54c3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/71d54c39e62413194a1ba65d2fe397603788e042)) ## v1.19.0 (2023-12-21) ### Features - Speed up to gap parser ([#41](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/41), [`595c65a`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/595c65ac0fdaac27d286c1e893abe28c8b6bfe52)) ## v1.18.0 (2023-12-13) ### Features - Add mac_to_int util ([#40](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/40), [`57aebfb`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/57aebfbcdf83754c8324890908d401718818d391)) ## v1.17.0 (2023-12-03) ### Features - Speed up int_to_bluetooth_address ([#39](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/39), [`ac354ae`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ac354ae68b7afedfe5242ec50a209a6241d33169)) ## v1.16.0 (2023-12-01) ### Features - Add cython monotonic_time_coarse implementation ([#38](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/38), [`ae3abb8`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ae3abb88023a998be5e4b75b32f0882ebb18dfd9)) ## v1.15.0 (2023-11-24) ### Chores - Add more benchmarks ([#36](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/36), [`0a2df27`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0a2df279e89d0dfe381d4188321819074622f315)) ### Features - Improve performance of gap parser ([#37](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/37), [`05ea718`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/05ea718dcdf0a1d848d0eb98236439f8f0be07cf)) ## v1.14.0 (2023-11-05) ### Features - Speed up gap parser with a memory view ([#35](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/35), [`35e132f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/35e132f30b93e964c22806c54c5d19a23fc97383)) ## v1.13.0 (2023-10-18) ### Bug Fixes - Reduce size of wheels by excluding generated .c files ([#34](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/34), [`1b56b6e`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1b56b6e3f1579e9abb0b1d2aaf57fec39c8fc10b)) ### Chores - Add tests for esphome issue 4838 ([#32](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/32), [`ddf0e58`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/ddf0e583215f79abefb23a52e42a61b08608d879)) ### Features - Update cibuildwheel to build on final cpython release ([#33](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/33), [`46781c1`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/46781c1b41eec31c5047e76a843077a3b02d6dca)) ## v1.12.0 (2023-09-24) ### Features - Small speedups to the gap parser ([#30](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/30), [`87c0fcc`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/87c0fccacde8da59b2b046fcd2e94a83f30fc364)) ## v1.11.0 (2023-09-01) ### Features - Add helper for resolving a private address using an identity key ([#29](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/29), [`b5e13cc`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/b5e13cc44711d4ef4aa306bc6e06666afde9968c)) ## v1.10.0 (2023-09-01) ### Features - Add calculate_distance_meters to estimate distance to a bluetooth device ([#28](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/28), [`c6f0150`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/c6f0150f48d73e603bf69642e7cb7b03375f8393)) ## v1.9.1 (2023-08-27) ### Bug Fixes - Rebuild wheels with cython 3.0.2 ([#27](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/27), [`4634dfb`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/4634dfb8f47ab42787afecc596e864bf3ac11cbe)) ## v1.9.0 (2023-08-23) ### Features - Speed up the new parse_advertisement_data_tuple function ([#26](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/26), [`1137a50`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1137a5004a1e2a65ee0d37ab555d6ce300208237)) ## v1.8.0 (2023-08-10) ### Features - Make returned data from parse_advertisement_data readonly ([#25](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/25), [`1a07397`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1a073972bfc7dff35b4d8cc2d7394c4ad15f1109)) ## v1.7.0 (2023-08-05) ### Build System - Remove wheel from list of build dependencies ([#23](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/23), [`5512c3d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5512c3d16947c4418c544977ae46fc69810b1b64)) ### Features - Remove the need to have a cpp compiler installed ([#24](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/24), [`2a7ebac`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2a7ebac86872407c7802a847b92ee739747cceaa)) ## v1.6.1 (2023-07-24) ### Bug Fixes - Pin python-semantic-release to fix release process ([#22](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/22), [`957ad28`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/957ad28f576c33d075f1f72875de118d5ef8fd4c)) ## v1.6.0 (2023-07-13) ### Features - Improve performance when data is all unique ([#21](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/21), [`60bff4b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/60bff4b6f2da3cadce4305280fffc232a683122c)) ## v1.5.0 (2023-07-13) ### Features - Avoid tuple copy if data is already a tuple ([#20](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/20), [`69829ba`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/69829bae919245bd50132affb4b7718e6dffae1d)) ## v1.4.0 (2023-07-13) ### Features - Cache overall parse ([#19](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/19), [`5983718`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5983718f6228e9f4428fa7843df4e37e3a7527bf)) ## v1.3.0 (2023-06-29) ### Features - Improve handling of corrupt data ([#18](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/18), [`b70fdd4`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/b70fdd45afc295b7082d8fae019e28f357356bf0)) ## v1.2.0 (2023-06-15) ### Chores - Add benchmark ([#14](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/14), [`46e68f4`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/46e68f427af4ee8e5b366543667814dadfd59092)) - Bump deps to fix CI ([#17](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/17), [`fa2e104`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/fa2e10405b4692bbeff4926744a2fdc27322beb0)) ### Features - Optimize gap parser ([#13](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/13), [`7df2658`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7df26580c06cf38e2621e16a9a17a3fafb6978e4)) - Optimize gap parser ([#15](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/15), [`c598c2d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/c598c2ddc106da657bfec30864a65c2e2a36c5f3)) - Optimize gap parser ([#16](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/16), [`5800d45`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/5800d4531400ee96f95cd4ee82677a4f32e23182)) ## v1.1.0 (2023-06-14) ### Features - Reduce string conversion overhead for bluetooth addresses ([#12](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/12), [`558c93f`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/558c93f28ffcc205df4a34be0de963fbaeddfafe)) ## v1.0.0 (2023-06-07) ### Features - Speed up parsing advertisement data ([#11](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/11), [`47e2519`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/47e251928d5d03d7978cd82f9a6173f98d0cbb68)) BREAKING CHANGE: The decode_advertisement_data function is no longer exposed It is likely nobody was using it since it is internals for parse_advertisement_data, but it was exposed. If this is a problem for you, please open an issue. ### Breaking Changes - The decode_advertisement_data function is no longer exposed ## v0.4.0 (2023-04-15) ### Features - Add cython implementation ([#10](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/10), [`7fd349d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7fd349d0dd83bbcb51ade87ee8dc94fa2db67742)) ## v0.3.1 (2022-12-19) ### Bug Fixes - Handle zero padding in adv data ([#9](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/9), [`65fb26b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/65fb26b5197d6cf1bd262eab98d52b159f89db9f)) ## v0.3.0 (2022-11-13) ### Chores - Add python 3.11 to the CI ([#8](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/8), [`07f114d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/07f114df1b5f5f665001df8b681421dcf7acab1a)) - Bump python-semantic-release ([#7](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/7), [`2b4fd66`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/2b4fd668f12ac6ef4d40e0347da623e587e2058a)) ### Features - Add gap parser ([#6](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/6), [`dcb1d86`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/dcb1d86a15e9387385128ebaf32498d4af268963)) ## v0.2.0 (2022-10-27) ### Features - Add human_readable_name function ([#5](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/5), [`bb408cd`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/bb408cddb5f043314ec802c8b6a8a306c84fa2a3)) ## v0.1.2 (2022-08-13) ### Bug Fixes - Ci release process ([#4](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/4), [`1726d16`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/1726d1617ad0fceda2dee3945f12bf43768a3fe2)) ## v0.1.1 (2022-08-12) ### Bug Fixes - Release process ([#3](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/3), [`0a2f45b`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/0a2f45b7cba9fe71f20e2030b7712d13c330072c)) ## v0.1.0 (2022-08-12) ### Chores - Initial commit ([`52bb085`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/52bb0853ec9fbcc9fa6c357ff88aeb2778ccbf28)) ### Features - Add short_address ([#2](https://github.com/Bluetooth-Devices/bluetooth-data-tools/pull/2), [`f6eade3`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/f6eade36a4dab779d8b17a10971932ffa41f2501)) - Init repo ([`7a24a2d`](https://github.com/Bluetooth-Devices/bluetooth-data-tools/commit/7a24a2d3cc7319c85250a747fb91985e3ec3207c)) bluetooth-data-tools-1.28.2/CONTRIBUTING.md000066400000000000000000000074631503112205700201150ustar00rootroot00000000000000# Contributing Contributions are welcome, and they are greatly appreciated! Every little helps, and credit will always be given. You can contribute in many ways: ## Types of Contributions ### Report Bugs Report bugs to [our issue page][gh-issues]. If you are reporting a bug, please include: - Your operating system name and version. - Any details about your local setup that might be helpful in troubleshooting. - Detailed steps to reproduce the bug. ### Fix Bugs Look through the GitHub issues for bugs. Anything tagged with "bug" and "help wanted" is open to whoever wants to implement it. ### Implement Features Look through the GitHub issues for features. Anything tagged with "enhancement" and "help wanted" is open to whoever wants to implement it. ### Write Documentation Bluetooth Data Tools could always use more documentation, whether as part of the official Bluetooth Data Tools docs, in docstrings, or even on the web in blog posts, articles, and such. ### Submit Feedback The best way to send feedback [our issue page][gh-issues] on GitHub. If you are proposing a feature: - Explain in detail how it would work. - Keep the scope as narrow as possible, to make it easier to implement. - Remember that this is a volunteer-driven project, and that contributions are welcome 😊 ## Get Started! Ready to contribute? Here's how to set yourself up for local development. 1. Fork the repo on GitHub. 2. Clone your fork locally: ```shell $ git clone git@github.com:your_name_here/bluetooth-data-tools.git ``` 3. Install the project dependencies with [Poetry](https://python-poetry.org): ```shell $ poetry install ``` 4. Create a branch for local development: ```shell $ git checkout -b name-of-your-bugfix-or-feature ``` Now you can make your changes locally. 5. When you're done making changes, check that your changes pass our tests: ```shell $ poetry run pytest ``` 6. Linting is done through [pre-commit](https://pre-commit.com). Provided you have the tool installed globally, you can run them all as one-off: ```shell $ pre-commit run -a ``` Or better, install the hooks once and have them run automatically each time you commit: ```shell $ pre-commit install ``` 7. Commit your changes and push your branch to GitHub: ```shell $ git add . $ git commit -m "feat(something): your detailed description of your changes" $ git push origin name-of-your-bugfix-or-feature ``` Note: the commit message should follow [the conventional commits](https://www.conventionalcommits.org). We run [`commitlint` on CI](https://github.com/marketplace/actions/commit-linter) to validate it, and if you've installed pre-commit hooks at the previous step, the message will be checked at commit time. 8. Submit a pull request through the GitHub website or using the GitHub CLI (if you have it installed): ```shell $ gh pr create --fill ``` ## Pull Request Guidelines We like to have the pull request open as soon as possible, that's a great place to discuss any piece of work, even unfinished. You can use draft pull request if it's still a work in progress. Here are a few guidelines to follow: 1. Include tests for feature or bug fixes. 2. Update the documentation for significant features. 3. Ensure tests are passing on CI. ## Tips To run a subset of tests: ```shell $ pytest tests ``` ## Making a new release The deployment should be automated and can be triggered from the Semantic Release workflow in GitHub. The next version will be based on [the commit logs](https://python-semantic-release.readthedocs.io/en/latest/commit-log-parsing.html#commit-log-parsing). This is done by [python-semantic-release](https://python-semantic-release.readthedocs.io/en/latest/index.html) via a GitHub action. [gh-issues]: https://github.com/bdraco/bluetooth-data-tools/issues bluetooth-data-tools-1.28.2/LICENSE000066400000000000000000000261211503112205700166610ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2022 J. Nick Koston Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. bluetooth-data-tools-1.28.2/README.md000066400000000000000000000074161503112205700171410ustar00rootroot00000000000000# Bluetooth Data Tools

CI Status Documentation Status Test coverage percentage CodSpeed Badge

Poetry black pre-commit

PyPI Version Supported Python versions License

Tools for converting bluetooth data and packets ## Installation Install this via pip (or your favourite package manager): `pip install bluetooth-data-tools` ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ## Credits This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [browniebroke/cookiecutter-pypackage](https://github.com/browniebroke/cookiecutter-pypackage) project template. bluetooth-data-tools-1.28.2/bench/000077500000000000000000000000001503112205700167315ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/bench/__init__.py000066400000000000000000000000001503112205700210300ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/bench/test_int_to_bluetooth_address.py000066400000000000000000000005131503112205700254270ustar00rootroot00000000000000from bluetooth_data_tools.utils import ( _int_to_bluetooth_address, int_to_bluetooth_address, ) def test_parse_int_to_bluetooth_address_uncached(benchmark): benchmark(lambda: _int_to_bluetooth_address(0)) def test_parse_int_to_bluetooth_address_cached(benchmark): benchmark(lambda: int_to_bluetooth_address(0)) bluetooth-data-tools-1.28.2/bench/test_parse_gap.py000066400000000000000000000130451503112205700223060ustar00rootroot00000000000000from bluetooth_data_tools import parse_advertisement_data # cythonize -X language_level=3 -a -i src/bluetooth_data_tools/gap.py advs = [ b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x07\n\xffL\x00\x10\x05\x1f\x1c8#\xe2", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x1a\x02\n\x06\x11\xffL\x00\x0f\x08\xd0\n\x7fnt\x00\x08\x0c\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b'\x02\x01\x04\x03\x03\x07\xfe\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x03\x19\x00\x00\x02\n\x00', b'\x02\x01\x06\x16\xffL\x00\x061\x00\xcdnI\xa1\x91\xb2\x06\x007\x00\x04\x02\xcb\xd7,"\x04\x08LF0', b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x1e\xff\x01ZR\x02\xb4\xe8B\xdb\xcf\xd4\x00\x97\x0c\x03\x01\x02\x03\x04\x05\x06\x07\x08\t\xa1\xa2\xa3\xa4\xa5\xa6", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xd8.\xad\xcd\r\x85", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80\xa0\xf8\x04.\xe1\x9f\x19\xfa\x04.\xe1\x9f\x18\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33105\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x89\xc0\xa8j(", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b'\x02\x01\x02\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x02\n\t\x03\x03\x07\xfe', b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", ] def test_parse_advertisement_data(benchmark): benchmark(lambda: parse_advertisement_data(advs)) bluetooth-data-tools-1.28.2/bench/test_parse_gap_tuple.py000066400000000000000000000134461503112205700235240ustar00rootroot00000000000000from bluetooth_data_tools import parse_advertisement_data_tuple from bluetooth_data_tools.gap import _uncached_parse_advertisement_data # cythonize -X language_level=3 -a -i src/bluetooth_data_tools/gap.py advs = ( b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x07\n\xffL\x00\x10\x05\x1f\x1c8#\xe2", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x1a\x02\n\x06\x11\xffL\x00\x0f\x08\xd0\n\x7fnt\x00\x08\x0c\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b'\x02\x01\x04\x03\x03\x07\xfe\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x03\x19\x00\x00\x02\n\x00', b'\x02\x01\x06\x16\xffL\x00\x061\x00\xcdnI\xa1\x91\xb2\x06\x007\x00\x04\x02\xcb\xd7,"\x04\x08LF0', b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x1e\xff\x01ZR\x02\xb4\xe8B\xdb\xcf\xd4\x00\x97\x0c\x03\x01\x02\x03\x04\x05\x06\x07\x08\t\xa1\xa2\xa3\xa4\xa5\xa6", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xd8.\xad\xcd\r\x85", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80\xa0\xf8\x04.\xe1\x9f\x19\xfa\x04.\xe1\x9f\x18\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33105\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x89\xc0\xa8j(", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b'\x02\x01\x02\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x02\n\t\x03\x03\x07\xfe', b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", ) def test_parse_advertisement_data_tuple(benchmark): benchmark(lambda: parse_advertisement_data_tuple(advs)) def test_parse_advertisement_data_tuple_uncached(benchmark): joined_advs = b"".join(advs) benchmark(lambda: _uncached_parse_advertisement_data(joined_advs)) bluetooth-data-tools-1.28.2/build_ext.py000066400000000000000000000036161503112205700202110ustar00rootroot00000000000000"""Build optional cython modules.""" import os from distutils.command.build_ext import build_ext from os.path import join from typing import Any try: from setuptools import Extension except ImportError: from distutils.core import Extension utils_module = Extension( "bluetooth_data_tools._utils_impl", [ join("src", "bluetooth_data_tools", "_utils_impl.pyx"), ], language="c", extra_compile_args=["-O3", "-g0"], ) time_module = Extension( "bluetooth_data_tools._time_impl", [ join("src", "bluetooth_data_tools", "_time_impl.pyx"), ], language="c", extra_compile_args=["-O3", "-g0"], ) TO_CYTHONIZE = [ "src/bluetooth_data_tools/gap.py", "src/bluetooth_data_tools/utils.py", ] EXTENSIONS = [ Extension( ext.removeprefix("src/").removesuffix(".py").replace("/", "."), [ext], language="c", extra_compile_args=["-O3", "-g0"], ) for ext in TO_CYTHONIZE ] class BuildExt(build_ext): def build_extensions(self) -> None: try: super().build_extensions() except Exception: # noqa: S110 pass def build(setup_kwargs: Any) -> None: if os.environ.get("SKIP_CYTHON", False): return try: from Cython.Build import cythonize setup_kwargs.update( dict( ext_modules=cythonize( [ time_module, utils_module, *EXTENSIONS, ], compiler_directives={"language_level": "3"}, # Python 3 ), cmdclass=dict(build_ext=BuildExt), ) ) setup_kwargs["exclude_package_data"] = { pkg: ["*.c"] for pkg in setup_kwargs["packages"] } except Exception: if os.environ.get("REQUIRE_CYTHON"): raise pass bluetooth-data-tools-1.28.2/commitlint.config.mjs000066400000000000000000000003621503112205700220110ustar00rootroot00000000000000export default { extends: ["@commitlint/config-conventional"], rules: { "header-max-length": [0, "always", Infinity], "body-max-line-length": [0, "always", Infinity], "footer-max-line-length": [0, "always", Infinity], }, }; bluetooth-data-tools-1.28.2/docs/000077500000000000000000000000001503112205700166025ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/docs/Makefile000066400000000000000000000013721503112205700202450ustar00rootroot00000000000000# 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 = . BUILDDIR = _build .PHONY: help livehtml Makefile # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) # Build, watch and serve docs with live reload livehtml: sphinx-autobuild -b html -c . $(SOURCEDIR) $(BUILDDIR)/html # 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) bluetooth-data-tools-1.28.2/docs/_static/000077500000000000000000000000001503112205700202305ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/docs/_static/.gitkeep000066400000000000000000000000001503112205700216470ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/docs/changelog.md000066400000000000000000000000601503112205700210470ustar00rootroot00000000000000(changelog)= ```{include} ../CHANGELOG.md ``` bluetooth-data-tools-1.28.2/docs/conf.py000066400000000000000000000012311503112205700200760ustar00rootroot00000000000000# 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 # Project information project = "bluetooth-data-tools" copyright = "2023, J. Nick Koston" author = "J. Nick Koston" release = "1.28.2" # General configuration extensions = [ "myst_parser", ] # The suffix of source filenames. source_suffix = [ ".rst", ".md", ] templates_path = [ "_templates", ] exclude_patterns = [ "_build", "Thumbs.db", ".DS_Store", ] # Options for HTML output html_theme = "furo" html_static_path = ["_static"] bluetooth-data-tools-1.28.2/docs/contributing.md000066400000000000000000000000661503112205700216350ustar00rootroot00000000000000(contributing)= ```{include} ../CONTRIBUTING.md ``` bluetooth-data-tools-1.28.2/docs/index.md000066400000000000000000000003611503112205700202330ustar00rootroot00000000000000# Welcome to bluetooth-data-tools documentation! ```{toctree} :caption: Installation & Usage :maxdepth: 2 installation usage ``` ```{toctree} :caption: Project Info :maxdepth: 2 changelog contributing ``` ```{include} ../README.md ``` bluetooth-data-tools-1.28.2/docs/installation.md000066400000000000000000000004371503112205700216310ustar00rootroot00000000000000(installation)= # Installation The package is published on [PyPI](https://pypi.org/project/bluetooth-data-tools/) and can be installed with `pip` (or any equivalent): ```bash pip install bluetooth-data-tools ``` Next, see the {ref}`section about usage ` to see how to use it. bluetooth-data-tools-1.28.2/docs/make.bat000066400000000000000000000013751503112205700202150ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. 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 bluetooth-data-tools-1.28.2/docs/usage.md000066400000000000000000000003371503112205700202330ustar00rootroot00000000000000(usage)= # Usage Assuming that you've followed the {ref}`installations steps `, you're now ready to use this package. Start by importing it: ```python import bluetooth_data_tools ``` TODO: Document usage bluetooth-data-tools-1.28.2/poetry.lock000066400000000000000000003605451503112205700200630ustar00rootroot00000000000000# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand. [[package]] name = "alabaster" version = "1.0.0" description = "A light, configurable Sphinx theme" optional = false python-versions = ">=3.10" groups = ["main", "docs"] files = [ {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, ] [[package]] name = "anyio" version = "4.8.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, ] [package.dependencies] exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} idna = ">=2.8" sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""] trio = ["trio (>=0.26.1)"] [[package]] name = "babel" version = "2.17.0" description = "Internationalization utilities" optional = false python-versions = ">=3.8" groups = ["main", "docs"] files = [ {file = "babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2"}, {file = "babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d"}, ] [package.extras] dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] [[package]] name = "beautifulsoup4" version = "4.13.3" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" groups = ["docs"] files = [ {file = "beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16"}, {file = "beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b"}, ] [package.dependencies] soupsieve = ">1.2" typing-extensions = ">=4.0.0" [package.extras] cchardet = ["cchardet"] chardet = ["chardet"] charset-normalizer = ["charset-normalizer"] html5lib = ["html5lib"] lxml = ["lxml"] [[package]] name = "certifi" version = "2025.1.31" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" groups = ["main", "docs"] files = [ {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, ] [[package]] name = "cffi" version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] markers = {main = "platform_python_implementation != \"PyPy\""} [package.dependencies] pycparser = "*" [[package]] name = "charset-normalizer" version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "docs"] files = [ {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" groups = ["docs"] files = [ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main", "benchmark", "dev", "docs"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] markers = {main = "sys_platform == \"win32\"", benchmark = "sys_platform == \"win32\"", dev = "sys_platform == \"win32\""} [[package]] name = "coverage" version = "7.6.12" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, ] [package.dependencies] tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" version = "45.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.7" groups = ["main"] files = [ {file = "cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1"}, {file = "cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999"}, {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750"}, {file = "cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2"}, {file = "cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257"}, {file = "cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8"}, {file = "cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad"}, {file = "cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6"}, {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872"}, {file = "cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4"}, {file = "cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97"}, {file = "cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a77c6fb8d76e9c9f99f2f3437c1a4ac287b34eaf40997cfab1e9bd2be175ac39"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7aad98a25ed8ac917fdd8a9c1e706e5a0956e06c498be1f713b61734333a4507"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3530382a43a0e524bc931f187fc69ef4c42828cf7d7f592f7f249f602b5a4ab0"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:6b613164cb8425e2f8db5849ffb84892e523bf6d26deb8f9bb76ae86181fa12b"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:96d4819e25bf3b685199b304a0029ce4a3caf98947ce8a066c9137cc78ad2c58"}, {file = "cryptography-45.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b97737a3ffbea79eebb062eb0d67d72307195035332501722a9ca86bab9e3ab2"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4828190fb6c4bcb6ebc6331f01fe66ae838bb3bd58e753b59d4b22eb444b996c"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03dbff8411206713185b8cebe31bc5c0eb544799a50c09035733716b386e61a4"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51dfbd4d26172d31150d84c19bbe06c68ea4b7f11bbc7b3a5e146b367c311349"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:0339a692de47084969500ee455e42c58e449461e0ec845a34a6a9b9bf7df7fb8"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:0cf13c77d710131d33e63626bd55ae7c0efb701ebdc2b3a7952b9b23a0412862"}, {file = "cryptography-45.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bbc505d1dc469ac12a0a064214879eac6294038d6b24ae9f71faae1448a9608d"}, {file = "cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57"}, ] [package.dependencies] cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] test = ["certifi (>=2024)", "cryptography-vectors (==45.0.4)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] name = "docutils" version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, ] [[package]] name = "exceptiongroup" version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" groups = ["benchmark", "dev", "docs"] markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] test = ["pytest (>=6)"] [[package]] name = "furo" version = "2024.8.6" description = "A clean customisable Sphinx documentation theme." optional = false python-versions = ">=3.8" groups = ["docs"] files = [ {file = "furo-2024.8.6-py3-none-any.whl", hash = "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c"}, {file = "furo-2024.8.6.tar.gz", hash = "sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01"}, ] [package.dependencies] beautifulsoup4 = "*" pygments = ">=2.7" sphinx = ">=6.0,<9.0" sphinx-basic-ng = ">=1.0.0.beta2" [[package]] name = "h11" version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false python-versions = ">=3.8" groups = ["docs"] files = [ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] name = "idna" version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" groups = ["main", "docs"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" groups = ["main", "docs"] files = [ {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, ] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" groups = ["benchmark", "dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] name = "jinja2" version = "3.1.6" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" groups = ["main", "docs"] files = [ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"}, {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"}, ] [package.dependencies] MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] [[package]] name = "markdown-it-py" version = "3.0.0" description = "Python port of markdown-it. Markdown parsing, done right!" optional = false python-versions = ">=3.8" groups = ["main", "dev", "docs"] files = [ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] [package.dependencies] mdurl = ">=0.1,<1.0" [package.extras] benchmarking = ["psutil", "pytest", "pytest-benchmark"] code-style = ["pre-commit (>=3.0,<4.0)"] compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] linkify = ["linkify-it-py (>=1,<3)"] plugins = ["mdit-py-plugins"] profiling = ["gprof2dot"] rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "mdit-py-plugins" version = "0.4.2" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" groups = ["main", "docs"] files = [ {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, ] [package.dependencies] markdown-it-py = ">=1.0.0,<4.0.0" [package.extras] code-style = ["pre-commit"] rtd = ["myst-parser", "sphinx-book-theme"] testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" optional = false python-versions = ">=3.7" groups = ["main", "dev", "docs"] files = [ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] [[package]] name = "myst-parser" version = "4.0.1" description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," optional = false python-versions = ">=3.10" groups = ["main", "docs"] files = [ {file = "myst_parser-4.0.1-py3-none-any.whl", hash = "sha256:9134e88959ec3b5780aedf8a99680ea242869d012e8821db3126d427edc9c95d"}, {file = "myst_parser-4.0.1.tar.gz", hash = "sha256:5cfea715e4f3574138aecbf7d54132296bfd72bb614d31168f48c477a830a7c4"}, ] [package.dependencies] docutils = ">=0.19,<0.22" jinja2 = "*" markdown-it-py = ">=3.0,<4.0" mdit-py-plugins = ">=0.4.1,<1.0" pyyaml = "*" sphinx = ">=7,<9" [package.extras] code-style = ["pre-commit (>=4.0,<5.0)"] linkify = ["linkify-it-py (>=2.0,<3.0)"] rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-book-theme (>=1.1,<2.0)", "sphinx-copybutton", "sphinx-design", "sphinx-pyscript", "sphinx-tippy (>=0.4.3)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.9.0,<0.10.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pygments (<2.19)", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"] testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"] [[package]] name = "packaging" version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["main", "benchmark", "dev", "docs"] files = [ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" groups = ["benchmark", "dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "py-cpuinfo" version = "9.0.0" description = "Get CPU info with pure Python" optional = false python-versions = "*" groups = ["benchmark"] files = [ {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"}, {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, ] [[package]] name = "pycparser" version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] markers = {main = "platform_python_implementation != \"PyPy\""} [[package]] name = "pygments" version = "2.19.1" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["main", "benchmark", "dev", "docs"] files = [ {file = "pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c"}, {file = "pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f"}, ] [package.extras] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" version = "8.4.1" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.9" groups = ["benchmark", "dev"] files = [ {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"}, {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"}, ] [package.dependencies] colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} iniconfig = ">=1" packaging = ">=20" pluggy = ">=1.5,<2" pygments = ">=2.7.2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-benchmark" version = "5.1.0" description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." optional = false python-versions = ">=3.9" groups = ["benchmark"] files = [ {file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"}, {file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"}, ] [package.dependencies] py-cpuinfo = "*" pytest = ">=8.1" [package.extras] aspect = ["aspectlib"] elasticsearch = ["elasticsearch"] histogram = ["pygal", "pygaljs", "setuptools"] [[package]] name = "pytest-codspeed" version = "3.2.0" description = "Pytest plugin to create CodSpeed benchmarks" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pytest_codspeed-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5165774424c7ab8db7e7acdb539763a0e5657996effefdf0664d7fd95158d34"}, {file = "pytest_codspeed-3.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bd55f92d772592c04a55209950c50880413ae46876e66bd349ef157075ca26c"}, {file = "pytest_codspeed-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf6f56067538f4892baa8d7ab5ef4e45bb59033be1ef18759a2c7fc55b32035"}, {file = "pytest_codspeed-3.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39a687b05c3d145642061b45ea78e47e12f13ce510104d1a2cda00eee0e36f58"}, {file = "pytest_codspeed-3.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46a1afaaa1ac4c2ca5b0700d31ac46d80a27612961d031067d73c6ccbd8d3c2b"}, {file = "pytest_codspeed-3.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c48ce3af3dfa78413ed3d69d1924043aa1519048dbff46edccf8f35a25dab3c2"}, {file = "pytest_codspeed-3.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:66692506d33453df48b36a84703448cb8b22953eea51f03fbb2eb758dc2bdc4f"}, {file = "pytest_codspeed-3.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:479774f80d0bdfafa16112700df4dbd31bf2a6757fac74795fd79c0a7b3c389b"}, {file = "pytest_codspeed-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:109f9f4dd1088019c3b3f887d003b7d65f98a7736ca1d457884f5aa293e8e81c"}, {file = "pytest_codspeed-3.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2f69a03b52c9bb041aec1b8ee54b7b6c37a6d0a948786effa4c71157765b6da"}, {file = "pytest_codspeed-3.2.0-py3-none-any.whl", hash = "sha256:54b5c2e986d6a28e7b0af11d610ea57bd5531cec8326abe486f1b55b09d91c39"}, {file = "pytest_codspeed-3.2.0.tar.gz", hash = "sha256:f9d1b1a3b2c69cdc0490a1e8b1ced44bffbd0e8e21d81a7160cfdd923f6e8155"}, ] [package.dependencies] cffi = ">=1.17.1" pytest = ">=3.8" rich = ">=13.8.1" [package.extras] compat = ["pytest-benchmark (>=5.0.0,<5.1.0)", "pytest-xdist (>=3.6.1,<3.7.0)"] lint = ["mypy (>=1.11.2,<1.12.0)", "ruff (>=0.6.5,<0.7.0)"] test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"] [[package]] name = "pytest-cov" version = "6.2.1" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5"}, {file = "pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2"}, ] [package.dependencies] coverage = {version = ">=7.5", extras = ["toml"]} pluggy = ">=1.2" pytest = ">=6.2.5" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pyyaml" version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["main", "docs"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "requests" version = "2.32.4" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" groups = ["main", "docs"] files = [ {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.8.0" groups = ["dev"] files = [ {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "sniffio" version = "1.3.1" description = "Sniff out which async library your code is running under" optional = false python-versions = ">=3.7" groups = ["docs"] files = [ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] [[package]] name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." optional = false python-versions = "*" groups = ["main", "docs"] files = [ {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] [[package]] name = "soupsieve" version = "2.6" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" groups = ["docs"] files = [ {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, ] [[package]] name = "sphinx" version = "8.1.3" description = "Python documentation generator" optional = false python-versions = ">=3.10" groups = ["main", "docs"] files = [ {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, ] [package.dependencies] alabaster = ">=0.7.14" babel = ">=2.13" colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} docutils = ">=0.20,<0.22" imagesize = ">=1.3" Jinja2 = ">=3.1" packaging = ">=23.0" Pygments = ">=2.17" requests = ">=2.30.0" snowballstemmer = ">=2.2" sphinxcontrib-applehelp = ">=1.0.7" sphinxcontrib-devhelp = ">=1.0.6" sphinxcontrib-htmlhelp = ">=2.0.6" sphinxcontrib-jsmath = ">=1.0.1" sphinxcontrib-qthelp = ">=1.0.6" sphinxcontrib-serializinghtml = ">=1.1.9" tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] lint = ["flake8 (>=6.0)", "mypy (==1.11.1)", "pyright (==1.1.384)", "pytest (>=6.0)", "ruff (==0.6.9)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-Pillow (==10.2.0.20240822)", "types-Pygments (==2.18.0.20240506)", "types-colorama (==0.4.15.20240311)", "types-defusedxml (==0.7.0.20240218)", "types-docutils (==0.21.0.20241005)", "types-requests (==2.32.0.20240914)", "types-urllib3 (==1.26.25.14)"] test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-autobuild" version = "2024.10.3" description = "Rebuild Sphinx documentation on changes, with hot reloading in the browser." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa"}, {file = "sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1"}, ] [package.dependencies] colorama = ">=0.4.6" sphinx = "*" starlette = ">=0.35" uvicorn = ">=0.25" watchfiles = ">=0.20" websockets = ">=11" [package.extras] test = ["httpx", "pytest (>=6)"] [[package]] name = "sphinx-basic-ng" version = "1.0.0b2" description = "A modern skeleton for Sphinx themes." optional = false python-versions = ">=3.7" groups = ["docs"] files = [ {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"}, {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"}, ] [package.dependencies] sphinx = ">=4.0" [package.extras] docs = ["furo", "ipython", "myst-parser", "sphinx-copybutton", "sphinx-inline-tabs"] [[package]] name = "sphinx-rtd-theme" version = "3.0.2" description = "Read the Docs theme for Sphinx" optional = true python-versions = ">=3.8" groups = ["main"] markers = "extra == \"docs\"" files = [ {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, ] [package.dependencies] docutils = ">0.18,<0.22" sphinx = ">=6,<9" sphinxcontrib-jquery = ">=4,<5" [package.extras] dev = ["bump2version", "transifex-client", "twine", "wheel"] [[package]] name = "sphinxcontrib-applehelp" version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" version = "2.0.0" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] name = "sphinxcontrib-jquery" version = "4.1" description = "Extension to include jQuery on newer Sphinx releases" optional = true python-versions = ">=2.7" groups = ["main"] markers = "extra == \"docs\"" files = [ {file = "sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a"}, {file = "sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae"}, ] [package.dependencies] Sphinx = ">=1.8" [[package]] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" optional = false python-versions = ">=3.5" groups = ["main", "docs"] files = [ {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, ] [package.extras] test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" version = "2.0.0" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" version = "2.0.0" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "starlette" version = "0.46.1" description = "The little ASGI library that shines." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227"}, {file = "starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230"}, ] [package.dependencies] anyio = ">=3.6.2,<5" [package.extras] full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] [[package]] name = "tomli" version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["main", "benchmark", "dev", "docs"] files = [ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] markers = {main = "python_version < \"3.11\"", benchmark = "python_version < \"3.11\"", dev = "python_full_version <= \"3.11.0a6\"", docs = "python_version < \"3.11\""} [[package]] name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["dev", "docs"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] markers = {dev = "python_version < \"3.11\""} [[package]] name = "urllib3" version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main", "docs"] files = [ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, ] [package.extras] brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" version = "0.34.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"}, {file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"}, ] [package.dependencies] click = ">=7.0" h11 = ">=0.8" typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} [package.extras] standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] [[package]] name = "watchfiles" version = "1.0.4" description = "Simple, modern and high performance file watching and code reload in python." optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "watchfiles-1.0.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ba5bb3073d9db37c64520681dd2650f8bd40902d991e7b4cfaeece3e32561d08"}, {file = "watchfiles-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f25d0ba0fe2b6d2c921cf587b2bf4c451860086534f40c384329fb96e2044d1"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47eb32ef8c729dbc4f4273baece89398a4d4b5d21a1493efea77a17059f4df8a"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:076f293100db3b0b634514aa0d294b941daa85fc777f9c698adb1009e5aca0b1"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eacd91daeb5158c598fe22d7ce66d60878b6294a86477a4715154990394c9b3"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13c2ce7b72026cfbca120d652f02c7750f33b4c9395d79c9790b27f014c8a5a2"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90192cdc15ab7254caa7765a98132a5a41471cf739513cc9bcf7d2ffcc0ec7b2"}, {file = "watchfiles-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278aaa395f405972e9f523bd786ed59dfb61e4b827856be46a42130605fd0899"}, {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a462490e75e466edbb9fc4cd679b62187153b3ba804868452ef0577ec958f5ff"}, {file = "watchfiles-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8d0d0630930f5cd5af929040e0778cf676a46775753e442a3f60511f2409f48f"}, {file = "watchfiles-1.0.4-cp310-cp310-win32.whl", hash = "sha256:cc27a65069bcabac4552f34fd2dce923ce3fcde0721a16e4fb1b466d63ec831f"}, {file = "watchfiles-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:8b1f135238e75d075359cf506b27bf3f4ca12029c47d3e769d8593a2024ce161"}, {file = "watchfiles-1.0.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2a9f93f8439639dc244c4d2902abe35b0279102bca7bbcf119af964f51d53c19"}, {file = "watchfiles-1.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eea33ad8c418847dd296e61eb683cae1c63329b6d854aefcd412e12d94ee235"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31f1a379c9dcbb3f09cf6be1b7e83b67c0e9faabed0471556d9438a4a4e14202"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ab594e75644421ae0a2484554832ca5895f8cab5ab62de30a1a57db460ce06c6"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc2eb5d14a8e0d5df7b36288979176fbb39672d45184fc4b1c004d7c3ce29317"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f68d8e9d5a321163ddacebe97091000955a1b74cd43724e346056030b0bacee"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9ce064e81fe79faa925ff03b9f4c1a98b0bbb4a1b8c1b015afa93030cb21a49"}, {file = "watchfiles-1.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b77d5622ac5cc91d21ae9c2b284b5d5c51085a0bdb7b518dba263d0af006132c"}, {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1941b4e39de9b38b868a69b911df5e89dc43767feeda667b40ae032522b9b5f1"}, {file = "watchfiles-1.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f8c4998506241dedf59613082d1c18b836e26ef2a4caecad0ec41e2a15e4226"}, {file = "watchfiles-1.0.4-cp311-cp311-win32.whl", hash = "sha256:4ebbeca9360c830766b9f0df3640b791be569d988f4be6c06d6fae41f187f105"}, {file = "watchfiles-1.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:05d341c71f3d7098920f8551d4df47f7b57ac5b8dad56558064c3431bdfc0b74"}, {file = "watchfiles-1.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:32b026a6ab64245b584acf4931fe21842374da82372d5c039cba6bf99ef722f3"}, {file = "watchfiles-1.0.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:229e6ec880eca20e0ba2f7e2249c85bae1999d330161f45c78d160832e026ee2"}, {file = "watchfiles-1.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5717021b199e8353782dce03bd8a8f64438832b84e2885c4a645f9723bf656d9"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0799ae68dfa95136dde7c472525700bd48777875a4abb2ee454e3ab18e9fc712"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43b168bba889886b62edb0397cab5b6490ffb656ee2fcb22dec8bfeb371a9e12"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb2c46e275fbb9f0c92e7654b231543c7bbfa1df07cdc4b99fa73bedfde5c844"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:857f5fc3aa027ff5e57047da93f96e908a35fe602d24f5e5d8ce64bf1f2fc733"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55ccfd27c497b228581e2838d4386301227fc0cb47f5a12923ec2fe4f97b95af"}, {file = "watchfiles-1.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c11ea22304d17d4385067588123658e9f23159225a27b983f343fcffc3e796a"}, {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:74cb3ca19a740be4caa18f238298b9d472c850f7b2ed89f396c00a4c97e2d9ff"}, {file = "watchfiles-1.0.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7cce76c138a91e720d1df54014a047e680b652336e1b73b8e3ff3158e05061e"}, {file = "watchfiles-1.0.4-cp312-cp312-win32.whl", hash = "sha256:b045c800d55bc7e2cadd47f45a97c7b29f70f08a7c2fa13241905010a5493f94"}, {file = "watchfiles-1.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:c2acfa49dd0ad0bf2a9c0bb9a985af02e89345a7189be1efc6baa085e0f72d7c"}, {file = "watchfiles-1.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:22bb55a7c9e564e763ea06c7acea24fc5d2ee5dfc5dafc5cfbedfe58505e9f90"}, {file = "watchfiles-1.0.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:8012bd820c380c3d3db8435e8cf7592260257b378b649154a7948a663b5f84e9"}, {file = "watchfiles-1.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:aa216f87594f951c17511efe5912808dfcc4befa464ab17c98d387830ce07b60"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c9953cf85529c05b24705639ffa390f78c26449e15ec34d5339e8108c7c407"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7cf684aa9bba4cd95ecb62c822a56de54e3ae0598c1a7f2065d51e24637a3c5d"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f44a39aee3cbb9b825285ff979ab887a25c5d336e5ec3574f1506a4671556a8d"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38320582736922be8c865d46520c043bff350956dfc9fbaee3b2df4e1740a4b"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39f4914548b818540ef21fd22447a63e7be6e24b43a70f7642d21f1e73371590"}, {file = "watchfiles-1.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f12969a3765909cf5dc1e50b2436eb2c0e676a3c75773ab8cc3aa6175c16e902"}, {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0986902677a1a5e6212d0c49b319aad9cc48da4bd967f86a11bde96ad9676ca1"}, {file = "watchfiles-1.0.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:308ac265c56f936636e3b0e3f59e059a40003c655228c131e1ad439957592303"}, {file = "watchfiles-1.0.4-cp313-cp313-win32.whl", hash = "sha256:aee397456a29b492c20fda2d8961e1ffb266223625346ace14e4b6d861ba9c80"}, {file = "watchfiles-1.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:d6097538b0ae5c1b88c3b55afa245a66793a8fec7ada6755322e465fb1a0e8cc"}, {file = "watchfiles-1.0.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:d3452c1ec703aa1c61e15dfe9d482543e4145e7c45a6b8566978fbb044265a21"}, {file = "watchfiles-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7b75fee5a16826cf5c46fe1c63116e4a156924d668c38b013e6276f2582230f0"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e997802d78cdb02623b5941830ab06f8860038faf344f0d288d325cc9c5d2ff"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e0611d244ce94d83f5b9aff441ad196c6e21b55f77f3c47608dcf651efe54c4a"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9745a4210b59e218ce64c91deb599ae8775c8a9da4e95fb2ee6fe745fc87d01a"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4810ea2ae622add560f4aa50c92fef975e475f7ac4900ce5ff5547b2434642d8"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:740d103cd01458f22462dedeb5a3382b7f2c57d07ff033fbc9465919e5e1d0f3"}, {file = "watchfiles-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdbd912a61543a36aef85e34f212e5d2486e7c53ebfdb70d1e0b060cc50dd0bf"}, {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0bc80d91ddaf95f70258cf78c471246846c1986bcc5fd33ccc4a1a67fcb40f9a"}, {file = "watchfiles-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab0311bb2ffcd9f74b6c9de2dda1612c13c84b996d032cd74799adb656af4e8b"}, {file = "watchfiles-1.0.4-cp39-cp39-win32.whl", hash = "sha256:02a526ee5b5a09e8168314c905fc545c9bc46509896ed282aeb5a8ba9bd6ca27"}, {file = "watchfiles-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:a5ae5706058b27c74bac987d615105da17724172d5aaacc6c362a40599b6de43"}, {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdcc92daeae268de1acf5b7befcd6cfffd9a047098199056c72e4623f531de18"}, {file = "watchfiles-1.0.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8d3d9203705b5797f0af7e7e5baa17c8588030aaadb7f6a86107b7247303817"}, {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdef5a1be32d0b07dcea3318a0be95d42c98ece24177820226b56276e06b63b0"}, {file = "watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:342622287b5604ddf0ed2d085f3a589099c9ae8b7331df3ae9845571586c4f3d"}, {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9fe37a2de80aa785d340f2980276b17ef697ab8db6019b07ee4fd28a8359d2f3"}, {file = "watchfiles-1.0.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9d1ef56b56ed7e8f312c934436dea93bfa3e7368adfcf3df4c0da6d4de959a1e"}, {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b42cac65beae3a362629950c444077d1b44f1790ea2772beaea95451c086bb"}, {file = "watchfiles-1.0.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e0227b8ed9074c6172cf55d85b5670199c99ab11fd27d2c473aa30aec67ee42"}, {file = "watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205"}, ] [package.dependencies] anyio = ">=3.0.0" [[package]] name = "websockets" version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false python-versions = ">=3.9" groups = ["docs"] files = [ {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, {file = "websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a"}, {file = "websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e"}, {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf"}, {file = "websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb"}, {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d"}, {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9"}, {file = "websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c"}, {file = "websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256"}, {file = "websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41"}, {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431"}, {file = "websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57"}, {file = "websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905"}, {file = "websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562"}, {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792"}, {file = "websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413"}, {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8"}, {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3"}, {file = "websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf"}, {file = "websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85"}, {file = "websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065"}, {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3"}, {file = "websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665"}, {file = "websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2"}, {file = "websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215"}, {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5"}, {file = "websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65"}, {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe"}, {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4"}, {file = "websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597"}, {file = "websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9"}, {file = "websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7"}, {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931"}, {file = "websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675"}, {file = "websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151"}, {file = "websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22"}, {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f"}, {file = "websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8"}, {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375"}, {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d"}, {file = "websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4"}, {file = "websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa"}, {file = "websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561"}, {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5f4c04ead5aed67c8a1a20491d54cdfba5884507a48dd798ecaf13c74c4489f5"}, {file = "websockets-15.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abdc0c6c8c648b4805c5eacd131910d2a7f6455dfd3becab248ef108e89ab16a"}, {file = "websockets-15.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a625e06551975f4b7ea7102bc43895b90742746797e2e14b70ed61c43a90f09b"}, {file = "websockets-15.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d591f8de75824cbb7acad4e05d2d710484f15f29d4a915092675ad3456f11770"}, {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47819cea040f31d670cc8d324bb6435c6f133b8c7a19ec3d61634e62f8d8f9eb"}, {file = "websockets-15.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac017dd64572e5c3bd01939121e4d16cf30e5d7e110a119399cf3133b63ad054"}, {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4a9fac8e469d04ce6c25bb2610dc535235bd4aa14996b4e6dbebf5e007eba5ee"}, {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363c6f671b761efcb30608d24925a382497c12c506b51661883c3e22337265ed"}, {file = "websockets-15.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2034693ad3097d5355bfdacfffcbd3ef5694f9718ab7f29c29689a9eae841880"}, {file = "websockets-15.0.1-cp39-cp39-win32.whl", hash = "sha256:3b1ac0d3e594bf121308112697cf4b32be538fb1444468fb0a6ae4feebc83411"}, {file = "websockets-15.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7643a03db5c95c799b89b31c036d5f27eeb4d259c798e878d6937d71832b1e4"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04"}, {file = "websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7f493881579c90fc262d9cdbaa05a6b54b3811c2f300766748db79f098db9940"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:47b099e1f4fbc95b701b6e85768e1fcdaf1630f3cbe4765fa216596f12310e2e"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f2b6de947f8c757db2db9c71527933ad0019737ec374a8a6be9a956786aaf9"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d08eb4c2b7d6c41da6ca0600c077e93f5adcfd979cd777d747e9ee624556da4b"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b826973a4a2ae47ba357e4e82fa44a463b8f168e1ca775ac64521442b19e87f"}, {file = "websockets-15.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:21c1fa28a6a7e3cbdc171c694398b6df4744613ce9b36b1a498e816787e28123"}, {file = "websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f"}, {file = "websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee"}, ] [extras] docs = ["Sphinx", "myst-parser", "sphinx-rtd-theme"] [metadata] lock-version = "2.1" python-versions = "^3.10" content-hash = "12a3b2b24f4544794ff6da473b17e9bf71098689c10b7adc7ef924d507df0df5" bluetooth-data-tools-1.28.2/pyproject.toml000066400000000000000000000065361503112205700206000ustar00rootroot00000000000000[build-system] requires = ['setuptools>=77.0', 'Cython', "poetry-core>=2.0.0"] build-backend = "poetry.core.masonry.api" [project] name = "bluetooth-data-tools" version = "1.28.2" license = "Apache-2.0" description = "Tools for converting bluetooth data and packets" authors = [{ name = "J. Nick Koston", email = "nick@koston.org" }] readme = "README.md" requires-python = ">=3.10" [project.urls] "Repository" = "https://github.com/bdraco/bluetooth-data-tools" "Documentation" = "https://bluetooth-data-tools.readthedocs.io" "Bug Tracker" = "https://github.com/bdraco/bluetooth-data-tools/issues" "Changelog" = "https://github.com/bdraco/bluetooth-data-tools/blob/main/CHANGELOG.md" [tool.poetry] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "Natural Language :: English", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries", ] packages = [ { include = "bluetooth_data_tools", from = "src" }, ] [tool.poetry.build] generate-setup-file = true script = "build_ext.py" [tool.poetry.dependencies] python = "^3.10" # Documentation Dependencies Sphinx = {version = ">=5,<9", optional = true} sphinx-rtd-theme = {version = ">=1,<4", optional = true} myst-parser = {version = ">=0.18,<4.1", optional = true} cryptography = ">=41.0.3" [tool.poetry.extras] docs = [ "myst-parser", "sphinx", "sphinx-rtd-theme", ] [tool.poetry.group.benchmark.dependencies] pytest-benchmark = ">=4,<6" [tool.poetry.group.dev.dependencies] pytest-codspeed = "^3.1.2" pytest = "^8.4" pytest-cov = "^6.2" [tool.poetry.group.docs] optional = true [tool.poetry.group.docs.dependencies] myst-parser = ">=0.16" sphinx = ">=4.0" furo = ">=2023.5.20" sphinx-autobuild = ">=2021.3.14" [tool.semantic_release] version_toml = ["pyproject.toml:project.version"] version_variables = [ "src/bluetooth_data_tools/__init__.py:__version__", "docs/conf.py:release", ] build_command = "pip install poetry && poetry build" branch = "main" [tool.pytest.ini_options] pythonpath = ["src"] [tool.coverage.run] branch = true [tool.coverage.report] exclude_lines = [ "pragma: no cover", "@overload", "if TYPE_CHECKING", "raise NotImplementedError", ] [tool.mypy] check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_untyped_defs = true mypy_path = "src/" no_implicit_optional = true show_error_codes = true warn_unreachable = true warn_unused_ignores = true exclude = [ 'docs/.*', 'setup.py', ] [[tool.mypy.overrides]] module = "tests.*" allow_untyped_defs = true [[tool.mypy.overrides]] module = "bench.*" allow_untyped_defs = true [[tool.mypy.overrides]] module = "docs.*" ignore_errors = true [tool.ruff] exclude = ["docs"] line-length = 88 target-version = "py310" [tool.ruff.lint] extend-select = [ "B", "E", "F", "I", # isort "S", # security (bandit) "W", "UP", # pyupgrade ] extend-ignore = [ "E501", # formatter will take care of line lengths ] [tool.ruff.lint.extend-per-file-ignores] "tests/*" = [ "S101", # assert ok in tests ] [tool.ruff.lint.isort] known-first-party = ["bluetooth_data_tools", "tests"] [tool.ruff.per-file-ignores] "tests/**/*" = [ "D100", "D101", "D102", "D103", "D104", "S101", "S311", ] "setup.py" = ["D100"] "conftest.py" = ["D100"] "docs/conf.py" = ["D100"] bluetooth-data-tools-1.28.2/renovate.json000066400000000000000000000001011503112205700203600ustar00rootroot00000000000000{ "extends": ["github>browniebroke/renovate-configs:python"] } bluetooth-data-tools-1.28.2/src/000077500000000000000000000000001503112205700164415ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/000077500000000000000000000000001503112205700226575ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/__init__.py000066400000000000000000000020631503112205700247710ustar00rootroot00000000000000"""Bluetooth data tools.""" from __future__ import annotations from .distance import calculate_distance_meters from .gap import ( BLEGAPAdvertisement, BLEGAPType, parse_advertisement_data, parse_advertisement_data_bytes, parse_advertisement_data_tuple, ) from .privacy import get_cipher_for_irk, resolve_private_address from .time import monotonic_time_coarse from .utils import ( address_to_bytes, human_readable_name, int_to_bluetooth_address, mac_to_int, manufacturer_data_to_raw, newest_manufacturer_data, short_address, ) __version__ = "1.28.2" __all__ = [ "address_to_bytes", "manufacturer_data_to_raw", "newest_manufacturer_data", "human_readable_name", "int_to_bluetooth_address", "parse_advertisement_data_bytes", "short_address", "BLEGAPType", "BLEGAPAdvertisement", "parse_advertisement_data", "parse_advertisement_data_tuple", "calculate_distance_meters", "get_cipher_for_irk", "resolve_private_address", "monotonic_time_coarse", "mac_to_int", ] bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/_time_impl.pyx000066400000000000000000000003561503112205700255430ustar00rootroot00000000000000import cython from posix.time cimport clock_gettime, timespec def _monotonic_time_coarse(): cdef timespec ts cdef double current clock_gettime(6, &ts) current = ts.tv_sec + (ts.tv_nsec / 1000000000.) return current bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/_utils_impl.pyx000066400000000000000000000005511503112205700257420ustar00rootroot00000000000000# cython: language_level=3, c_string_type=str, c_string_encoding=ascii from libc.stdint cimport uint64_t cdef extern from "utils_wrapper.h": void _uint64_to_bdaddr(uint64_t address, char bdaddr[17]) nogil def _int_to_bluetooth_address(addr: int) -> str: cdef char bdaddr[17] _uint64_to_bdaddr(addr, bdaddr) return bdaddr[:17] bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/distance.py000066400000000000000000000007251503112205700250270ustar00rootroot00000000000000from typing import cast MAX_THEORETICAL_DISTANCE = 400.0 def calculate_distance_meters(power: int, rssi: int) -> float | None: """Calculate the distance in meters between the scanner and the device.""" if rssi == 0 or power == 0: return None if (ratio := rssi * 1.0 / power) < 1.0: distance = pow(ratio, 10) else: distance = cast(float, 0.89976 * pow(ratio, 7.7095) + 0.111) return min(distance, MAX_THEORETICAL_DISTANCE) bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/gap.pxd000066400000000000000000000034311503112205700241440ustar00rootroot00000000000000import cython cdef str BLE_UUID cdef dict _EMPTY_MANUFACTURER_DATA cdef dict _EMPTY_SERVICE_DATA cdef list _EMPTY_SERVICE_UUIDS cdef object from_bytes cdef object from_bytes_little cdef object from_bytes_signed cdef object _cached_uint16_bytes_as_uuid cdef object _cached_uint32_bytes_as_uuid cdef object _cached_uint128_bytes_as_uuid cdef object _cached_parse_advertisement_data cdef object _cached_parse_advertisement_data_tuple cdef object _cached_from_bytes_signed cdef object _LOGGER cdef class BLEGAPAdvertisement: cdef readonly object local_name cdef readonly object service_uuids cdef readonly object service_data cdef readonly object manufacturer_data cdef readonly object tx_power cdef cython.uint TYPE_SHORT_LOCAL_NAME cdef cython.uint TYPE_COMPLETE_LOCAL_NAME cdef cython.uint TYPE_MANUFACTURER_SPECIFIC_DATA cdef cython.uint TYPE_16BIT_SERVICE_UUID_COMPLETE cdef cython.uint TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE cdef cython.uint TYPE_32BIT_SERVICE_UUID_COMPLETE cdef cython.uint TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE cdef cython.uint TYPE_128BIT_SERVICE_UUID_COMPLETE cdef cython.uint TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE cdef cython.uint TYPE_SERVICE_DATA cdef cython.uint TYPE_SERVICE_DATA_32BIT_UUID cdef cython.uint TYPE_SERVICE_DATA_128BIT_UUID cdef cython.uint TYPE_TX_POWER_LEVEL cpdef parse_advertisement_data(object data) @cython.locals( gap_data="const unsigned char *", gap_value=cython.bytes, gap_type_num="unsigned char", total_length=cython.uint, length="unsigned char", offset=cython.uint, start=cython.uint, end=cython.uint, i=cython.uint, ) cpdef _uncached_parse_advertisement_bytes(bytes gap_bytes) cpdef _uncached_parse_advertisement_data(bytes gap_bytes) cpdef _uncached_parse_advertisement_tuple(tuple data) bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/gap.py000066400000000000000000000273121503112205700240050ustar00rootroot00000000000000"""GATT Advertisement and Scan Response Data (GAP).""" import logging from collections.abc import Iterable from enum import IntEnum from functools import lru_cache, partial from typing import TYPE_CHECKING BLE_UUID = "0000-1000-8000-00805f9b34fb" _LOGGER = logging.getLogger(__name__) class BLEGAPAdvertisement: """GATT Advertisement and Scan Response Data (GAP).""" __slots__ = ( "local_name", "service_uuids", "service_data", "manufacturer_data", "tx_power", ) def __init__( self, local_name: str | None, service_uuids: list[str], service_data: dict[str, bytes], manufacturer_data: dict[int, bytes], tx_power: int | None, ) -> None: """Initialize GAP Advertisement.""" self.local_name = local_name self.service_uuids = service_uuids self.service_data = service_data self.manufacturer_data = manufacturer_data self.tx_power = tx_power class BLEGAPType(IntEnum): """Advertising data types.""" TYPE_UNKNOWN = 0x00 TYPE_FLAGS = 0x01 TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE = 0x02 TYPE_16BIT_SERVICE_UUID_COMPLETE = 0x03 TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE = 0x04 TYPE_32BIT_SERVICE_UUID_COMPLETE = 0x05 TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE = 0x06 TYPE_128BIT_SERVICE_UUID_COMPLETE = 0x07 TYPE_SHORT_LOCAL_NAME = 0x08 TYPE_COMPLETE_LOCAL_NAME = 0x09 TYPE_TX_POWER_LEVEL = 0x0A TYPE_CLASS_OF_DEVICE = 0x0D TYPE_SIMPLE_PAIRING_HASH_C = 0x0E TYPE_SIMPLE_PAIRING_RANDOMIZER_R = 0x0F TYPE_SECURITY_MANAGER_TK_VALUE = 0x10 TYPE_SECURITY_MANAGER_OOB_FLAGS = 0x11 TYPE_SLAVE_CONNECTION_INTERVAL_RANGE = 0x12 TYPE_SOLICITED_SERVICE_UUIDS_16BIT = 0x14 TYPE_SOLICITED_SERVICE_UUIDS_128BIT = 0x15 TYPE_SERVICE_DATA = 0x16 TYPE_PUBLIC_TARGET_ADDRESS = 0x17 TYPE_RANDOM_TARGET_ADDRESS = 0x18 TYPE_APPEARANCE = 0x19 TYPE_ADVERTISING_INTERVAL = 0x1A TYPE_LE_BLUETOOTH_DEVICE_ADDRESS = 0x1B TYPE_LE_ROLE = 0x1C TYPE_SIMPLE_PAIRING_HASH_C256 = 0x1D TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 = 0x1E TYPE_SERVICE_DATA_32BIT_UUID = 0x20 TYPE_SERVICE_DATA_128BIT_UUID = 0x21 TYPE_URI = 0x24 TYPE_3D_INFORMATION_DATA = 0x3D TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF from_bytes = int.from_bytes from_bytes_little = partial(from_bytes, byteorder="little") from_bytes_signed = partial(from_bytes, byteorder="little", signed=True) TYPE_SHORT_LOCAL_NAME = BLEGAPType.TYPE_SHORT_LOCAL_NAME.value TYPE_COMPLETE_LOCAL_NAME = BLEGAPType.TYPE_COMPLETE_LOCAL_NAME.value TYPE_MANUFACTURER_SPECIFIC_DATA = BLEGAPType.TYPE_MANUFACTURER_SPECIFIC_DATA.value TYPE_16BIT_SERVICE_UUID_COMPLETE = BLEGAPType.TYPE_16BIT_SERVICE_UUID_COMPLETE.value TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE = ( BLEGAPType.TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE.value ) TYPE_32BIT_SERVICE_UUID_COMPLETE = BLEGAPType.TYPE_32BIT_SERVICE_UUID_COMPLETE.value TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE = ( BLEGAPType.TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE.value ) TYPE_128BIT_SERVICE_UUID_COMPLETE = BLEGAPType.TYPE_128BIT_SERVICE_UUID_COMPLETE.value TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE = ( BLEGAPType.TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE.value ) TYPE_SERVICE_DATA = BLEGAPType.TYPE_SERVICE_DATA.value TYPE_SERVICE_DATA_32BIT_UUID = BLEGAPType.TYPE_SERVICE_DATA_32BIT_UUID.value TYPE_SERVICE_DATA_128BIT_UUID = BLEGAPType.TYPE_SERVICE_DATA_128BIT_UUID.value TYPE_TX_POWER_LEVEL = BLEGAPType.TYPE_TX_POWER_LEVEL.value bytes_ = bytes BLEGAPAdvertisementTupleType = tuple[ str | None, list[str], dict[str, bytes], dict[int, bytes], int | None ] _cached_from_bytes_signed = lru_cache(maxsize=256)(from_bytes_signed) @lru_cache(maxsize=256) def _uint128_bytes_as_uuid(uint128_bytes: bytes_) -> str: """Convert an integer to a UUID str.""" int_value = from_bytes_little(uint128_bytes) hex = f"{int_value:032x}" return f"{hex[:8]}-{hex[8:12]}-{hex[12:16]}-{hex[16:20]}-{hex[20:]}" _cached_uint128_bytes_as_uuid = _uint128_bytes_as_uuid @lru_cache(maxsize=256) def _uint16_bytes_as_uuid(uuid16_bytes: bytes_) -> str: """Convert a 16-bit UUID to a UUID str.""" return f"0000{from_bytes_little(uuid16_bytes):04x}-{BLE_UUID}" _cached_uint16_bytes_as_uuid = _uint16_bytes_as_uuid @lru_cache(maxsize=256) def _uint32_bytes_as_uuid(uuid32_bytes: bytes_) -> str: """Convert a 32-bit UUID to a UUID str.""" return f"{from_bytes_little(uuid32_bytes):08x}-{BLE_UUID}" _cached_uint32_bytes_as_uuid = _uint32_bytes_as_uuid _EMPTY_MANUFACTURER_DATA: dict[int, bytes] = {} _EMPTY_SERVICE_DATA: dict[str, bytes] = {} _EMPTY_SERVICE_UUIDS: list[str] = [] @lru_cache(maxsize=256) def _parse_advertisement_data( data: bytes, ) -> BLEGAPAdvertisement: """Parse advertisement data and return a BLEGAPAdvertisement.""" return _uncached_parse_advertisement_data(data) _cached_parse_advertisement_data = _parse_advertisement_data def parse_advertisement_data( data: Iterable[bytes], ) -> BLEGAPAdvertisement: """Parse advertisement data and return a BLEGAPAdvertisement.""" if type(data) is tuple: return _cached_parse_advertisement_data( b"".join(data) if len(data) > 1 else data[0] ) return _cached_parse_advertisement_data(b"".join(data)) def _uncached_parse_advertisement_data(data: bytes) -> BLEGAPAdvertisement: return BLEGAPAdvertisement(*_uncached_parse_advertisement_bytes(data)) def _uncached_parse_advertisement_tuple( data: tuple[bytes, ...], ) -> BLEGAPAdvertisementTupleType: return _uncached_parse_advertisement_bytes( b"".join(data) if len(data) > 1 else data[0] ) def _uncached_parse_advertisement_bytes( gap_bytes: bytes, ) -> BLEGAPAdvertisementTupleType: manufacturer_data = _EMPTY_MANUFACTURER_DATA service_data = _EMPTY_SERVICE_DATA service_uuids = _EMPTY_SERVICE_UUIDS local_name: str | None = None tx_power: int | None = None offset = 0 total_length = len(gap_bytes) gap_data = gap_bytes # IMPORTANT: All data must be manually bounds checked # because the data is untrusted and can be malformed. while offset + 2 < total_length: if not (length := gap_data[offset]): offset += 1 # Handle zero padding continue if not (gap_type_num := gap_data[offset + 1]): offset += 1 + length # Skip empty type continue start = offset + 2 end = start + length - 1 offset += 1 + length if end > total_length or end - start <= 0: _LOGGER.debug( "Invalid BLE GAP AD structure at offset %s: %s (%s)", offset, gap_bytes, ) continue if gap_type_num == TYPE_SHORT_LOCAL_NAME and local_name is None: local_name = gap_data[start:end].decode("utf-8", "replace") elif gap_type_num == TYPE_COMPLETE_LOCAL_NAME: local_name = gap_data[start:end].decode("utf-8", "replace") elif gap_type_num == TYPE_MANUFACTURER_SPECIFIC_DATA: splice_pos = start + 2 if splice_pos >= total_length or splice_pos >= end: break if manufacturer_data is _EMPTY_MANUFACTURER_DATA: manufacturer_data = {} manufacturer_data[gap_data[start] | (gap_data[start + 1] << 8)] = gap_data[ splice_pos:end ] elif gap_type_num in { TYPE_16BIT_SERVICE_UUID_COMPLETE, TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE, }: if service_uuids is _EMPTY_SERVICE_UUIDS: service_uuids = [] # Parse multiple 16-bit UUIDs (each is 2 bytes) for i in range(start, end, 2): if i + 2 <= end: service_uuids.append( _cached_uint16_bytes_as_uuid(gap_data[i : i + 2]) ) elif gap_type_num in { TYPE_32BIT_SERVICE_UUID_COMPLETE, TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE, }: if service_uuids is _EMPTY_SERVICE_UUIDS: service_uuids = [] # Parse multiple 32-bit UUIDs (each is 4 bytes) for i in range(start, end, 4): if i + 4 <= end: service_uuids.append( _cached_uint32_bytes_as_uuid(gap_data[i : i + 4]) ) elif gap_type_num in { TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE, TYPE_128BIT_SERVICE_UUID_COMPLETE, }: if service_uuids is _EMPTY_SERVICE_UUIDS: service_uuids = [] service_uuids.append(_cached_uint128_bytes_as_uuid(gap_data[start:end])) elif gap_type_num == TYPE_SERVICE_DATA: splice_pos = start + 2 if splice_pos >= total_length or splice_pos >= end: break if service_data is _EMPTY_SERVICE_DATA: service_data = {} service_data[_cached_uint16_bytes_as_uuid(gap_data[start:splice_pos])] = ( gap_data[splice_pos:end] ) elif gap_type_num == TYPE_SERVICE_DATA_32BIT_UUID: splice_pos = start + 4 if splice_pos >= total_length or splice_pos >= end: break if service_data is _EMPTY_SERVICE_DATA: service_data = {} service_data[_cached_uint32_bytes_as_uuid(gap_data[start:splice_pos])] = ( gap_data[splice_pos:end] ) elif gap_type_num == TYPE_SERVICE_DATA_128BIT_UUID: splice_pos = start + 16 if splice_pos >= total_length or splice_pos >= end: break if service_data is _EMPTY_SERVICE_DATA: service_data = {} service_data[_cached_uint128_bytes_as_uuid(gap_data[start:splice_pos])] = ( gap_data[splice_pos:end] ) elif gap_type_num == TYPE_TX_POWER_LEVEL: tx_power = _cached_from_bytes_signed(gap_data[start:end]) return (local_name, service_uuids, service_data, manufacturer_data, tx_power) if TYPE_CHECKING: @lru_cache(maxsize=1024) def parse_advertisement_data_bytes( gap_bytes: bytes, ) -> BLEGAPAdvertisementTupleType: """Parse a tuple of raw advertisement data and return a tuple of BLEGAPAdvertisementTupleType. The format of the tuple is: (local_name, service_uuids, service_data, manufacturer_data, tx_power) This is tightly coupled to bleak. If you are not using bleak it is recommended to use parse_advertisement_data instead. local_name: str | None service_uuids: list[str] service_data: dict[str, bytes] manufacturer_data: dict[int, bytes] tx_power: int | None """ return _uncached_parse_advertisement_bytes(gap_bytes) @lru_cache(maxsize=256) def parse_advertisement_data_tuple( data: tuple[bytes, ...], ) -> BLEGAPAdvertisementTupleType: """Parse raw advertisement bytes and return a tuple of BLEGAPAdvertisementTupleType. The format of the tuple is: (local_name, service_uuids, service_data, manufacturer_data, tx_power) This is tightly coupled to bleak. If you are not using bleak it is recommended to use parse_advertisement_data instead. local_name: str | None service_uuids: list[str] service_data: dict[str, bytes] manufacturer_data: dict[int, bytes] tx_power: int | None """ return _uncached_parse_advertisement_tuple(data) else: parse_advertisement_data_bytes = lru_cache(maxsize=1024)( _uncached_parse_advertisement_bytes ) parse_advertisement_data_tuple = lru_cache(maxsize=256)( _uncached_parse_advertisement_tuple ) bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/privacy.py000066400000000000000000000017521503112205700247130ustar00rootroot00000000000000"""Helpers for resolving a private address if you know its identity resolving key. This process uses 128bit IRK as encryption key for ECB AES. One half of address is used to store a random 24bit number (prand). This is encrypted to produce a "hash". The top 24 bits of the hash should math the other half of the MAC address. See https://www.mdpi.com/2227-7390/10/22/4346 """ import binascii from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes PADDING = b"\x00" * 13 def get_cipher_for_irk(irk: bytes) -> Cipher: return Cipher(algorithms.AES(irk), modes.ECB()) # noqa: S305 def resolve_private_address( cipher: Cipher, address: str, ) -> bool: rpa = binascii.unhexlify(address.replace(":", "")) if rpa[0] & 0xC0 != 0x40: # Not an RPA return False pt = PADDING + rpa[:3] encryptor = cipher.encryptor() ct = encryptor.update(pt) + encryptor.finalize() if ct[13:] != rpa[3:]: return False return True bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/py.typed000066400000000000000000000000001503112205700243440ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/time.py000066400000000000000000000027701503112205700241750ustar00rootroot00000000000000"""Bluetooth time utils.""" from __future__ import annotations import platform import time from collections.abc import Callable from contextlib import suppress from functools import partial CLOCK_MONOTONIC_COARSE = 6 def __gen_monotonic_time_coarse() -> partial[float]: """Return a function that provides monotonic time in seconds. This is the coarse version of time_monotonic, which is faster but less accurate. Since many arm64 and 32-bit platforms don't support VDSO with time.monotonic because of errata, we can't rely on the kernel to provide a fast monotonic time. https://lore.kernel.org/lkml/20170404171826.25030-1-marc.zyngier@arm.com/ """ # We use a partial here since its implementation is in native code # which allows us to avoid the overhead of the global lookup # of CLOCK_MONOTONIC_COARSE. return partial(time.clock_gettime, CLOCK_MONOTONIC_COARSE) monotonic_time_coarse: Callable[[], float] = time.monotonic _USE_COARSE_MONOTONIC_TIME = False with suppress(Exception): if ( platform.system() == "Linux" and abs(time.monotonic() - __gen_monotonic_time_coarse()()) < 1 ): monotonic_time_coarse = __gen_monotonic_time_coarse() _USE_COARSE_MONOTONIC_TIME = True if _USE_COARSE_MONOTONIC_TIME: with suppress(ImportError): from ._time_impl import ( # type: ignore[no-redef] # noqa: F811 F401 _monotonic_time_coarse as monotonic_time_coarse, ) __all__ = [ "monotonic_time_coarse", ] bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/utils.pxd000066400000000000000000000000641503112205700245340ustar00rootroot00000000000000cdef object L_PACK cpdef object mac_to_int(str mac) bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/utils.py000066400000000000000000000037241503112205700243770ustar00rootroot00000000000000"""Bluetooth utils.""" from __future__ import annotations from functools import lru_cache from struct import Struct L_PACK = Struct(">L") try: from ._utils_impl import _int_to_bluetooth_address # noqa: F811 F401 except ImportError: def _int_to_bluetooth_address(address: int) -> str: """Convert an integer to a bluetooth address.""" mac_hex = f"{address:012X}" return f"{mac_hex[0:2]}:{mac_hex[2:4]}:{mac_hex[4:6]}:{mac_hex[6:8]}:{mac_hex[8:10]}:{mac_hex[10:12]}" # noqa: E501 int_to_bluetooth_address = lru_cache(maxsize=256)(_int_to_bluetooth_address) def mac_to_int(address: str) -> int: """Convert a mac address to an integer.""" return int(address.replace(":", ""), 16) def short_address(address: str) -> str: """Convert a Bluetooth address to a short address.""" results = address.replace("-", ":").split(":") last: str = results[-1] second_last: str = results[-2] return f"{second_last.upper()}{last.upper()}"[-4:] def human_readable_name(name: str | None, local_name: str, address: str) -> str: """Return a human readable name for the given name, local_name, and address.""" return f"{name or local_name} ({short_address(address)})" def newest_manufacturer_data(manufacturer_data: dict[int, bytes]) -> bytes | None: """Return the raw data from manufacturer data.""" if manufacturer_data and (last_id := list(manufacturer_data)[-1]): return manufacturer_data[last_id] return None def address_to_bytes(address: str) -> bytes: """Return the address as bytes.""" if ":" not in address: address_as_int = 0 else: address_as_int = mac_to_int(address) return L_PACK.pack(address_as_int) def manufacturer_data_to_raw(manufacturer_id: int, manufacturer_data: bytes) -> bytes: """Return the raw data from manufacturer data.""" init_bytes: bytes = int(manufacturer_id).to_bytes(2, byteorder="little") return b"\x00" * 2 + init_bytes + manufacturer_data bluetooth-data-tools-1.28.2/src/bluetooth_data_tools/utils_wrapper.h000066400000000000000000000020121503112205700257230ustar00rootroot00000000000000#include /** * Convert the given integer bluetooth address to its hexadecimal string representation. * The buffer passed in must accept at least 17 bytes. It will NOT be null-terminated. */ void _uint64_to_bdaddr(uint64_t address, char bdaddr[17]) { static const char hex_table[] = "0123456789ABCDEF"; bdaddr[0] = hex_table[(address >> 44) & 0x0F]; bdaddr[1] = hex_table[(address >> 40) & 0x0F]; bdaddr[2] = ':'; bdaddr[3] = hex_table[(address >> 36) & 0x0F]; bdaddr[4] = hex_table[(address >> 32) & 0x0F]; bdaddr[5] = ':'; bdaddr[6] = hex_table[(address >> 28) & 0x0F]; bdaddr[7] = hex_table[(address >> 24) & 0x0F]; bdaddr[8] = ':'; bdaddr[9] = hex_table[(address >> 20) & 0x0F]; bdaddr[10] = hex_table[(address >> 16) & 0x0F]; bdaddr[11] = ':'; bdaddr[12] = hex_table[(address >> 12) & 0x0F]; bdaddr[13] = hex_table[(address >> 8) & 0x0F]; bdaddr[14] = ':'; bdaddr[15] = hex_table[(address >> 4) & 0x0F]; bdaddr[16] = hex_table[address & 0x0F]; } bluetooth-data-tools-1.28.2/tests/000077500000000000000000000000001503112205700170145ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/tests/__init__.py000066400000000000000000000000001503112205700211130ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/tests/benchmarks/000077500000000000000000000000001503112205700211315ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/tests/benchmarks/__init__.py000066400000000000000000000000001503112205700232300ustar00rootroot00000000000000bluetooth-data-tools-1.28.2/tests/benchmarks/test_int_to_bluetooth_address.py000066400000000000000000000006551503112205700276360ustar00rootroot00000000000000from pytest_codspeed import BenchmarkFixture from bluetooth_data_tools.utils import ( _int_to_bluetooth_address, int_to_bluetooth_address, ) def test_parse_int_to_bluetooth_address_uncached(benchmark: BenchmarkFixture) -> None: benchmark(lambda: _int_to_bluetooth_address(0)) def test_parse_int_to_bluetooth_address_cached(benchmark: BenchmarkFixture) -> None: benchmark(lambda: int_to_bluetooth_address(0)) bluetooth-data-tools-1.28.2/tests/benchmarks/test_parse_gap.py000066400000000000000000000137401503112205700245100ustar00rootroot00000000000000# cythonize -X language_level=3 -a -i src/bluetooth_data_tools/gap.py from pytest_codspeed import BenchmarkFixture from bluetooth_data_tools import parse_advertisement_data advs = [ b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x07\n\xffL\x00\x10\x05\x1f\x1c8#\xe2", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x1a\x02\n\x06\x11\xffL\x00\x0f\x08\xd0\n\x7fnt\x00\x08\x0c\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b'\x02\x01\x04\x03\x03\x07\xfe\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x03\x19\x00\x00\x02\n\x00', b'\x02\x01\x06\x16\xffL\x00\x061\x00\xcdnI\xa1\x91\xb2\x06\x007\x00\x04\x02\xcb\xd7,"\x04\x08LF0', b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x1e\xff\x01ZR\x02\xb4\xe8B\xdb\xcf\xd4\x00\x97\x0c\x03\x01\x02\x03\x04\x05\x06\x07\x08\t\xa1\xa2\xa3\xa4\xa5\xa6", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xd8.\xad\xcd\r\x85", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80\xa0\xf8\x04.\xe1\x9f\x19\xfa\x04.\xe1\x9f\x18\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33105\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x89\xc0\xa8j(", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b'\x02\x01\x02\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x02\n\t\x03\x03\x07\xfe', b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", ] def test_parse_advertisement_single_tuple(benchmark: BenchmarkFixture) -> None: advs_as_single_tuple = (b"".join(advs),) benchmark(lambda: parse_advertisement_data(advs_as_single_tuple)) def test_parse_advertisement_data_tuple(benchmark: BenchmarkFixture) -> None: advs_as_tuple = tuple(advs) benchmark(lambda: parse_advertisement_data(advs_as_tuple)) def test_parse_advertisement_data(benchmark: BenchmarkFixture) -> None: benchmark(lambda: parse_advertisement_data(advs)) bluetooth-data-tools-1.28.2/tests/benchmarks/test_parse_gap_bytes.py000066400000000000000000000136561503112205700257240ustar00rootroot00000000000000# cythonize -X language_level=3 -a -i src/bluetooth_data_tools/gap.py from pytest_codspeed import BenchmarkFixture from bluetooth_data_tools import parse_advertisement_data_bytes from bluetooth_data_tools.gap import _uncached_parse_advertisement_bytes advs = ( b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x07\n\xffL\x00\x10\x05\x1f\x1c8#\xe2", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x1a\x02\n\x06\x11\xffL\x00\x0f\x08\xd0\n\x7fnt\x00\x08\x0c\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b'\x02\x01\x04\x03\x03\x07\xfe\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x03\x19\x00\x00\x02\n\x00', b'\x02\x01\x06\x16\xffL\x00\x061\x00\xcdnI\xa1\x91\xb2\x06\x007\x00\x04\x02\xcb\xd7,"\x04\x08LF0', b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x1e\xff\x01ZR\x02\xb4\xe8B\xdb\xcf\xd4\x00\x97\x0c\x03\x01\x02\x03\x04\x05\x06\x07\x08\t\xa1\xa2\xa3\xa4\xa5\xa6", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xd8.\xad\xcd\r\x85", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80\xa0\xf8\x04.\xe1\x9f\x19\xfa\x04.\xe1\x9f\x18\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33105\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x89\xc0\xa8j(", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b'\x02\x01\x02\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x02\n\t\x03\x03\x07\xfe', b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", ) def test_parse_advertisement_data_bytes(benchmark: BenchmarkFixture) -> None: joined_advs = b"".join(advs) benchmark(lambda: parse_advertisement_data_bytes(joined_advs)) def test_parse_advertisement_data_tuple_bytes(benchmark: BenchmarkFixture) -> None: joined_advs = b"".join(advs) benchmark(lambda: _uncached_parse_advertisement_bytes(joined_advs)) bluetooth-data-tools-1.28.2/tests/benchmarks/test_parse_gap_tuple.py000066400000000000000000000136071503112205700257230ustar00rootroot00000000000000# cythonize -X language_level=3 -a -i src/bluetooth_data_tools/gap.py from pytest_codspeed import BenchmarkFixture from bluetooth_data_tools import parse_advertisement_data_tuple from bluetooth_data_tools.gap import _uncached_parse_advertisement_data advs = ( b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x07\n\xffL\x00\x10\x05\x1f\x1c8#\xe2", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x1a\x02\n\x06\x11\xffL\x00\x0f\x08\xd0\n\x7fnt\x00\x08\x0c\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b'\x02\x01\x04\x03\x03\x07\xfe\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x03\x19\x00\x00\x02\n\x00', b'\x02\x01\x06\x16\xffL\x00\x061\x00\xcdnI\xa1\x91\xb2\x06\x007\x00\x04\x02\xcb\xd7,"\x04\x08LF0', b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x13\xc0\xa8k\xef", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x1e\xff\x01ZR\x02\xb4\xe8B\xdb\xcf\xd4\x00\x97\x0c\x03\x01\x02\x03\x04\x05\x06\x07\x08\t\xa1\xa2\xa3\xa4\xa5\xa6", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xd8.\xad\xcd\r\x85", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x1b\xffu\x00B\x04\x01\x80n\xe0\x9d\x13\x99\x0f\xf3\xe2\x9d\x13\x99\x0f\xf2\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x1b\xffu\x00B\x04\x01\x80\xa0\xf8\x04.\xe1\x9f\x19\xfa\x04.\xe1\x9f\x18\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33105\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33231\x03\x19\xc1\x03", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B4\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x06\x0e\xffL\x00\x0f\x05\x90\x00QB\n\x10\x02#\x04", b"\x02\x01\x06\x16\xffL\x00\x061\x00\x8aO\xa3\xed?\x1e\x05\x00H\x04\x01\x02\xd8E\xf3\xc6\x04\x08Nan", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03\x89\xc0\xa8j(", b"\x02\x01\x06\t\xffY\x00\xc5-^\xabRv", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x02$\xfe\x04\xff\xd1\x01\x00", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b'\x02\x01\x02\x10\xff\xa7\x05\x05\x10\x01\x00\x00\x00\x00\x00\x00\x02"\x00\xca\x02\n\t\x03\x03\x07\xfe', b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x0f\xffi\t`U\xf97\x95\x06.\x00\x00<\x00\x00", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F331F5\x03\x19\xc1\x03", b"\x1b\xffu\x00B\x04\x01\x80f\x8c\xeaHM\x93;\x8e\xeaHM\x93:\x01\x00\x00\x00\x00\x00\x00", b"\x02\x01\x06\x05\tRZSS", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330C2\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33208\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330F3\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F33163\x03\x19\xc1\x03", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F3320D\x03\x19\xc1\x03", b"\x02\x01\x1a\x0b\xffL\x00\t\x06\x03+\xc0\xa8kZ", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", b"\x02\x01\x1a\x02\n\x0c\n\xffL\x00\x10\x05\x1b\x1c\x03\xc5\xbe", b"\x02\x01\x06\x03\x03\x12\x18\x10\tLOOKin_98F330B5\x03\x19\xc1\x03", ) def test_parse_advertisement_data_tuple(benchmark: BenchmarkFixture) -> None: benchmark(lambda: parse_advertisement_data_tuple(advs)) def test_parse_advertisement_data_tuple_uncached(benchmark: BenchmarkFixture) -> None: joined_advs = b"".join(advs) benchmark(lambda: _uncached_parse_advertisement_data(joined_advs)) bluetooth-data-tools-1.28.2/tests/test_distance.py000066400000000000000000000012041503112205700222140ustar00rootroot00000000000000"""Test utils.""" from bluetooth_data_tools import calculate_distance_meters def tests_calculate_distance_meters(): """Test distance estimate calculation.""" assert calculate_distance_meters(-59, -60) == 1.1352362990362899 assert calculate_distance_meters(59, -60) == 1.183020818815412 assert calculate_distance_meters(12, -80) == 400.0 assert calculate_distance_meters(59, 0) is None assert calculate_distance_meters(-3, -100) == 400.0 assert calculate_distance_meters(-3, -96) == 400.0 assert calculate_distance_meters(-3, -3) == 1.01076 assert calculate_distance_meters(-4, -3) == 0.056313514709472656 bluetooth-data-tools-1.28.2/tests/test_gap.py000066400000000000000000000632251503112205700212040ustar00rootroot00000000000000import base64 import pytest from bluetooth_data_tools import ( parse_advertisement_data, parse_advertisement_data_bytes, parse_advertisement_data_tuple, ) def test_parse_advertisement_data_Prodigio_D83567A4F5A5_bytes(): data = b"".join( [ base64.b64decode("AgoEFglQcm9kaWdpb19EODM1NjdBNEY1QTU="), base64.b64decode("AgEGEQYbxdWlAgCqneMRKvIQGaoGCf8CJUQJgAcAAg=="), ] ) (local_name, service_uuids, service_data, manufacturer_data, tx_power) = ( parse_advertisement_data_bytes(data) ) assert local_name == "Prodigio_D83567A4F5A5" assert service_uuids == ["06aa1910-f22a-11e3-9daa-0002a5d5c51b"] assert service_data == {} assert manufacturer_data == {9474: b"D\t\x80\x07\x00\x02"} assert tx_power == 4 def test_parse_advertisement_data_Prodigio_D83567A4F5A5(): data = [ base64.b64decode("AgoEFglQcm9kaWdpb19EODM1NjdBNEY1QTU="), base64.b64decode("AgEGEQYbxdWlAgCqneMRKvIQGaoGCf8CJUQJgAcAAg=="), ] adv = parse_advertisement_data(data) assert adv.local_name == "Prodigio_D83567A4F5A5" assert adv.service_uuids == ["06aa1910-f22a-11e3-9daa-0002a5d5c51b"] assert adv.service_data == {} assert adv.manufacturer_data == {9474: b"D\t\x80\x07\x00\x02"} assert adv.tx_power == 4 def test_parse_advertisement_data_unknown_apple_device(): data = [ base64.b64decode("AgEaAgoFCv9MABAFChx3+Vs="), ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {76: b"\x10\x05\n\x1cw\xf9["} assert adv.tx_power == 5 def test_parse_advertisement_data_empty(): data = [ b"\x00", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_flags_only(): data = [ b"\x01\x01\x06", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_ignores_invalid(): data = [ b"\x02\x01\x1a\x02\n\x05\n\xffL\x00\x10\x05\n\x1cw\xf9[\x02\x01", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {76: b"\x10\x05\n\x1cw\xf9["} assert adv.tx_power == 5 def test_parse_advertisement_data_ignores_zero_type(): data = [ b"\x02\x01\x1a\x02\n\x05\n\xffL\x00\x10\x05\n\x1cw\xf9[\x02\x00", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {76: b"\x10\x05\n\x1cw\xf9["} assert adv.tx_power == 5 def test_parse_advertisement_data_unknown_fd3d(): data = [ base64.b64decode("AgEGD/9pCWBV+Tw02tgAEDEAAA=="), base64.b64decode("BhY9/WcAZA=="), ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {"0000fd3d-0000-1000-8000-00805f9b34fb": b"g\x00d"} assert adv.manufacturer_data == {2409: b"`U\xf9<4\xda\xd8\x00\x101\x00\x00"} assert adv.tx_power is None def test_parse_advertisement_data_moat(): data = [ base64.b64decode("AgEGAwMAEBUWABDfeeOmErMVUHBjVGIcb7kL//8="), base64.b64decode("AgoAAwMAIAsWAFDfeeOmErO5CwgJTW9hdF9TMg=="), ] adv = parse_advertisement_data(data) assert adv.local_name == "Moat_S2" assert adv.service_uuids == [ "00001000-0000-1000-8000-00805f9b34fb", "00002000-0000-1000-8000-00805f9b34fb", ] assert adv.service_data == { "00001000-0000-1000-8000-00805f9b34fb": b"\xdfy\xe3\xa6\x12\xb3\x15PpcTb" b"\x1co\xb9\x0b\xff\xff", "00005000-0000-1000-8000-00805f9b34fb": b"\xdfy\xe3\xa6\x12\xb3\xb9\x0b", } assert adv.manufacturer_data == {} assert adv.tx_power == 0 def test_parse_advertisement_data_unknown_apple_215(): data = [ base64.b64decode("AgEGGv9MAAIV1Ubfl0dXR+++CT4ty90MdxU2zcm1"), ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == { 76: b"\x02\x15\xd5F\xdf\x97GWG\xef\xbe\t>-\xcb\xdd\x0cw\x156\xcd\xc9\xb5" } assert adv.tx_power is None def test_parse_advertisement_data_oral_b_toothbrush(): data = [ base64.b64decode("AgEGDv/cAAYyawNSAAEECQAEAwIN/g=="), base64.b64decode("EglPcmFsLUIgVG9vdGhicnVzaAUSEABQAAIKAA=="), ] adv = parse_advertisement_data(data) assert adv.local_name == "Oral-B Toothbrush" assert adv.service_uuids == ["0000fe0d-0000-1000-8000-00805f9b34fb"] assert adv.service_data == {} assert adv.manufacturer_data == {220: b"\x062k\x03R\x00\x01\x04\t\x00\x04"} assert adv.tx_power == 0 assert parse_advertisement_data_tuple(tuple(data)) == ( "Oral-B Toothbrush", ["0000fe0d-0000-1000-8000-00805f9b34fb"], {}, {220: b"\x062k\x03R\x00\x01\x04\t\x00\x04"}, 0, ) def test_parse_advertisement_short_local_name(): data = [ base64.b64decode("AgEGFv9MAAYxAOTEm+77PgUADQABAmMRIGUECE5hbg=="), ] adv = parse_advertisement_data(data) assert adv.local_name == "Nan" assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == { 76: b"\x061\x00\xe4\xc4\x9b\xee\xfb>\x05\x00\r\x00\x01\x02c\x11 e" } assert adv.tx_power is None def test_parse_advertisement_data_32bit_service_data(): data = [ b"\x07\x20\x1a\x02\n\x05\n\xff", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {"050a021a-0000-1000-8000-00805f9b34fb": b"\n\xff"} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_128bit_service_data(): data = [ b"\x12\x21\x1a\x02\n\x05\n\xff\x062k\x03R\x00\x01\x04\t\x00\x04", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {"00090401-0052-036b-3206-ff0a050a021a": b"\x04"} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_32bit_and_128bit_service_data(): data = [ b"\x07\x20\x1a\x02\n\x05\n\xff", b"\x12\x21\x1a\x02\n\x05\n\xff\x062k\x03R\x00\x01\x04\t\x00\x04", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == { "00090401-0052-036b-3206-ff0a050a021a": b"\x04", "050a021a-0000-1000-8000-00805f9b34fb": b"\n\xff", } assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_128bit_and_32bit_service_data(): data = [ b"\x12\x21\x1a\x02\n\x05\n\xff\x062k\x03R\x00\x01\x04\t\x00\x04", b"\x07\x20\x1a\x02\n\x05\n\xff", ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == { "00090401-0052-036b-3206-ff0a050a021a": b"\x04", "050a021a-0000-1000-8000-00805f9b34fb": b"\n\xff", } assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_128bit_service_data_tuple(): data = (b"\x12\x21\x1a\x02\n\x05\n\xff\x062k\x03R\x00\x01\x04\t\x00\x04",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {"00090401-0052-036b-3206-ff0a050a021a": b"\x04"} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_zero_padded(): data = [ bytes.fromhex( "02.01.06.0E.FF.69.09.FA.62.0F.CF.2D.F2.DA.0F" ".00.22.04.00.09.16.3D.FD.63.C0.56.00.22.04".replace(".", "") ) ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == { "0000fd3d-0000-1000-8000-00805f9b34fb": b'c\xc0V\x00"\x04' } assert adv.manufacturer_data == {2409: b'\xfab\x0f\xcf-\xf2\xda\x0f\x00"\x04'} assert adv.tx_power is None def test_parse_adv_data(): data = [ bytes.fromhex( "02.01.06.05.02.E0.FF.E7.FE.0B.FF.65.0B.88.A0" ".C8.47.8C.EA.D1.C1.0C.09.4D.32.5F.42.31.41.38" ".53.31.30.50".replace(".", "") ) ] adv = parse_advertisement_data(data) assert adv.local_name == "M2_B1A8S10P" assert adv.service_uuids == [ "0000ffe0-0000-1000-8000-00805f9b34fb", "0000fee7-0000-1000-8000-00805f9b34fb", ] assert adv.service_data == {} assert adv.manufacturer_data == {2917: b"\x88\xa0\xc8G\x8c\xea\xd1\xc1"} assert adv.tx_power is None def test_parse_multiple_16bit_uuids(): """Test parsing advertisement data with 3 16-bit service UUIDs.""" # Build advertisement data with 3 16-bit UUIDs # Length: 7 (1 byte type + 6 bytes for 3 UUIDs) # Type: 0x02 (16-bit service UUID more available) # UUIDs in little-endian: 0x1234 -> 3412, 0x5678 -> 7856, 0x9ABC -> BC9A data = [bytes.fromhex("070234127856BC9A")] adv = parse_advertisement_data(data) assert adv.service_uuids == [ "00001234-0000-1000-8000-00805f9b34fb", "00005678-0000-1000-8000-00805f9b34fb", "00009abc-0000-1000-8000-00805f9b34fb", ] assert adv.local_name is None assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_multiple_32bit_uuids(): """Test parsing advertisement data with 2 32-bit service UUIDs.""" # Build advertisement data with 2 32-bit UUIDs # Length: 9 (1 byte type + 8 bytes for 2 UUIDs) # Type: 0x04 (32-bit service UUID more available) # UUIDs in little-endian: 0x12345678 -> 78563412, 0x9ABCDEF0 -> F0DEBC9A data = [bytes.fromhex("090478563412F0DEBC9A")] adv = parse_advertisement_data(data) assert adv.service_uuids == [ "12345678-0000-1000-8000-00805f9b34fb", "9abcdef0-0000-1000-8000-00805f9b34fb", ] assert adv.local_name is None assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_mixed_16bit_32bit_uuids(): """Test parsing advertisement data with 16-bit UUID followed by 32-bit UUID.""" # Build advertisement data with: # - One 16-bit UUID: 0x1234 # - Two 32-bit UUIDs: 0x56789ABC, 0xDEF01234 data = [ bytes.fromhex( "03023412" # Length=3, Type=0x02, UUID=0x1234 (little-endian) "090478563412F0DEBC9A" # Length=9, Type=0x04, UUIDs in little-endian ) ] adv = parse_advertisement_data(data) assert adv.service_uuids == [ "00001234-0000-1000-8000-00805f9b34fb", # 16-bit "12345678-0000-1000-8000-00805f9b34fb", # 32-bit "9abcdef0-0000-1000-8000-00805f9b34fb", # 32-bit ] assert adv.local_name is None assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_mixed_16bit_128bit_uuids(): """Test parsing advertisement data with 16-bit UUID followed by 128-bit UUID.""" # Build advertisement data with: # - One 16-bit UUID: 0x1234 # - One 128-bit UUID: 550e8400-e29b-41d4-a716-446655440000 # Note: 128-bit UUIDs are stored in reverse byte order in BLE data = [ bytes.fromhex( "03023412" # Length=3, Type=0x02, UUID=0x1234 (little-endian) "110600004455664416a7d4419be200840e55" # Length=17, Type=0x06, 128-bit UUID (reversed) ) ] adv = parse_advertisement_data(data) assert adv.service_uuids == [ "00001234-0000-1000-8000-00805f9b34fb", # 16-bit "550e8400-e29b-41d4-a716-446655440000", # 128-bit ] assert adv.local_name is None assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_zero_padded_scan_included(): data = [ b"\x02\x01\x06\t\xffY\x00\xfe\x024\x9e\xa6\xba\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x07\x1b\xc5\xd5\xa5\x02\x00\xb8" b'\x9f\xe6\x11M"\x00\r\xa2\xcb\x06\x16\x00\rH\x10\x00\x00\x00\x00\x00\x00\x00' ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == ["cba20d00-224d-11e6-9fb8-0002a5d5c51b"] assert adv.service_data == {"00000d00-0000-1000-8000-00805f9b34fb": b"H\x10\x00"} assert adv.manufacturer_data == {89: b"\xfe\x024\x9e\xa6\xba"} assert adv.tx_power is None def test_parse_advertisement_data_recovers_from_corrupt_data(): data = [ b"\x03\x03\x9f\xfe\x17\x16\x9f\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x06\xf8" ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == ["0000fe9f-0000-1000-8000-00805f9b34fb"] assert adv.service_data == { "0000fe9f-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_recovers_from_corrupt_data_2(): data = [ b"\x1a\xff\xc3\x03_\xef5B\xb0I\x0f\xbb\x00&\x01\x00m*" b"\xb2c\xd8\xb0\x02\n\x00\x00\xf2\x02\x01\x06 " ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == { 963: b"_\xef5B\xb0I\x0f\xbb\x00&\x01\x00m*\xb2c\xd8\xb0\x02\n\x00\x00\xf2" } assert adv.tx_power is None def test_parse_advertisement_data_recovers_from_corrupt_data_3(): data = [ b"\x03\x03\x9f\xfe\x17\x16\x9f\xfe\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x06 " ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == ["0000fe9f-0000-1000-8000-00805f9b34fb"] assert adv.service_data == { "0000fe9f-0000-1000-8000-00805f9b34fb": b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" } assert adv.manufacturer_data == {} assert adv.tx_power is None def test_parse_advertisement_data_recovers_from_corrupt_data_43(): data = [ b"\x1a\xff\xc3\x03_\xef5B\xb3I\x0f\xbb\x00&\x01\x01m*" b"\xb2c\xd8.\x02\n\x00\x00\xf2\x02\x01\xc6\xf8" ] adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == { 963: b"_\xef5B\xb3I\x0f\xbb\x00&\x01\x01m*\xb2c\xd8.\x02\n\x00\x00\xf2" } assert adv.tx_power is None def test_name_parser(): """Test parsing name from https://github.com/esphome/issues/issues/4838.""" data = ( b"\t\tPineTime\002\001\006\021\007\236\312\334$\016\345\251(340\223\363\243\265\001\000@n", ) adv = parse_advertisement_data(data) assert adv.local_name == "PineTime" assert adv.service_uuids == ["01b5a3f3-9330-3433-28a9-e50e24dcca9e"] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( "PineTime", ["01b5a3f3-9330-3433-28a9-e50e24dcca9e"], {}, {}, None, ) def test_invalid_gap_num(): """Test skip invalid gap type.""" data = ( b"\t\x00PineTime\002\001\006\021\007\236\312\334$\016\345\251(340\223\363\243\265\001\000@n", ) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == ["01b5a3f3-9330-3433-28a9-e50e24dcca9e"] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, ["01b5a3f3-9330-3433-28a9-e50e24dcca9e"], {}, {}, None, ) def test_out_of_bounds_length(): """Test out of bound length.""" data = ( b"\xff\x00PineTime\002\001\006\021\007\236\312\334$\016\345\251(340\223\363\243\265\001\000@n", ) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_out_of_bounds_length_by_one(): """Test out of bound length by one.""" data = (b"\x01\x08",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_manufacturer_data_short_by_one(): """Test short manufacturer data.""" data = (b"\x02\xff\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_manufacturer_data_short_by_two(): """Test short manufacturer data.""" data = (b"\x02\xff\x01\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_manufacturer_data_short_by_three(): """Test short manufacturer data.""" data = (b"\x03\xff\x01\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_manufacturer_data_short_by_five(): """Test short manufacturer data.""" data = (b"\x05\xff\x01\x01\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_manufacturer_data_single_byte(): """Test single byte manufacturer data.""" data = (b"\x04\xff\x01\x01\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {257: b"\x01"} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {257: b"\x01"}, None, ) def test_service_data_short(): """Test short service data.""" data = (b"\x02\x16\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_32bit_uuid_short(): """Test short 32bit uuid data.""" data = (b"\x02 \x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_128bit_uuid_short(): """Test short 128bit uuid data.""" data = (b"\x02!\x01",) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( None, [], {}, {}, None, ) def test_zero_padded_end(): """Test name with zero padded end.""" data = (b"\x02\x08a\x00",) adv = parse_advertisement_data(data) assert adv.local_name == "a" assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple(tuple(data)) == ( "a", [], {}, {}, None, ) def test_zero_padded_out_of_bounds_length(): """Test zero padded out of bound length.""" data = ( b"\x00\xff\x00PineTime\002\001\006\021\007\236\312\334$\016\345\251(340\223\363\243\265\001\000@n", ) adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple( tuple( data, ) ) == ( None, [], {}, {}, None, ) def test_data_shorter_than_length() -> None: """Test data shorter than length.""" for len in range(0, 30): data = bytes((len,)) + b"!\x01" adv = parse_advertisement_data((data,)) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple((data,)) == ( None, [], {}, {}, None, ) @pytest.mark.parametrize( "data", [ (b"\x02 a\xc4|\x04@*'\x9c\xa5C\r\xa1\xe6\x1e\xe7\x8f\xa57D\xe6$\x03",), ( b"\xe8\x9d\x83\x8b\x96\x85\x07U\x19$&\x1c\x91\x80\xba\x04Z", b'"EU\xcb\x11\xeb\xdc\xd4)\xc9\x1b\x8c\xfe\x1e\xd7\xca\x98\xfe\xcd%\xf6>\xbb\xe3\xbc\xfc5', b"(\x86\x18\xe9m>\x89\xa7\xe1=\x9fE\x0f\xbcE\xb2<", ), ( b"\xf4\x9e\x0f!\x93n\xae\x1e\x89\xc2\xb4\x97\x98\xdc~\x9a\xb3\x06\x7f\x11", b"\x89\xc2\x07\xff\xe7QEG&;\x06\xab\xebN\xf5\xc4g\xfe", b"\xeb\x852\x0b,KB", ), ( b'\xcbu\xa5\xe4\xa1\xdd`c\x88\xa9\xe2\xaah\xe5"%X\x87\xf0', b'\xac;\x8f\xc43!\xb0?"\xb8\n<', b"\x10nyT\xed\x96\x07\x9a", ), ( b"\r\xd6'\xder\xfc@T\xb3Q\x12EH\x9e\xe9\xf8x\xe3\xcc\ti\xfb", b"\xfe@\x89", b"Gt\xc3_\xf9\x8e\xdd#", ), ( b'\x17b\x02c\xbe%"\x06\xfe\x05c4\x04\x97\x03)|\xd0\xf4\xeb~\xb1gI', b"r\xc0\x9a>^o\xcb\xdb\xc2r\xca\x1a'VL\xac\xd7\x8e\xa7\xeb\xc2:\xe2_\x96\xe31r", b"\\^\xe6\x96]%\x17\x02\xa5\xdcAE\x92\xb2\x1c\x1a\xd4Y\x07\xddZ\xebC\x12B\xb6\xcb\x8a", ), ( b"\x1b\x87c\xb7\x12nK\xf3_\xb4\x18)x<\xe2\x05\xc8\xdb\xf8\x1b\xf7 \xe6\x99\xe3Z\xd1C\x88\xda\x98", b"\xbb\xbe@,\xa6\xdcj*\x85u\xe3\xc4", b"w\xb7\xeb\xb0", ), ( b"\x88\x83\x7fN\xd0E\xa6\xc5(h\xcd\xe7\x80\\\xf0\xe6n:\x10K\x02\x92", b"\xc5\xe6`a\xf7\xf5 \x1eV\xd6]8$\xf0\xf0", b"\x01rS\xf1\xe2ht\xd6\x8f\xc6\x0e\xd0~", ), ( b"\x10\xa6\xc4}\xb6\xc9n\x00", b"\xa8\xd8#'@\xde\x9a\xf6;&\x88\x0f\xc1m\xe5v\xa3\x17O\x8b\x92\x94\\\x91\x8b\xee\xa1\xed", b'\xccA\x9c\x01;\xd1\xe8e\xeb\xf3\x8b\xa1\xd6\xe5P]\xc7"_@\x10\x1e\x8b\x90o\r\xd9', ), ], ) def test_negative_splice_pos_does_not_crash(data: tuple[bytes, bytes, bytes]) -> None: """Test data that would cause a negative splice position. All of the data here will result in a negative splice position when attempting to parse the advertisement data. This is a regression test to ensure that the parser does not crash when it encounters this data. A negative splice position is caused by the parser attempting to splice the data at a position that is greater than the length of the data. This can happen when the data is malformed or when the parser is attempting to parse data that is not in the expected format. The parser should be able to handle this gracefully and return an empty advertisement object without crashing. """ adv = parse_advertisement_data(data) assert adv.local_name is None assert adv.service_uuids == [] assert adv.service_data == {} assert adv.manufacturer_data == {} assert adv.tx_power is None assert parse_advertisement_data_tuple( tuple( data, ) ) == ( None, [], {}, {}, None, ) bluetooth-data-tools-1.28.2/tests/test_gap_fuzzer.py000066400000000000000000000010421503112205700225760ustar00rootroot00000000000000import random from bluetooth_data_tools.gap import _uncached_parse_advertisement_data def test_gap_fuzzer() -> None: """Test random data does not crash.""" for i in range(1000): adv = ( bytes([random.randint(0, 255) for _ in range(random.randint(1, 31))]), bytes([random.randint(0, 255) for _ in range(random.randint(1, 31))]), bytes([random.randint(0, 255) for _ in range(random.randint(1, 31))]), ) print([i, adv]) _uncached_parse_advertisement_data(b"".join(adv)) bluetooth-data-tools-1.28.2/tests/test_privacy.py000066400000000000000000000006521503112205700221050ustar00rootroot00000000000000from bluetooth_data_tools import get_cipher_for_irk, resolve_private_address def test_resolve_private_address(): cipher = get_cipher_for_irk(b"\x00" * 16) assert resolve_private_address(cipher, "40:01:02:0a:c4:a6") assert resolve_private_address(cipher, "40:02:03:d2:74:ce") assert not resolve_private_address(cipher, "40:00:00:d2:74:ce") assert not resolve_private_address(cipher, "00:01:ff:a0:3a:76") bluetooth-data-tools-1.28.2/tests/test_utils.py000066400000000000000000000030001503112205700215560ustar00rootroot00000000000000from bluetooth_data_tools import ( address_to_bytes, human_readable_name, int_to_bluetooth_address, mac_to_int, manufacturer_data_to_raw, newest_manufacturer_data, short_address, ) def test_int_to_bluetooth_address(): assert int_to_bluetooth_address(0) == "00:00:00:00:00:00" assert int_to_bluetooth_address(1) == "00:00:00:00:00:01" assert int_to_bluetooth_address(0xFFFFFFFFFFFF) == "FF:FF:FF:FF:FF:FF" assert int_to_bluetooth_address(0x123456789ABC) == "12:34:56:78:9A:BC" assert int_to_bluetooth_address(0xDEF012345678) == "DE:F0:12:34:56:78" def test_newest_manufacturer_data(): data = {1: b"\x01\x02\x03\x04"} assert newest_manufacturer_data(data) == b"\x01\x02\x03\x04" assert newest_manufacturer_data({}) is None def test_address_to_bytes(): assert address_to_bytes("00:00:00:00:00:00") == b"\x00\x00\x00\x00" assert address_to_bytes("a-c-b") == b"\x00\x00\x00\x00" def test_manufacturer_data_to_raw(): assert ( manufacturer_data_to_raw(1, b"\x01\x02\x03\x04") == b"\x00\x00\x01\x00\x01\x02\x03\x04" ) def test_short_address(): assert short_address("AA:BB:CC:DD:EE:FF") == "EEFF" def test_human_readable_name(): assert ( human_readable_name("My Device", "Your Device", "AA:BB:CC:DD:EE:FF") == "My Device (EEFF)" ) def test_mac_to_int(): assert mac_to_int("00:00:00:00:00:00") == 0 assert mac_to_int("00:00:00:00:00:01") == 1 assert mac_to_int("FF:FF:FF:FF:FF:FF") == 0xFFFFFFFFFFFF