.*)"
34 |
35 | frame_regex = (
36 | frame_start
37 | + frame_length
38 | + frame_engineering_mode
39 | + frame_head
40 | + frame_target_state
41 | + frame_moving_target_distance
42 | + frame_moving_target_energy
43 | + frame_static_target_distance
44 | + frame_static_target_energy
45 | + frame_detection_distance
46 | + frame_engineering_data
47 | + frame_tail
48 | + frame_check
49 | + frame_end
50 | )
51 |
52 | engineering_frame_regex = (
53 | frame_maximum_motion_gates
54 | + frame_maximum_static_gates
55 | + frame_motion_energy_gates
56 | + frame_static_energy_gates
57 | + frame_additional_information
58 | )
59 |
--------------------------------------------------------------------------------
/.github/labels.toml:
--------------------------------------------------------------------------------
1 | [breaking]
2 | color = "ffcc00"
3 | name = "breaking"
4 | description = "Breaking change."
5 |
6 | [bug]
7 | color = "d73a4a"
8 | name = "bug"
9 | description = "Something isn't working"
10 |
11 | [dependencies]
12 | color = "0366d6"
13 | name = "dependencies"
14 | description = "Pull requests that update a dependency file"
15 |
16 | [github_actions]
17 | color = "000000"
18 | name = "github_actions"
19 | description = "Update of github actions"
20 |
21 | [documentation]
22 | color = "1bc4a5"
23 | name = "documentation"
24 | description = "Improvements or additions to documentation"
25 |
26 | [duplicate]
27 | color = "cfd3d7"
28 | name = "duplicate"
29 | description = "This issue or pull request already exists"
30 |
31 | [enhancement]
32 | color = "a2eeef"
33 | name = "enhancement"
34 | description = "New feature or request"
35 |
36 | ["good first issue"]
37 | color = "7057ff"
38 | name = "good first issue"
39 | description = "Good for newcomers"
40 |
41 | ["help wanted"]
42 | color = "008672"
43 | name = "help wanted"
44 | description = "Extra attention is needed"
45 |
46 | [invalid]
47 | color = "e4e669"
48 | name = "invalid"
49 | description = "This doesn't seem right"
50 |
51 | [nochangelog]
52 | color = "555555"
53 | name = "nochangelog"
54 | description = "Exclude pull requests from changelog"
55 |
56 | [question]
57 | color = "d876e3"
58 | name = "question"
59 | description = "Further information is requested"
60 |
61 | [removed]
62 | color = "e99695"
63 | name = "removed"
64 | description = "Removed piece of functionalities."
65 |
66 | [tests]
67 | color = "bfd4f2"
68 | name = "tests"
69 | description = "CI, CD and testing related changes"
70 |
71 | [wontfix]
72 | color = "ffffff"
73 | name = "wontfix"
74 | description = "This will not be worked on"
75 |
76 | [discussion]
77 | color = "c2e0c6"
78 | name = "discussion"
79 | description = "Some discussion around the project"
80 |
81 | [hacktoberfest]
82 | color = "ffa663"
83 | name = "hacktoberfest"
84 | description = "Good issues for Hacktoberfest"
85 |
86 | [answered]
87 | color = "0ee2b6"
88 | name = "answered"
89 | description = "Automatically closes as answered after a delay"
90 |
91 | [waiting]
92 | color = "5f7972"
93 | name = "waiting"
94 | description = "Automatically closes if no answer after a delay"
95 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 |
9 | concurrency:
10 | group: ${{ github.head_ref || github.run_id }}
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | lint:
15 | runs-on: ubuntu-latest
16 | steps:
17 | - uses: actions/checkout@v3
18 | - uses: actions/setup-python@v3
19 | with:
20 | python-version: "3.9"
21 | - uses: pre-commit/action@v2.0.3
22 |
23 | # Make sure commit messages follow the conventional commits convention:
24 | # https://www.conventionalcommits.org
25 | commitlint:
26 | name: Lint Commit Messages
27 | runs-on: ubuntu-latest
28 | steps:
29 | - uses: actions/checkout@v3
30 | with:
31 | fetch-depth: 0
32 | - uses: wagoid/commitlint-github-action@v4.1.11
33 |
34 | test:
35 | strategy:
36 | fail-fast: false
37 | matrix:
38 | python-version:
39 | - "3.9"
40 | - "3.10"
41 | os:
42 | - ubuntu-latest
43 | runs-on: ${{ matrix.os }}
44 | steps:
45 | - uses: actions/checkout@v3
46 | - name: Set up Python
47 | uses: actions/setup-python@v3
48 | with:
49 | python-version: ${{ matrix.python-version }}
50 | - uses: snok/install-poetry@v1
51 | - name: Install Dependencies
52 | run: poetry install
53 | - name: Test with Pytest
54 | run: poetry run pytest --cov-report=xml
55 | - name: Upload coverage to Codecov
56 | uses: codecov/codecov-action@v3
57 | with:
58 | token: ${{ secrets.CODECOV_TOKEN }}
59 |
60 | release:
61 | runs-on: ubuntu-latest
62 | environment: release
63 | if: github.ref == 'refs/heads/main'
64 | needs:
65 | - test
66 | - lint
67 | - commitlint
68 |
69 | steps:
70 | - uses: actions/checkout@v3
71 | with:
72 | fetch-depth: 0
73 |
74 | # Run semantic release:
75 | # - Update CHANGELOG.md
76 | # - Update version in code
77 | # - Create git tag
78 | # - Create GitHub release
79 | # - Publish to PyPI
80 | - name: Python Semantic Release
81 | uses: relekang/python-semantic-release@v7.31.4
82 | with:
83 | github_token: ${{ secrets.GITHUB_TOKEN }}
84 | pypi_token: ${{ secrets.PYPI_TOKEN }}
85 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "ld2410-ble"
3 | version = "0.2.0"
4 | description = "Interface with LD2410B modules from HiLink"
5 | authors = ["930913 <3722064+930913@users.noreply.github.com>"]
6 | license = "Apache Software License 2.0"
7 | readme = "README.md"
8 | repository = "https://github.com/930913/ld2410-ble"
9 | documentation = "https://ld2410-ble.readthedocs.io"
10 | classifiers = [
11 | "Development Status :: 2 - Pre-Alpha",
12 | "Intended Audience :: Developers",
13 | "Natural Language :: English",
14 | "Operating System :: OS Independent",
15 | "Topic :: Software Development :: Libraries",
16 | ]
17 | packages = [
18 | { include = "ld2410_ble", from = "src" },
19 | ]
20 |
21 | [tool.poetry.urls]
22 | "Bug Tracker" = "https://github.com/930913/ld2410-ble/issues"
23 | "Changelog" = "https://github.com/930913/ld2410-ble/blob/main/CHANGELOG.md"
24 |
25 | [tool.poetry.dependencies]
26 | python = "^3.9"
27 |
28 | # Documentation Dependencies
29 | Sphinx = {version = "^5.0", optional = true}
30 | sphinx-rtd-theme = {version = "^1.0", optional = true}
31 | myst-parser = {version = "^0.18", optional = true}
32 | bleak-retry-connector = ">=2.3.0"
33 | bleak = ">=0.19.0"
34 | async-timeout = ">=4.0.1"
35 |
36 | [tool.poetry.extras]
37 | docs = [
38 | "myst-parser",
39 | "sphinx",
40 | "sphinx-rtd-theme",
41 | ]
42 |
43 | [tool.poetry.dev-dependencies]
44 | pytest = "^7.0"
45 | pytest-cov = "^3.0"
46 |
47 | [tool.semantic_release]
48 | branch = "main"
49 | version_toml = "pyproject.toml:tool.poetry.version"
50 | version_variable = "src/ld2410_ble/__init__.py:__version__"
51 | build_command = "pip install poetry && poetry build"
52 |
53 | [tool.pytest.ini_options]
54 | addopts = "-v -Wdefault --cov=ld2410_ble --cov-report=term-missing:skip-covered"
55 | pythonpath = ["src"]
56 |
57 | [tool.coverage.run]
58 | branch = true
59 |
60 | [tool.coverage.report]
61 | exclude_lines = [
62 | "pragma: no cover",
63 | "@overload",
64 | "if TYPE_CHECKING",
65 | "raise NotImplementedError",
66 | ]
67 |
68 | [tool.isort]
69 | profile = "black"
70 | known_first_party = ["ld2410_ble", "tests"]
71 |
72 | [tool.mypy]
73 | check_untyped_defs = true
74 | disallow_any_generics = true
75 | disallow_incomplete_defs = true
76 | disallow_untyped_defs = true
77 | mypy_path = "src/"
78 | no_implicit_optional = true
79 | show_error_codes = true
80 | warn_unreachable = true
81 | warn_unused_ignores = true
82 | exclude = [
83 | 'docs/.*',
84 | 'setup.py',
85 | ]
86 |
87 | [[tool.mypy.overrides]]
88 | module = "tests.*"
89 | allow_untyped_defs = true
90 |
91 | [[tool.mypy.overrides]]
92 | module = "docs.*"
93 | ignore_errors = true
94 |
95 | [build-system]
96 | requires = ["poetry-core>=1.0.0"]
97 | build-backend = "poetry.core.masonry.api"
98 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Python template
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | share/python-wheels/
26 | *.egg-info/
27 | .installed.cfg
28 | *.egg
29 | MANIFEST
30 |
31 | # PyInstaller
32 | # Usually these files are written by a python script from a template
33 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
34 | *.manifest
35 | *.spec
36 |
37 | # Installer logs
38 | pip-log.txt
39 | pip-delete-this-directory.txt
40 |
41 | # Unit test / coverage reports
42 | htmlcov/
43 | .tox/
44 | .nox/
45 | .coverage
46 | .coverage.*
47 | .cache
48 | nosetests.xml
49 | coverage.xml
50 | *.cover
51 | *.py,cover
52 | .hypothesis/
53 | .pytest_cache/
54 | cover/
55 |
56 | # Translations
57 | *.mo
58 | *.pot
59 |
60 | # Django stuff:
61 | *.log
62 | local_settings.py
63 | db.sqlite3
64 | db.sqlite3-journal
65 |
66 | # Flask stuff:
67 | instance/
68 | .webassets-cache
69 |
70 | # Scrapy stuff:
71 | .scrapy
72 |
73 | # Sphinx documentation
74 | docs/_build/
75 |
76 | # PyBuilder
77 | .pybuilder/
78 | target/
79 |
80 | # Jupyter Notebook
81 | .ipynb_checkpoints
82 |
83 | # IPython
84 | profile_default/
85 | ipython_config.py
86 |
87 | # pyenv
88 | # For a library or package, you might want to ignore these files since the code is
89 | # intended to run in multiple environments; otherwise, check them in:
90 | # .python-version
91 |
92 | # pipenv
93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
96 | # install all needed dependencies.
97 | #Pipfile.lock
98 |
99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
100 | __pypackages__/
101 |
102 | # Celery stuff
103 | celerybeat-schedule
104 | celerybeat.pid
105 |
106 | # SageMath parsed files
107 | *.sage.py
108 |
109 | # Environments
110 | .env
111 | .venv
112 | env/
113 | venv/
114 | ENV/
115 | env.bak/
116 | venv.bak/
117 |
118 | # Spyder project settings
119 | .spyderproject
120 | .spyproject
121 |
122 | # Rope project settings
123 | .ropeproject
124 |
125 | # mkdocs documentation
126 | /site
127 |
128 | # mypy
129 | .mypy_cache/
130 | .dmypy.json
131 | dmypy.json
132 |
133 | # Pyre type checker
134 | .pyre/
135 |
136 | # pytype static type analyzer
137 | .pytype/
138 |
139 | # Cython debug symbols
140 | cython_debug/
141 |
--------------------------------------------------------------------------------
/.idea/watcherTasks.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # LD2410 BLE
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Interface with LD2410B modules from HiLink
34 |
35 | ## Installation
36 |
37 | Install this via pip (or your favourite package manager):
38 |
39 | `pip install ld2410-ble`
40 |
41 | ## Contributors ✨
42 |
43 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
53 |
54 | ## Credits
55 |
56 | This package was created with
57 | [Cookiecutter](https://github.com/audreyr/cookiecutter) and the
58 | [browniebroke/cookiecutter-pypackage](https://github.com/browniebroke/cookiecutter-pypackage)
59 | project template.
60 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcome, and they are greatly appreciated! Every little helps, and credit will always be given.
4 |
5 | You can contribute in many ways:
6 |
7 | ## Types of Contributions
8 |
9 | ### Report Bugs
10 |
11 | Report bugs to [our issue page][gh-issues]. If you are reporting a bug, please include:
12 |
13 | - Your operating system name and version.
14 | - Any details about your local setup that might be helpful in troubleshooting.
15 | - Detailed steps to reproduce the bug.
16 |
17 | ### Fix Bugs
18 |
19 | Look through the GitHub issues for bugs. Anything tagged with "bug" and "help wanted" is open to whoever wants to implement it.
20 |
21 | ### Implement Features
22 |
23 | Look through the GitHub issues for features. Anything tagged with "enhancement" and "help wanted" is open to whoever wants to implement it.
24 |
25 | ### Write Documentation
26 |
27 | LD2410 BLE could always use more documentation, whether as part of the official LD2410 BLE docs, in docstrings, or even on the web in blog posts, articles, and such.
28 |
29 | ### Submit Feedback
30 |
31 | The best way to send feedback [our issue page][gh-issues] on GitHub. If you are proposing a feature:
32 |
33 | - Explain in detail how it would work.
34 | - Keep the scope as narrow as possible, to make it easier to implement.
35 | - Remember that this is a volunteer-driven project, and that contributions are welcome 😊
36 |
37 | ## Get Started!
38 |
39 | Ready to contribute? Here's how to set yourself up for local development.
40 |
41 | 1. Fork the repo on GitHub.
42 |
43 | 2. Clone your fork locally:
44 |
45 | ```shell
46 | $ git clone git@github.com:/ld2410-ble.git
47 | ```
48 |
49 | 3. Install the project dependencies with [Poetry](https://python-poetry.org):
50 |
51 | ```shell
52 | $ poetry install
53 | ```
54 |
55 | 4. Create a branch for local development:
56 |
57 | ```shell
58 | $ git checkout -b name-of-your-bugfix-or-feature
59 | ```
60 |
61 | Now you can make your changes locally.
62 |
63 | 5. When you're done making changes, check that your changes pass our tests:
64 |
65 | ```shell
66 | $ poetry run pytest
67 | ```
68 |
69 | 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:
70 |
71 | ```shell
72 | $ pre-commit run -a
73 | ```
74 |
75 | Or better, install the hooks once and have them run automatically each time you commit:
76 |
77 | ```shell
78 | $ pre-commit install
79 | ```
80 |
81 | 7. Commit your changes and push your branch to GitHub:
82 |
83 | ```shell
84 | $ git add .
85 | $ git commit -m "feat(something): your detailed description of your changes"
86 | $ git push origin name-of-your-bugfix-or-feature
87 | ```
88 |
89 | 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.
90 |
91 | 8. Submit a pull request through the GitHub website or using the GitHub CLI (if you have it installed):
92 |
93 | ```shell
94 | $ gh pr create --fill
95 | ```
96 |
97 | ## Pull Request Guidelines
98 |
99 | 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:
100 |
101 | 1. Include tests for feature or bug fixes.
102 | 2. Update the documentation for significant features.
103 | 3. Ensure tests are passing on CI.
104 |
105 | ## Tips
106 |
107 | To run a subset of tests:
108 |
109 | ```shell
110 | $ pytest tests
111 | ```
112 |
113 | ## Making a new release
114 |
115 | 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.
116 |
117 | [gh-issues]: https://github.com/930913/ld2410-ble/issues
118 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright 2022 930913
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/src/ld2410_ble/ld2410_ble.py:
--------------------------------------------------------------------------------
1 | from __future__ import annotations
2 |
3 | import asyncio
4 | import logging
5 | import re
6 | import sys
7 | from collections.abc import Callable
8 | from typing import Any, TypeVar
9 |
10 | from bleak.backends.device import BLEDevice
11 | from bleak.backends.scanner import AdvertisementData
12 | from bleak.exc import BleakDBusError
13 | from bleak_retry_connector import BLEAK_RETRY_EXCEPTIONS as BLEAK_EXCEPTIONS
14 | from bleak_retry_connector import (
15 | BleakClientWithServiceCache,
16 | BleakError,
17 | BleakNotFoundError,
18 | establish_connection,
19 | retry_bluetooth_connection_error,
20 | )
21 |
22 | from .const import (
23 | CHARACTERISTIC_NOTIFY,
24 | CHARACTERISTIC_WRITE,
25 | CMD_BT_PASS_DEFAULT,
26 | CMD_BT_PASS_POST,
27 | CMD_BT_PASS_PRE,
28 | CMD_DISABLE_CONFIG,
29 | CMD_ENABLE_CONFIG,
30 | CMD_ENABLE_ENGINEERING_MODE,
31 | MOVING_TARGET,
32 | STATIC_TARGET,
33 | engineering_frame_regex,
34 | frame_regex,
35 | )
36 | from .exceptions import CharacteristicMissingError
37 | from .models import LD2410BLEState
38 |
39 | BLEAK_BACKOFF_TIME = 0.25
40 |
41 | __version__ = "0.0.0"
42 |
43 |
44 | WrapFuncType = TypeVar("WrapFuncType", bound=Callable[..., Any])
45 |
46 | RETRY_BACKOFF_EXCEPTIONS = (BleakDBusError,)
47 |
48 | _LOGGER = logging.getLogger(__name__)
49 |
50 | DEFAULT_ATTEMPTS = sys.maxsize
51 |
52 |
53 | class LD2410BLE:
54 | def __init__(
55 | self,
56 | ble_device: BLEDevice,
57 | advertisement_data: AdvertisementData | None = None,
58 | password: bytes = CMD_BT_PASS_DEFAULT,
59 | ) -> None:
60 | """Init the LD2410BLE."""
61 | self._ble_device = ble_device
62 | self._advertisement_data = advertisement_data
63 | self._password = password
64 | self._operation_lock = asyncio.Lock()
65 | self._state = LD2410BLEState()
66 | self._connect_lock: asyncio.Lock = asyncio.Lock()
67 | self._client: BleakClientWithServiceCache | None = None
68 | self._expected_disconnect = False
69 | self.loop = asyncio.get_running_loop()
70 | self._callbacks: list[Callable[[LD2410BLEState], None]] = []
71 | self._disconnected_callbacks: list[Callable[[], None]] = []
72 | self._buf = b""
73 |
74 | def set_ble_device_and_advertisement_data(
75 | self, ble_device: BLEDevice, advertisement_data: AdvertisementData
76 | ) -> None:
77 | """Set the ble device."""
78 | self._ble_device = ble_device
79 | self._advertisement_data = advertisement_data
80 |
81 | @property
82 | def address(self) -> str:
83 | """Return the address."""
84 | return self._ble_device.address
85 |
86 | @property
87 | def _address(self) -> str:
88 | """Return the address."""
89 | return self._ble_device.address
90 |
91 | @property
92 | def name(self) -> str:
93 | """Get the name of the device."""
94 | return self._ble_device.name or self._ble_device.address
95 |
96 | @property
97 | def rssi(self) -> int | None:
98 | """Get the rssi of the device."""
99 | if self._advertisement_data:
100 | return self._advertisement_data.rssi
101 | return None
102 |
103 | @property
104 | def state(self) -> LD2410BLEState:
105 | """Return the state."""
106 | return self._state
107 |
108 | @property
109 | def is_moving(self) -> bool:
110 | return self._state.is_moving
111 |
112 | @property
113 | def is_static(self) -> bool:
114 | return self._state.is_static
115 |
116 | @property
117 | def moving_target_distance(self) -> int:
118 | return self._state.moving_target_distance
119 |
120 | @property
121 | def moving_target_energy(self) -> int:
122 | return self._state.moving_target_energy
123 |
124 | @property
125 | def static_target_distance(self) -> int:
126 | return self._state.static_target_distance
127 |
128 | @property
129 | def static_target_energy(self) -> int:
130 | return self._state.static_target_energy
131 |
132 | @property
133 | def detection_distance(self) -> int:
134 | return self._state.detection_distance
135 |
136 | @property
137 | def max_motion_gates(self) -> int:
138 | assert self._state.max_motion_gates is not None # nosec
139 | return self._state.max_motion_gates
140 |
141 | @property
142 | def max_static_gates(self) -> int:
143 | assert self._state.max_static_gates is not None # nosec
144 | return self._state.max_static_gates
145 |
146 | @property
147 | def motion_energy_gates(self) -> list[int]:
148 | assert self._state.motion_energy_gates is not None # nosec
149 | return self._state.motion_energy_gates
150 |
151 | @property
152 | def motion_energy_gate_0(self) -> int:
153 | assert self._state.motion_energy_gates is not None # nosec
154 | return self._state.motion_energy_gates[0]
155 |
156 | @property
157 | def motion_energy_gate_1(self) -> int:
158 | assert self._state.motion_energy_gates is not None # nosec
159 | return self._state.motion_energy_gates[1]
160 |
161 | @property
162 | def motion_energy_gate_2(self) -> int:
163 | assert self._state.motion_energy_gates is not None # nosec
164 | return self._state.motion_energy_gates[2]
165 |
166 | @property
167 | def motion_energy_gate_3(self) -> int:
168 | assert self._state.motion_energy_gates is not None # nosec
169 | return self._state.motion_energy_gates[3]
170 |
171 | @property
172 | def motion_energy_gate_4(self) -> int:
173 | assert self._state.motion_energy_gates is not None # nosec
174 | return self._state.motion_energy_gates[4]
175 |
176 | @property
177 | def motion_energy_gate_5(self) -> int:
178 | assert self._state.motion_energy_gates is not None # nosec
179 | return self._state.motion_energy_gates[5]
180 |
181 | @property
182 | def motion_energy_gate_6(self) -> int:
183 | assert self._state.motion_energy_gates is not None # nosec
184 | return self._state.motion_energy_gates[6]
185 |
186 | @property
187 | def motion_energy_gate_7(self) -> int:
188 | assert self._state.motion_energy_gates is not None # nosec
189 | return self._state.motion_energy_gates[7]
190 |
191 | @property
192 | def motion_energy_gate_8(self) -> int:
193 | assert self._state.motion_energy_gates is not None # nosec
194 | return self._state.motion_energy_gates[8]
195 |
196 | @property
197 | def static_energy_gates(self) -> list[int]:
198 | assert self._state.static_energy_gates is not None # nosec
199 | return self._state.static_energy_gates
200 |
201 | @property
202 | def static_energy_gate_0(self) -> int:
203 | assert self._state.static_energy_gates is not None # nosec
204 | return self._state.static_energy_gates[0]
205 |
206 | @property
207 | def static_energy_gate_1(self) -> int:
208 | assert self._state.static_energy_gates is not None # nosec
209 | return self._state.static_energy_gates[1]
210 |
211 | @property
212 | def static_energy_gate_2(self) -> int:
213 | assert self._state.static_energy_gates is not None # nosec
214 | return self._state.static_energy_gates[2]
215 |
216 | @property
217 | def static_energy_gate_3(self) -> int:
218 | assert self._state.static_energy_gates is not None # nosec
219 | return self._state.static_energy_gates[3]
220 |
221 | @property
222 | def static_energy_gate_4(self) -> int:
223 | assert self._state.static_energy_gates is not None # nosec
224 | return self._state.static_energy_gates[4]
225 |
226 | @property
227 | def static_energy_gate_5(self) -> int:
228 | assert self._state.static_energy_gates is not None # nosec
229 | return self._state.static_energy_gates[5]
230 |
231 | @property
232 | def static_energy_gate_6(self) -> int:
233 | assert self._state.static_energy_gates is not None # nosec
234 | return self._state.static_energy_gates[6]
235 |
236 | @property
237 | def static_energy_gate_7(self) -> int:
238 | assert self._state.static_energy_gates is not None # nosec
239 | return self._state.static_energy_gates[7]
240 |
241 | @property
242 | def static_energy_gate_8(self) -> int:
243 | assert self._state.static_energy_gates is not None # nosec
244 | return self._state.static_energy_gates[8]
245 |
246 | async def stop(self) -> None:
247 | """Stop the LD2410BLE."""
248 | _LOGGER.debug("%s: Stop", self.name)
249 | await self._execute_disconnect()
250 |
251 | def _fire_callbacks(self) -> None:
252 | """Fire the callbacks."""
253 | for callback in self._callbacks:
254 | callback(self._state)
255 |
256 | def register_callback(
257 | self, callback: Callable[[LD2410BLEState], None]
258 | ) -> Callable[[], None]:
259 | """Register a callback to be called when the state changes."""
260 |
261 | def unregister_callback() -> None:
262 | self._callbacks.remove(callback)
263 |
264 | self._callbacks.append(callback)
265 | return unregister_callback
266 |
267 | def _fire_disconnected_callbacks(self) -> None:
268 | """Fire the callbacks."""
269 | for callback in self._disconnected_callbacks:
270 | callback()
271 |
272 | def register_disconnected_callback(
273 | self, callback: Callable[[], None]
274 | ) -> Callable[[], None]:
275 | """Register a callback to be called when the state changes."""
276 |
277 | def unregister_callback() -> None:
278 | self._disconnected_callbacks.remove(callback)
279 |
280 | self._disconnected_callbacks.append(callback)
281 | return unregister_callback
282 |
283 | async def initialise(self) -> None:
284 | _LOGGER.debug("%s: Sending configuration commands", self.name)
285 | await self._send_command(CMD_BT_PASS_PRE + self._password + CMD_BT_PASS_POST)
286 | await asyncio.sleep(0.1)
287 | await self._send_command(CMD_ENABLE_CONFIG)
288 | await asyncio.sleep(0.1)
289 | await self._send_command(CMD_ENABLE_ENGINEERING_MODE)
290 | await asyncio.sleep(0.1)
291 | await self._send_command(CMD_DISABLE_CONFIG)
292 | await asyncio.sleep(0.1)
293 |
294 | _LOGGER.debug("%s: Subscribe to notifications; RSSI: %s", self.name, self.rssi)
295 | if self._client is not None:
296 | await self._client.start_notify(
297 | CHARACTERISTIC_NOTIFY, self._notification_handler
298 | )
299 |
300 | async def _ensure_connected(self) -> None:
301 | """Ensure connection to device is established."""
302 | if self._connect_lock.locked():
303 | _LOGGER.debug(
304 | "%s: Connection already in progress, waiting for it to complete; RSSI: %s",
305 | self.name,
306 | self.rssi,
307 | )
308 | if self._client and self._client.is_connected:
309 | return
310 | async with self._connect_lock:
311 | # Check again while holding the lock
312 | if self._client and self._client.is_connected:
313 | return
314 | _LOGGER.debug("%s: Connecting; RSSI: %s", self.name, self.rssi)
315 | client = await establish_connection(
316 | BleakClientWithServiceCache,
317 | self._ble_device,
318 | self.name,
319 | self._disconnected,
320 | use_services_cache=True,
321 | ble_device_callback=lambda: self._ble_device,
322 | )
323 | _LOGGER.debug("%s: Connected; RSSI: %s", self.name, self.rssi)
324 |
325 | self._client = client
326 |
327 | async def _reconnect(self) -> None:
328 | """Attempt a reconnect"""
329 | _LOGGER.debug("ensuring connection")
330 | try:
331 | await self._ensure_connected()
332 | _LOGGER.debug("ensured connection - initialising")
333 | await self.initialise()
334 | except BleakNotFoundError:
335 | _LOGGER.debug("failed to ensure connection - backing off")
336 | await asyncio.sleep(BLEAK_BACKOFF_TIME)
337 | _LOGGER.debug("reconnecting again")
338 | asyncio.create_task(self._reconnect())
339 |
340 | def intify(self, state: bytes) -> int:
341 | return int.from_bytes(state, byteorder="little")
342 |
343 | def _notification_handler(self, _sender: int, data: bytearray) -> None:
344 | """Handle notification responses."""
345 | _LOGGER.debug("%s: Notification received: %s", self.name, data.hex())
346 |
347 | self._buf += data
348 | msg = re.search(frame_regex, self._buf)
349 | if msg:
350 | self._buf = self._buf[msg.end() :] # noqa: E203
351 | target_state = msg.group("target_state")
352 | engineering_data = msg.group("engineering_data")
353 |
354 | target_state_int = self.intify(target_state)
355 | is_moving = bool(target_state_int & MOVING_TARGET)
356 | is_static = bool(target_state_int & STATIC_TARGET)
357 | moving_target_distance = self.intify(msg.group("moving_target_distance"))
358 | moving_target_energy = self.intify(msg.group("moving_target_energy"))
359 | static_target_distance = self.intify(msg.group("static_target_distance"))
360 | static_target_energy = self.intify(msg.group("static_target_energy"))
361 | detection_distance = self.intify(msg.group("detection_distance"))
362 |
363 | max_motion_gates = None
364 | max_static_gates = None
365 | motion_energy_gates = None
366 | static_energy_gates = None
367 | if engineering_data:
368 | em = re.match(engineering_frame_regex, engineering_data)
369 | if em:
370 | max_motion_gates = self.intify(em.group("maximum_motion_gates"))
371 | max_static_gates = self.intify(em.group("maximum_static_gates"))
372 | motion_energy_gates = [x for x in em.group("motion_energy_gates")]
373 | static_energy_gates = [x for x in em.group("static_energy_gates")]
374 |
375 | self._state = LD2410BLEState(
376 | is_moving=is_moving,
377 | is_static=is_static,
378 | moving_target_distance=moving_target_distance,
379 | moving_target_energy=moving_target_energy,
380 | static_target_distance=static_target_distance,
381 | static_target_energy=static_target_energy,
382 | detection_distance=detection_distance,
383 | max_motion_gates=max_motion_gates,
384 | max_static_gates=max_static_gates,
385 | motion_energy_gates=motion_energy_gates,
386 | static_energy_gates=static_energy_gates,
387 | )
388 |
389 | self._fire_callbacks()
390 |
391 | _LOGGER.debug(
392 | "%s: Notification received; RSSI: %s: %s %s",
393 | self.name,
394 | self.rssi,
395 | data.hex(),
396 | self._state,
397 | )
398 |
399 | def _disconnected(self, client: BleakClientWithServiceCache) -> None:
400 | """Disconnected callback."""
401 | self._fire_disconnected_callbacks()
402 | if self._expected_disconnect:
403 | _LOGGER.debug(
404 | "%s: Disconnected from device; RSSI: %s", self.name, self.rssi
405 | )
406 | return
407 | _LOGGER.warning(
408 | "%s: Device unexpectedly disconnected; RSSI: %s",
409 | self.name,
410 | self.rssi,
411 | )
412 | asyncio.create_task(self._reconnect())
413 |
414 | def _disconnect(self) -> None:
415 | """Disconnect from device."""
416 | asyncio.create_task(self._execute_timed_disconnect())
417 |
418 | async def _execute_timed_disconnect(self) -> None:
419 | """Execute timed disconnection."""
420 | _LOGGER.debug(
421 | "%s: Disconnecting",
422 | self.name,
423 | )
424 | await self._execute_disconnect()
425 |
426 | async def _execute_disconnect(self) -> None:
427 | """Execute disconnection."""
428 | async with self._connect_lock:
429 | client = self._client
430 | self._expected_disconnect = True
431 | self._client = None
432 | if client and client.is_connected:
433 | await client.stop_notify(CHARACTERISTIC_NOTIFY)
434 | await client.disconnect()
435 |
436 | @retry_bluetooth_connection_error(DEFAULT_ATTEMPTS)
437 | async def _send_command_locked(self, commands: list[bytes]) -> None:
438 | """Send command to device and read response."""
439 | try:
440 | await self._execute_command_locked(commands)
441 | except BleakDBusError as ex:
442 | # Disconnect so we can reset state and try again
443 | await asyncio.sleep(BLEAK_BACKOFF_TIME)
444 | _LOGGER.debug(
445 | "%s: RSSI: %s; Backing off %ss; Disconnecting due to error: %s",
446 | self.name,
447 | self.rssi,
448 | BLEAK_BACKOFF_TIME,
449 | ex,
450 | )
451 | await self._execute_disconnect()
452 | raise
453 | except BleakError as ex:
454 | # Disconnect so we can reset state and try again
455 | _LOGGER.debug(
456 | "%s: RSSI: %s; Disconnecting due to error: %s", self.name, self.rssi, ex
457 | )
458 | await self._execute_disconnect()
459 | raise
460 |
461 | async def _send_command(
462 | self, commands: list[bytes] | bytes, retry: int | None = None
463 | ) -> None:
464 | """Send command to device and read response."""
465 | await self._ensure_connected()
466 | if not isinstance(commands, list):
467 | commands = [commands]
468 | await self._send_command_while_connected(commands, retry)
469 |
470 | async def _send_command_while_connected(
471 | self, commands: list[bytes], retry: int | None = None
472 | ) -> None:
473 | """Send command to device and read response."""
474 | _LOGGER.debug(
475 | "%s: Sending commands %s",
476 | self.name,
477 | [command.hex() for command in commands],
478 | )
479 | if self._operation_lock.locked():
480 | _LOGGER.debug(
481 | "%s: Operation already in progress, waiting for it to complete; RSSI: %s",
482 | self.name,
483 | self.rssi,
484 | )
485 | async with self._operation_lock:
486 | try:
487 | await self._send_command_locked(commands)
488 | return
489 | except BleakNotFoundError:
490 | _LOGGER.error(
491 | "%s: device not found, no longer in range, or poor RSSI: %s",
492 | self.name,
493 | self.rssi,
494 | exc_info=True,
495 | )
496 | raise
497 | except CharacteristicMissingError as ex:
498 | _LOGGER.debug(
499 | "%s: characteristic missing: %s; RSSI: %s",
500 | self.name,
501 | ex,
502 | self.rssi,
503 | exc_info=True,
504 | )
505 | raise
506 | except BLEAK_EXCEPTIONS:
507 | _LOGGER.debug("%s: communication failed", self.name, exc_info=True)
508 | raise
509 |
510 | raise RuntimeError("Unreachable")
511 |
512 | async def _execute_command_locked(self, commands: list[bytes]) -> None:
513 | """Execute command and read response."""
514 | assert self._client is not None # nosec
515 | for command in commands:
516 | await self._client.write_gatt_char(CHARACTERISTIC_WRITE, command, False)
517 |
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | [[package]]
2 | name = "alabaster"
3 | version = "0.7.12"
4 | description = "A configurable sidebar-enabled Sphinx theme"
5 | category = "main"
6 | optional = true
7 | python-versions = "*"
8 |
9 | [[package]]
10 | name = "async-timeout"
11 | version = "4.0.2"
12 | description = "Timeout context manager for asyncio programs"
13 | category = "main"
14 | optional = false
15 | python-versions = ">=3.6"
16 |
17 | [[package]]
18 | name = "atomicwrites"
19 | version = "1.4.1"
20 | description = "Atomic file writes."
21 | category = "dev"
22 | optional = false
23 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
24 |
25 | [[package]]
26 | name = "attrs"
27 | version = "21.4.0"
28 | description = "Classes Without Boilerplate"
29 | category = "dev"
30 | optional = false
31 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
32 |
33 | [package.extras]
34 | dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"]
35 | docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
36 | tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"]
37 | tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"]
38 |
39 | [[package]]
40 | name = "babel"
41 | version = "2.10.3"
42 | description = "Internationalization utilities"
43 | category = "main"
44 | optional = true
45 | python-versions = ">=3.6"
46 |
47 | [package.dependencies]
48 | pytz = ">=2015.7"
49 |
50 | [[package]]
51 | name = "bleak"
52 | version = "0.19.0"
53 | description = "Bluetooth Low Energy platform Agnostic Klient"
54 | category = "main"
55 | optional = false
56 | python-versions = ">=3.7,<4.0"
57 |
58 | [package.dependencies]
59 | async-timeout = ">=3.0.0,<5"
60 | bleak-winrt = {version = ">=1.2.0,<2.0.0", markers = "platform_system == \"Windows\""}
61 | dbus-fast = {version = ">=1.22.0,<2.0.0", markers = "platform_system == \"Linux\""}
62 | pyobjc-core = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""}
63 | pyobjc-framework-CoreBluetooth = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""}
64 | pyobjc-framework-libdispatch = {version = ">=8.5.1,<9.0.0", markers = "platform_system == \"Darwin\""}
65 |
66 | [[package]]
67 | name = "bleak-retry-connector"
68 | version = "2.3.0"
69 | description = "A connector for Bleak Clients that handles transient connection failures"
70 | category = "main"
71 | optional = false
72 | python-versions = ">=3.9,<4.0"
73 |
74 | [package.dependencies]
75 | async-timeout = ">=4.0.1"
76 | bleak = ">=0.19.0"
77 | dbus-fast = {version = ">=1.14.0", markers = "platform_system == \"Linux\""}
78 |
79 | [package.extras]
80 | docs = ["Sphinx (>=5.0,<6.0)", "myst-parser (>=0.18,<0.19)", "sphinx-rtd-theme (>=1.0,<2.0)"]
81 |
82 | [[package]]
83 | name = "bleak-winrt"
84 | version = "1.2.0"
85 | description = "Python WinRT bindings for Bleak"
86 | category = "main"
87 | optional = false
88 | python-versions = "*"
89 |
90 | [[package]]
91 | name = "certifi"
92 | version = "2022.6.15"
93 | description = "Python package for providing Mozilla's CA Bundle."
94 | category = "main"
95 | optional = true
96 | python-versions = ">=3.6"
97 |
98 | [[package]]
99 | name = "charset-normalizer"
100 | version = "2.1.0"
101 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
102 | category = "main"
103 | optional = true
104 | python-versions = ">=3.6.0"
105 |
106 | [package.extras]
107 | unicode_backport = ["unicodedata2"]
108 |
109 | [[package]]
110 | name = "colorama"
111 | version = "0.4.5"
112 | description = "Cross-platform colored terminal text."
113 | category = "main"
114 | optional = false
115 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
116 |
117 | [[package]]
118 | name = "coverage"
119 | version = "6.4.4"
120 | description = "Code coverage measurement for Python"
121 | category = "dev"
122 | optional = false
123 | python-versions = ">=3.7"
124 |
125 | [package.dependencies]
126 | tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
127 |
128 | [package.extras]
129 | toml = ["tomli"]
130 |
131 | [[package]]
132 | name = "dbus-fast"
133 | version = "1.45.0"
134 | description = "A faster version of dbus-next"
135 | category = "main"
136 | optional = false
137 | python-versions = ">=3.7,<4.0"
138 |
139 | [package.dependencies]
140 | async-timeout = ">=3.0.0"
141 |
142 | [package.extras]
143 | docs = ["Sphinx (>=5.1.1,<6.0.0)", "myst-parser (>=0.18.0,<0.19.0)", "sphinx-rtd-theme (>=1.0.0,<2.0.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinxcontrib-fulltoc (>=1.2.0,<2.0.0)"]
144 |
145 | [[package]]
146 | name = "docutils"
147 | version = "0.17.1"
148 | description = "Docutils -- Python Documentation Utilities"
149 | category = "main"
150 | optional = true
151 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
152 |
153 | [[package]]
154 | name = "flux-led"
155 | version = "0.28.32"
156 | description = "A Python library to communicate with the flux_led smart bulbs"
157 | category = "main"
158 | optional = false
159 | python-versions = ">=3.7"
160 |
161 | [package.dependencies]
162 | webcolors = "*"
163 |
164 | [package.extras]
165 | all = ["Sphinx (>=3.4.3)", "black (>=19.10b0)", "bump2version (>=1.0.1)", "codecov (>=2.1.4)", "coverage (>=5.1)", "flake8 (>=3.8.3)", "flake8-debugger (>=3.2.1)", "ipython (>=7.15.0)", "m2r2 (>=0.2.7)", "pytest (>=5.4.3)", "pytest-asyncio", "pytest-cov (>=2.9.0)", "pytest-raises (>=0.11)", "pytest-runner (>=5.2)", "sphinx-rtd-theme (>=0.5.1)", "tox (>=3.15.2)", "twine (>=3.1.1)", "typing-extensions", "webcolors", "wheel (>=0.34.2)"]
166 | dev = ["Sphinx (>=3.4.3)", "black (>=19.10b0)", "bump2version (>=1.0.1)", "codecov (>=2.1.4)", "coverage (>=5.1)", "flake8 (>=3.8.3)", "flake8-debugger (>=3.2.1)", "ipython (>=7.15.0)", "m2r2 (>=0.2.7)", "pytest (>=5.4.3)", "pytest-asyncio", "pytest-cov (>=2.9.0)", "pytest-raises (>=0.11)", "pytest-runner (>=5.2)", "sphinx-rtd-theme (>=0.5.1)", "tox (>=3.15.2)", "twine (>=3.1.1)", "wheel (>=0.34.2)"]
167 | setup = ["pytest-runner (>=5.2)"]
168 | test = ["black (>=19.10b0)", "codecov (>=2.1.4)", "flake8 (>=3.8.3)", "flake8-debugger (>=3.2.1)", "pytest (>=5.4.3)", "pytest-asyncio", "pytest-cov (>=2.9.0)", "pytest-raises (>=0.11)"]
169 |
170 | [[package]]
171 | name = "idna"
172 | version = "3.3"
173 | description = "Internationalized Domain Names in Applications (IDNA)"
174 | category = "main"
175 | optional = true
176 | python-versions = ">=3.5"
177 |
178 | [[package]]
179 | name = "imagesize"
180 | version = "1.4.1"
181 | description = "Getting image size from png/jpeg/jpeg2000/gif file"
182 | category = "main"
183 | optional = true
184 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
185 |
186 | [[package]]
187 | name = "importlib-metadata"
188 | version = "4.12.0"
189 | description = "Read metadata from Python packages"
190 | category = "main"
191 | optional = true
192 | python-versions = ">=3.7"
193 |
194 | [package.dependencies]
195 | zipp = ">=0.5"
196 |
197 | [package.extras]
198 | docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"]
199 | perf = ["ipython"]
200 | testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
201 |
202 | [[package]]
203 | name = "iniconfig"
204 | version = "1.1.1"
205 | description = "iniconfig: brain-dead simple config-ini parsing"
206 | category = "dev"
207 | optional = false
208 | python-versions = "*"
209 |
210 | [[package]]
211 | name = "jinja2"
212 | version = "3.1.2"
213 | description = "A very fast and expressive template engine."
214 | category = "main"
215 | optional = true
216 | python-versions = ">=3.7"
217 |
218 | [package.dependencies]
219 | MarkupSafe = ">=2.0"
220 |
221 | [package.extras]
222 | i18n = ["Babel (>=2.7)"]
223 |
224 | [[package]]
225 | name = "markdown-it-py"
226 | version = "2.1.0"
227 | description = "Python port of markdown-it. Markdown parsing, done right!"
228 | category = "main"
229 | optional = true
230 | python-versions = ">=3.7"
231 |
232 | [package.dependencies]
233 | mdurl = ">=0.1,<1.0"
234 |
235 | [package.extras]
236 | benchmarking = ["psutil", "pytest", "pytest-benchmark (>=3.2,<4.0)"]
237 | code_style = ["pre-commit (==2.6)"]
238 | compare = ["commonmark (>=0.9.1,<0.10.0)", "markdown (>=3.3.6,<3.4.0)", "mistletoe (>=0.8.1,<0.9.0)", "mistune (>=2.0.2,<2.1.0)", "panflute (>=2.1.3,<2.2.0)"]
239 | linkify = ["linkify-it-py (>=1.0,<2.0)"]
240 | plugins = ["mdit-py-plugins"]
241 | profiling = ["gprof2dot"]
242 | rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
243 | testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
244 |
245 | [[package]]
246 | name = "markupsafe"
247 | version = "2.1.1"
248 | description = "Safely add untrusted strings to HTML/XML markup."
249 | category = "main"
250 | optional = true
251 | python-versions = ">=3.7"
252 |
253 | [[package]]
254 | name = "mdit-py-plugins"
255 | version = "0.3.0"
256 | description = "Collection of plugins for markdown-it-py"
257 | category = "main"
258 | optional = true
259 | python-versions = "~=3.6"
260 |
261 | [package.dependencies]
262 | markdown-it-py = ">=1.0.0,<3.0.0"
263 |
264 | [package.extras]
265 | code_style = ["pre-commit (==2.6)"]
266 | rtd = ["myst-parser (>=0.14.0,<0.15.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"]
267 | testing = ["coverage", "pytest (>=3.6,<4)", "pytest-cov", "pytest-regressions"]
268 |
269 | [[package]]
270 | name = "mdurl"
271 | version = "0.1.1"
272 | description = "Markdown URL utilities"
273 | category = "main"
274 | optional = true
275 | python-versions = ">=3.7"
276 |
277 | [[package]]
278 | name = "myst-parser"
279 | version = "0.18.0"
280 | description = "An extended commonmark compliant parser, with bridges to docutils & sphinx."
281 | category = "main"
282 | optional = true
283 | python-versions = ">=3.7"
284 |
285 | [package.dependencies]
286 | docutils = ">=0.15,<0.19"
287 | jinja2 = "*"
288 | markdown-it-py = ">=1.0.0,<3.0.0"
289 | mdit-py-plugins = ">=0.3.0,<0.4.0"
290 | pyyaml = "*"
291 | sphinx = ">=4,<6"
292 | typing-extensions = "*"
293 |
294 | [package.extras]
295 | code_style = ["pre-commit (>=2.12,<3.0)"]
296 | linkify = ["linkify-it-py (>=1.0,<2.0)"]
297 | rtd = ["ipython", "sphinx-book-theme", "sphinx-design", "sphinxcontrib.mermaid (>=0.7.1,<0.8.0)", "sphinxext-opengraph (>=0.6.3,<0.7.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"]
298 | testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"]
299 |
300 | [[package]]
301 | name = "packaging"
302 | version = "21.3"
303 | description = "Core utilities for Python packages"
304 | category = "main"
305 | optional = false
306 | python-versions = ">=3.6"
307 |
308 | [package.dependencies]
309 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
310 |
311 | [[package]]
312 | name = "pluggy"
313 | version = "1.0.0"
314 | description = "plugin and hook calling mechanisms for python"
315 | category = "dev"
316 | optional = false
317 | python-versions = ">=3.6"
318 |
319 | [package.extras]
320 | dev = ["pre-commit", "tox"]
321 | testing = ["pytest", "pytest-benchmark"]
322 |
323 | [[package]]
324 | name = "py"
325 | version = "1.11.0"
326 | description = "library with cross-python path, ini-parsing, io, code, log facilities"
327 | category = "dev"
328 | optional = false
329 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
330 |
331 | [[package]]
332 | name = "pygments"
333 | version = "2.12.0"
334 | description = "Pygments is a syntax highlighting package written in Python."
335 | category = "main"
336 | optional = true
337 | python-versions = ">=3.6"
338 |
339 | [[package]]
340 | name = "pyobjc-core"
341 | version = "8.5.1"
342 | description = "Python<->ObjC Interoperability Module"
343 | category = "main"
344 | optional = false
345 | python-versions = ">=3.6"
346 |
347 | [[package]]
348 | name = "pyobjc-framework-Cocoa"
349 | version = "8.5.1"
350 | description = "Wrappers for the Cocoa frameworks on macOS"
351 | category = "main"
352 | optional = false
353 | python-versions = ">=3.6"
354 |
355 | [package.dependencies]
356 | pyobjc-core = ">=8.5.1"
357 |
358 | [[package]]
359 | name = "pyobjc-framework-CoreBluetooth"
360 | version = "8.5.1"
361 | description = "Wrappers for the framework CoreBluetooth on macOS"
362 | category = "main"
363 | optional = false
364 | python-versions = ">=3.6"
365 |
366 | [package.dependencies]
367 | pyobjc-core = ">=8.5.1"
368 | pyobjc-framework-Cocoa = ">=8.5.1"
369 |
370 | [[package]]
371 | name = "pyobjc-framework-libdispatch"
372 | version = "8.5.1"
373 | description = "Wrappers for libdispatch on macOS"
374 | category = "main"
375 | optional = false
376 | python-versions = ">=3.6"
377 |
378 | [package.dependencies]
379 | pyobjc-core = ">=8.5.1"
380 |
381 | [[package]]
382 | name = "pyparsing"
383 | version = "3.0.9"
384 | description = "pyparsing module - Classes and methods to define and execute parsing grammars"
385 | category = "main"
386 | optional = false
387 | python-versions = ">=3.6.8"
388 |
389 | [package.extras]
390 | diagrams = ["jinja2", "railroad-diagrams"]
391 |
392 | [[package]]
393 | name = "pytest"
394 | version = "7.1.2"
395 | description = "pytest: simple powerful testing with Python"
396 | category = "dev"
397 | optional = false
398 | python-versions = ">=3.7"
399 |
400 | [package.dependencies]
401 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
402 | attrs = ">=19.2.0"
403 | colorama = {version = "*", markers = "sys_platform == \"win32\""}
404 | iniconfig = "*"
405 | packaging = "*"
406 | pluggy = ">=0.12,<2.0"
407 | py = ">=1.8.2"
408 | tomli = ">=1.0.0"
409 |
410 | [package.extras]
411 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
412 |
413 | [[package]]
414 | name = "pytest-cov"
415 | version = "3.0.0"
416 | description = "Pytest plugin for measuring coverage."
417 | category = "dev"
418 | optional = false
419 | python-versions = ">=3.6"
420 |
421 | [package.dependencies]
422 | coverage = {version = ">=5.2.1", extras = ["toml"]}
423 | pytest = ">=4.6"
424 |
425 | [package.extras]
426 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
427 |
428 | [[package]]
429 | name = "pytz"
430 | version = "2022.1"
431 | description = "World timezone definitions, modern and historical"
432 | category = "main"
433 | optional = true
434 | python-versions = "*"
435 |
436 | [[package]]
437 | name = "pyyaml"
438 | version = "6.0"
439 | description = "YAML parser and emitter for Python"
440 | category = "main"
441 | optional = true
442 | python-versions = ">=3.6"
443 |
444 | [[package]]
445 | name = "requests"
446 | version = "2.28.1"
447 | description = "Python HTTP for Humans."
448 | category = "main"
449 | optional = true
450 | python-versions = ">=3.7, <4"
451 |
452 | [package.dependencies]
453 | certifi = ">=2017.4.17"
454 | charset-normalizer = ">=2,<3"
455 | idna = ">=2.5,<4"
456 | urllib3 = ">=1.21.1,<1.27"
457 |
458 | [package.extras]
459 | socks = ["PySocks (>=1.5.6,!=1.5.7)"]
460 | use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
461 |
462 | [[package]]
463 | name = "snowballstemmer"
464 | version = "2.2.0"
465 | description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
466 | category = "main"
467 | optional = true
468 | python-versions = "*"
469 |
470 | [[package]]
471 | name = "sphinx"
472 | version = "5.1.1"
473 | description = "Python documentation generator"
474 | category = "main"
475 | optional = true
476 | python-versions = ">=3.6"
477 |
478 | [package.dependencies]
479 | alabaster = ">=0.7,<0.8"
480 | babel = ">=1.3"
481 | colorama = {version = ">=0.3.5", markers = "sys_platform == \"win32\""}
482 | docutils = ">=0.14,<0.20"
483 | imagesize = "*"
484 | importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
485 | Jinja2 = ">=2.3"
486 | packaging = "*"
487 | Pygments = ">=2.0"
488 | requests = ">=2.5.0"
489 | snowballstemmer = ">=1.1"
490 | sphinxcontrib-applehelp = "*"
491 | sphinxcontrib-devhelp = "*"
492 | sphinxcontrib-htmlhelp = ">=2.0.0"
493 | sphinxcontrib-jsmath = "*"
494 | sphinxcontrib-qthelp = "*"
495 | sphinxcontrib-serializinghtml = ">=1.1.5"
496 |
497 | [package.extras]
498 | docs = ["sphinxcontrib-websupport"]
499 | lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "isort", "mypy (>=0.971)", "sphinx-lint", "types-requests", "types-typed-ast"]
500 | test = ["cython", "html5lib", "pytest (>=4.6)", "typed-ast"]
501 |
502 | [[package]]
503 | name = "sphinx-rtd-theme"
504 | version = "1.0.0"
505 | description = "Read the Docs theme for Sphinx"
506 | category = "main"
507 | optional = true
508 | python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
509 |
510 | [package.dependencies]
511 | docutils = "<0.18"
512 | sphinx = ">=1.6"
513 |
514 | [package.extras]
515 | dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client"]
516 |
517 | [[package]]
518 | name = "sphinxcontrib-applehelp"
519 | version = "1.0.2"
520 | description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books"
521 | category = "main"
522 | optional = true
523 | python-versions = ">=3.5"
524 |
525 | [package.extras]
526 | lint = ["docutils-stubs", "flake8", "mypy"]
527 | test = ["pytest"]
528 |
529 | [[package]]
530 | name = "sphinxcontrib-devhelp"
531 | version = "1.0.2"
532 | description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document."
533 | category = "main"
534 | optional = true
535 | python-versions = ">=3.5"
536 |
537 | [package.extras]
538 | lint = ["docutils-stubs", "flake8", "mypy"]
539 | test = ["pytest"]
540 |
541 | [[package]]
542 | name = "sphinxcontrib-htmlhelp"
543 | version = "2.0.0"
544 | description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files"
545 | category = "main"
546 | optional = true
547 | python-versions = ">=3.6"
548 |
549 | [package.extras]
550 | lint = ["docutils-stubs", "flake8", "mypy"]
551 | test = ["html5lib", "pytest"]
552 |
553 | [[package]]
554 | name = "sphinxcontrib-jsmath"
555 | version = "1.0.1"
556 | description = "A sphinx extension which renders display math in HTML via JavaScript"
557 | category = "main"
558 | optional = true
559 | python-versions = ">=3.5"
560 |
561 | [package.extras]
562 | test = ["flake8", "mypy", "pytest"]
563 |
564 | [[package]]
565 | name = "sphinxcontrib-qthelp"
566 | version = "1.0.3"
567 | description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document."
568 | category = "main"
569 | optional = true
570 | python-versions = ">=3.5"
571 |
572 | [package.extras]
573 | lint = ["docutils-stubs", "flake8", "mypy"]
574 | test = ["pytest"]
575 |
576 | [[package]]
577 | name = "sphinxcontrib-serializinghtml"
578 | version = "1.1.5"
579 | description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)."
580 | category = "main"
581 | optional = true
582 | python-versions = ">=3.5"
583 |
584 | [package.extras]
585 | lint = ["docutils-stubs", "flake8", "mypy"]
586 | test = ["pytest"]
587 |
588 | [[package]]
589 | name = "tomli"
590 | version = "2.0.1"
591 | description = "A lil' TOML parser"
592 | category = "dev"
593 | optional = false
594 | python-versions = ">=3.7"
595 |
596 | [[package]]
597 | name = "typing-extensions"
598 | version = "4.3.0"
599 | description = "Backported and Experimental Type Hints for Python 3.7+"
600 | category = "main"
601 | optional = true
602 | python-versions = ">=3.7"
603 |
604 | [[package]]
605 | name = "urllib3"
606 | version = "1.26.11"
607 | description = "HTTP library with thread-safe connection pooling, file post, and more."
608 | category = "main"
609 | optional = true
610 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
611 |
612 | [package.extras]
613 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
614 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"]
615 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
616 |
617 | [[package]]
618 | name = "webcolors"
619 | version = "1.12"
620 | description = "A library for working with color names and color values formats defined by HTML and CSS."
621 | category = "main"
622 | optional = false
623 | python-versions = ">=3.7"
624 |
625 | [[package]]
626 | name = "zipp"
627 | version = "3.8.1"
628 | description = "Backport of pathlib-compatible object wrapper for zip files"
629 | category = "main"
630 | optional = true
631 | python-versions = ">=3.7"
632 |
633 | [package.extras]
634 | docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"]
635 | testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
636 |
637 | [extras]
638 | docs = ["myst-parser", "Sphinx", "sphinx-rtd-theme"]
639 |
640 | [metadata]
641 | lock-version = "1.1"
642 | python-versions = "^3.9"
643 | content-hash = "cc1b77fa653e3c4a09c36133586dfc1bd6ec69284c6cbfa61235c85db1b3d901"
644 |
645 | [metadata.files]
646 | alabaster = [
647 | {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
648 | {file = "alabaster-0.7.12.tar.gz", hash = "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"},
649 | ]
650 | async-timeout = [
651 | {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
652 | {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
653 | ]
654 | atomicwrites = [
655 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"},
656 | ]
657 | attrs = [
658 | {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
659 | {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
660 | ]
661 | babel = [
662 | {file = "Babel-2.10.3-py3-none-any.whl", hash = "sha256:ff56f4892c1c4bf0d814575ea23471c230d544203c7748e8c68f0089478d48eb"},
663 | {file = "Babel-2.10.3.tar.gz", hash = "sha256:7614553711ee97490f732126dc077f8d0ae084ebc6a96e23db1482afabdb2c51"},
664 | ]
665 | bleak = [
666 | {file = "bleak-0.19.0-py3-none-any.whl", hash = "sha256:ccdba0d17dcceb1326e4e46600b37e9019cd52ce01948e2a3dbd6c94d1e4de01"},
667 | {file = "bleak-0.19.0.tar.gz", hash = "sha256:cce5200ca9bac7daaa74dd009c867c8c2b161a124e234c74307462e86caf50e6"},
668 | ]
669 | bleak-retry-connector = [
670 | {file = "bleak_retry_connector-2.3.0-py3-none-any.whl", hash = "sha256:251bd30720e908ec371c8ad5e4893a14d4e7700897d3a4a4e29f0722b2d2c499"},
671 | {file = "bleak_retry_connector-2.3.0.tar.gz", hash = "sha256:58c159aa3b3ecef9f3d63beb19923279ab3c77c7cca3a0cc82cc6daae3c93637"},
672 | ]
673 | bleak-winrt = [
674 | {file = "bleak-winrt-1.2.0.tar.gz", hash = "sha256:0577d070251b9354fc6c45ffac57e39341ebb08ead014b1bdbd43e211d2ce1d6"},
675 | {file = "bleak_winrt-1.2.0-cp310-cp310-win32.whl", hash = "sha256:a2ae3054d6843ae0cfd3b94c83293a1dfd5804393977dd69bde91cb5099fc47c"},
676 | {file = "bleak_winrt-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:677df51dc825c6657b3ae94f00bd09b8ab88422b40d6a7bdbf7972a63bc44e9a"},
677 | {file = "bleak_winrt-1.2.0-cp311-cp311-win32.whl", hash = "sha256:9449cdb942f22c9892bc1ada99e2ccce9bea8a8af1493e81fefb6de2cb3a7b80"},
678 | {file = "bleak_winrt-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:98c1b5a6a6c431ac7f76aa4285b752fe14a1c626bd8a1dfa56f66173ff120bee"},
679 | {file = "bleak_winrt-1.2.0-cp37-cp37m-win32.whl", hash = "sha256:623ac511696e1f58d83cb9c431e32f613395f2199b3db7f125a3d872cab968a4"},
680 | {file = "bleak_winrt-1.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:13ab06dec55469cf51a2c187be7b630a7a2922e1ea9ac1998135974a7239b1e3"},
681 | {file = "bleak_winrt-1.2.0-cp38-cp38-win32.whl", hash = "sha256:5a36ff8cd53068c01a795a75d2c13054ddc5f99ce6de62c1a97cd343fc4d0727"},
682 | {file = "bleak_winrt-1.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:810c00726653a962256b7acd8edf81ab9e4a3c66e936a342ce4aec7dbd3a7263"},
683 | {file = "bleak_winrt-1.2.0-cp39-cp39-win32.whl", hash = "sha256:dd740047a08925bde54bec357391fcee595d7b8ca0c74c87170a5cbc3f97aa0a"},
684 | {file = "bleak_winrt-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:63130c11acfe75c504a79c01f9919e87f009f5e742bfc7b7a5c2a9c72bf591a7"},
685 | ]
686 | certifi = [
687 | {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"},
688 | {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"},
689 | ]
690 | charset-normalizer = [
691 | {file = "charset-normalizer-2.1.0.tar.gz", hash = "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413"},
692 | {file = "charset_normalizer-2.1.0-py3-none-any.whl", hash = "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5"},
693 | ]
694 | colorama = [
695 | {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
696 | {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
697 | ]
698 | coverage = [
699 | {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"},
700 | {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"},
701 | {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"},
702 | {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"},
703 | {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"},
704 | {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"},
705 | {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"},
706 | {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"},
707 | {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"},
708 | {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"},
709 | {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"},
710 | {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"},
711 | {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"},
712 | {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"},
713 | {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"},
714 | {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"},
715 | {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"},
716 | {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"},
717 | {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"},
718 | {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"},
719 | {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"},
720 | {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"},
721 | {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"},
722 | {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"},
723 | {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"},
724 | {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"},
725 | {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"},
726 | {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"},
727 | {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"},
728 | {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"},
729 | {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"},
730 | {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"},
731 | {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"},
732 | {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"},
733 | {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"},
734 | {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"},
735 | {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"},
736 | {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"},
737 | {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"},
738 | {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"},
739 | {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"},
740 | {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"},
741 | {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"},
742 | {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"},
743 | {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"},
744 | {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"},
745 | {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"},
746 | {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"},
747 | {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"},
748 | {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"},
749 | ]
750 | dbus-fast = [
751 | {file = "dbus_fast-1.45.0-cp310-cp310-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:a80d284d72ebc9893943e6be705866d72dfa37ce7534cd274e7ab1cd86b0a829"},
752 | {file = "dbus_fast-1.45.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8250cfafb1f875fe0204bbea49419ee8c72ff834c40f22765ac39c54ba1b8fd3"},
753 | {file = "dbus_fast-1.45.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5d092874c16d5f64dd5c164cbf84da151a6565fa21aa518da8cf4178e2b9df0c"},
754 | {file = "dbus_fast-1.45.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:552e145b1fdb98922cc83b24fb8677ee63029628f19bb7b2f1aca075c3208945"},
755 | {file = "dbus_fast-1.45.0-cp311-cp311-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:eb30d3d70deff8145ceedad15b7030fcc0d9b5411b84f0b80ba1f6581f83fec0"},
756 | {file = "dbus_fast-1.45.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40050d56f59be198486fc0ad1a7b4aba16928a31c89f84e98cd58ea332186a9f"},
757 | {file = "dbus_fast-1.45.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:10bc728544b95204abb9717941272146a9ba671ee7e6e93a697e4a17e93840c2"},
758 | {file = "dbus_fast-1.45.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9ca3b008892aff4e0fa5a8046a8492043f5108502f3105a09f676749855d130e"},
759 | {file = "dbus_fast-1.45.0-cp37-cp37m-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:24561a1a31de35fef7d59b285e5e5b5c1c76b7eb4e9047dcaf0a726627204b6c"},
760 | {file = "dbus_fast-1.45.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c6286bd0a9a3ef0a65dfb666df07bd77efa0d6f1798afe5dabc14437cd5ed6a"},
761 | {file = "dbus_fast-1.45.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:48e09ae676c87ca4fbc58881f0c0d6c41a67d87610878c9ed3a6692fc0368b29"},
762 | {file = "dbus_fast-1.45.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a1d81da92f2438164b8ebea566972e0706313e46490f8cc2a2c5480adc50b238"},
763 | {file = "dbus_fast-1.45.0-cp38-cp38-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:9a838a2bb353079ad4a040c697099be6481d908ae063810d28e086c259bd2786"},
764 | {file = "dbus_fast-1.45.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69a6b90ba45ace831cb6e9b5ad0c0850fed8bec95591d35edafedbeac323135"},
765 | {file = "dbus_fast-1.45.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ed0d2c86fe4c98c8f685adab6b4c18307855b7198fe8cd78971e8e1dac1e3c68"},
766 | {file = "dbus_fast-1.45.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:77ca7d27648a09fc38e54aa6289a1eb32214ac72e64bfa46a12c6161ddd3c984"},
767 | {file = "dbus_fast-1.45.0-cp39-cp39-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:b673c1810010625ef8e9a0df314267b9e7b597828412caa337716efebbdfbf05"},
768 | {file = "dbus_fast-1.45.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3292370b9f07da9bced35915b0e5b3930d24a642d18400462ab3be4af9ef552c"},
769 | {file = "dbus_fast-1.45.0-cp39-cp39-manylinux_2_31_x86_64.whl", hash = "sha256:9323a530b952aa0a6e5cd9cb00b150f74cc2ea2c519fe01e13d5d635f2607d9a"},
770 | {file = "dbus_fast-1.45.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a77dcb8c11e1685ae1d3600b9e8260ca5c9daaa9526664112af2f1bdcbee280d"},
771 | {file = "dbus_fast-1.45.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7ff3c131469b6f90a52c953d853a0a97dced5dc6678496b12657aaa1e014ca78"},
772 | {file = "dbus_fast-1.45.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:2685caab65ddb2e7b3aed6dc17a214bb1f7cfd6164f4895bee167ecd5463d71e"},
773 | {file = "dbus_fast-1.45.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5bef4860104bc3580e49a70928d6f05085c9911f842efe12f099539092a4f94"},
774 | {file = "dbus_fast-1.45.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:2cfdabca35a48172d19c56bc149c9ce76f94a747e243a3cfd7c115751988800d"},
775 | {file = "dbus_fast-1.45.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27eff54c50e752e213d98dbf9dfc2d98a8109dfa9c1314eab5074aef3ea45f51"},
776 | {file = "dbus_fast-1.45.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux_2_5_i686.manylinux1_i686.manylinux2014_i686.whl", hash = "sha256:2f7ede9ad484d38d63d33b5b54757a885d6a36569d5cfed6d1a7969576396d21"},
777 | {file = "dbus_fast-1.45.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed5e612d0c66fe204030b5c6513cd132203d0a32030e2b6d9ed84b26409959aa"},
778 | {file = "dbus_fast-1.45.0.tar.gz", hash = "sha256:ed5204b265f316f1a5ab52de3d857038532945b4645a0ff73e6dbb9622747117"},
779 | ]
780 | docutils = [
781 | {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
782 | {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
783 | ]
784 | flux-led = [
785 | {file = "flux_led-0.28.32-py3-none-any.whl", hash = "sha256:0a8a2f52a1e494f5273ba2d5cc5955f39cc948ffe1e81152b1115bcad67c94e0"},
786 | {file = "flux_led-0.28.32.tar.gz", hash = "sha256:931a690b570a93ccb1c71d62786dafd6f5e25358edcabaea41ed5a17a0b2a2ba"},
787 | ]
788 | idna = [
789 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
790 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
791 | ]
792 | imagesize = [
793 | {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
794 | {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
795 | ]
796 | importlib-metadata = [
797 | {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"},
798 | {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"},
799 | ]
800 | iniconfig = [
801 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
802 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
803 | ]
804 | jinja2 = [
805 | {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
806 | {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
807 | ]
808 | markdown-it-py = [
809 | {file = "markdown-it-py-2.1.0.tar.gz", hash = "sha256:cf7e59fed14b5ae17c0006eff14a2d9a00ed5f3a846148153899a0224e2c07da"},
810 | {file = "markdown_it_py-2.1.0-py3-none-any.whl", hash = "sha256:93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27"},
811 | ]
812 | markupsafe = [
813 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
814 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
815 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"},
816 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"},
817 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"},
818 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"},
819 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"},
820 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"},
821 | {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"},
822 | {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"},
823 | {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"},
824 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"},
825 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"},
826 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"},
827 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"},
828 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"},
829 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"},
830 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"},
831 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"},
832 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"},
833 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"},
834 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"},
835 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"},
836 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"},
837 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"},
838 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"},
839 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"},
840 | {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"},
841 | {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"},
842 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"},
843 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"},
844 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"},
845 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"},
846 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"},
847 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"},
848 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"},
849 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"},
850 | {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"},
851 | {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
852 | {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
853 | ]
854 | mdit-py-plugins = [
855 | {file = "mdit-py-plugins-0.3.0.tar.gz", hash = "sha256:ecc24f51eeec6ab7eecc2f9724e8272c2fb191c2e93cf98109120c2cace69750"},
856 | {file = "mdit_py_plugins-0.3.0-py3-none-any.whl", hash = "sha256:b1279701cee2dbf50e188d3da5f51fee8d78d038cdf99be57c6b9d1aa93b4073"},
857 | ]
858 | mdurl = [
859 | {file = "mdurl-0.1.1-py3-none-any.whl", hash = "sha256:6a8f6804087b7128040b2fb2ebe242bdc2affaeaa034d5fc9feeed30b443651b"},
860 | {file = "mdurl-0.1.1.tar.gz", hash = "sha256:f79c9709944df218a4cdb0fcc0b0c7ead2f44594e3e84dc566606f04ad749c20"},
861 | ]
862 | myst-parser = [
863 | {file = "myst-parser-0.18.0.tar.gz", hash = "sha256:739a4d96773a8e55a2cacd3941ce46a446ee23dcd6b37e06f73f551ad7821d86"},
864 | {file = "myst_parser-0.18.0-py3-none-any.whl", hash = "sha256:4965e51918837c13bf1c6f6fe2c6bddddf193148360fbdaefe743a4981358f6a"},
865 | ]
866 | packaging = [
867 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
868 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
869 | ]
870 | pluggy = [
871 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
872 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
873 | ]
874 | py = [
875 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
876 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
877 | ]
878 | pygments = [
879 | {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
880 | {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
881 | ]
882 | pyobjc-core = [
883 | {file = "pyobjc-core-8.5.1.tar.gz", hash = "sha256:f8592a12de076c27006700c4a46164478564fa33d7da41e7cbdd0a3bf9ddbccf"},
884 | {file = "pyobjc_core-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b62dcf987cc511188fc2aa5b4d3b9fd895361ea4984380463497ce4b0752ddf4"},
885 | {file = "pyobjc_core-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0accc653501a655f66c13f149a1d3d30e6cb65824edf852f7960a00c4f930d5b"},
886 | {file = "pyobjc_core-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f82b32affc898e9e5af041c1cecde2c99f2ce160b87df77f678c99f1550a4655"},
887 | {file = "pyobjc_core-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f7b2f6b6f3caeb882c658fe0c7098be2e8b79893d84daa8e636cb3e58a07df00"},
888 | {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:872c0202c911a5a2f1269261c168e36569f6ddac17e5d854ac19e581726570cc"},
889 | {file = "pyobjc_core-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:21f92e231a4bae7f2d160d065f5afbf5e859a1e37f29d34ac12592205fc8c108"},
890 | {file = "pyobjc_core-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:315334dd09781129af6a39641248891c4caa57043901750b0139c6614ce84ec0"},
891 | ]
892 | pyobjc-framework-Cocoa = [
893 | {file = "pyobjc-framework-Cocoa-8.5.1.tar.gz", hash = "sha256:9a3de5cdb4644e85daf53f2ed912ef6c16ea5804a9e65552eafe62c2e139eb8c"},
894 | {file = "pyobjc_framework_Cocoa-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa572acc2628488a47be8d19f4701fc96fce7377cc4da18316e1e08c3918521a"},
895 | {file = "pyobjc_framework_Cocoa-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb3ae21c8d81b7f02a891088c623cef61bca89bd671eff58c632d2f926b649f3"},
896 | {file = "pyobjc_framework_Cocoa-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:88f08f5bd94c66d373d8413c1d08218aff4cff0b586e0cc4249b2284023e7577"},
897 | {file = "pyobjc_framework_Cocoa-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:063683b57e4bd88cb0f9631ae65d25ec4eecf427d2fe8d0c578f88da9c896f3f"},
898 | {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f8806ddfac40620fb27f185d0f8937e69e330617319ecc2eccf6b9c8451bdd1"},
899 | {file = "pyobjc_framework_Cocoa-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:7733a9a201df9e0cc2a0cf7bf54d76bd7981cba9b599353b243e3e0c9eefec10"},
900 | {file = "pyobjc_framework_Cocoa-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f0ab227f99d3e25dd3db73f8cde0999914a5f0dd6a08600349d25f95eaa0da63"},
901 | ]
902 | pyobjc-framework-CoreBluetooth = [
903 | {file = "pyobjc-framework-CoreBluetooth-8.5.1.tar.gz", hash = "sha256:b4f621fc3b5bf289db58e64fd746773b18297f87a0ffc5502de74f69133301c1"},
904 | {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:bc720f2987a4d28dc73b13146e7c104d717100deb75c244da68f1d0849096661"},
905 | {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2167f22886beb5b3ae69e475e055403f28eab065c49a25e2b98b050b483be799"},
906 | {file = "pyobjc_framework_CoreBluetooth-8.5.1-cp36-abi3-macosx_11_0_universal2.whl", hash = "sha256:aa9587a36eca143701731e8bb6c369148f8cc48c28168d41e7323828e5117f2d"},
907 | ]
908 | pyobjc-framework-libdispatch = [
909 | {file = "pyobjc-framework-libdispatch-8.5.1.tar.gz", hash = "sha256:066fb34fceb326307559104d45532ec2c7b55426f9910b70dbefd5d1b8fd530f"},
910 | {file = "pyobjc_framework_libdispatch-8.5.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a316646ab30ba2a97bc828f8e27e7bb79efdf993d218a9c5118396b4f81dc762"},
911 | {file = "pyobjc_framework_libdispatch-8.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7730a29e4d9c7d8c2e8d9ffb60af0ab6699b2186296d2bff0a2dd54527578bc3"},
912 | {file = "pyobjc_framework_libdispatch-8.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:76208d9d2b0071df2950800495ac0300360bb5f25cbe9ab880b65cb809764979"},
913 | {file = "pyobjc_framework_libdispatch-8.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1ad9aa4773ff1d89bf4385c081824c4f8708b50e3ac2fe0a9d590153242c0f67"},
914 | {file = "pyobjc_framework_libdispatch-8.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81e1833bd26f15930faba678f9efdffafc79ec04e2ea8b6d1b88cafc0883af97"},
915 | {file = "pyobjc_framework_libdispatch-8.5.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:73226e224436eb6383e7a8a811c90ed597995adb155b4f46d727881a383ac550"},
916 | {file = "pyobjc_framework_libdispatch-8.5.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d115355ce446fc073c75cedfd7ab0a13958adda8e3a3b1e421e1f1e5f65640da"},
917 | ]
918 | pyparsing = [
919 | {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
920 | {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
921 | ]
922 | pytest = [
923 | {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"},
924 | {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"},
925 | ]
926 | pytest-cov = [
927 | {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"},
928 | {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
929 | ]
930 | pytz = [
931 | {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
932 | {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
933 | ]
934 | pyyaml = [
935 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
936 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"},
937 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"},
938 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"},
939 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
940 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
941 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
942 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
943 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
944 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
945 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"},
946 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"},
947 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"},
948 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"},
949 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"},
950 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"},
951 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"},
952 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"},
953 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"},
954 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"},
955 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"},
956 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"},
957 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"},
958 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"},
959 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"},
960 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"},
961 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"},
962 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"},
963 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"},
964 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"},
965 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"},
966 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
967 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
968 | ]
969 | requests = [
970 | {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
971 | {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
972 | ]
973 | snowballstemmer = [
974 | {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
975 | {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
976 | ]
977 | sphinx = [
978 | {file = "Sphinx-5.1.1-py3-none-any.whl", hash = "sha256:309a8da80cb6da9f4713438e5b55861877d5d7976b69d87e336733637ea12693"},
979 | {file = "Sphinx-5.1.1.tar.gz", hash = "sha256:ba3224a4e206e1fbdecf98a4fae4992ef9b24b85ebf7b584bb340156eaf08d89"},
980 | ]
981 | sphinx-rtd-theme = [
982 | {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"},
983 | {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"},
984 | ]
985 | sphinxcontrib-applehelp = [
986 | {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
987 | {file = "sphinxcontrib_applehelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a"},
988 | ]
989 | sphinxcontrib-devhelp = [
990 | {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"},
991 | {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"},
992 | ]
993 | sphinxcontrib-htmlhelp = [
994 | {file = "sphinxcontrib-htmlhelp-2.0.0.tar.gz", hash = "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2"},
995 | {file = "sphinxcontrib_htmlhelp-2.0.0-py2.py3-none-any.whl", hash = "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07"},
996 | ]
997 | sphinxcontrib-jsmath = [
998 | {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"},
999 | {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"},
1000 | ]
1001 | sphinxcontrib-qthelp = [
1002 | {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"},
1003 | {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"},
1004 | ]
1005 | sphinxcontrib-serializinghtml = [
1006 | {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"},
1007 | {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"},
1008 | ]
1009 | tomli = [
1010 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
1011 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
1012 | ]
1013 | typing-extensions = [
1014 | {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"},
1015 | {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"},
1016 | ]
1017 | urllib3 = [
1018 | {file = "urllib3-1.26.11-py2.py3-none-any.whl", hash = "sha256:c33ccba33c819596124764c23a97d25f32b28433ba0dedeb77d873a38722c9bc"},
1019 | {file = "urllib3-1.26.11.tar.gz", hash = "sha256:ea6e8fb210b19d950fab93b60c9009226c63a28808bc8386e05301e25883ac0a"},
1020 | ]
1021 | webcolors = [
1022 | {file = "webcolors-1.12-py3-none-any.whl", hash = "sha256:d98743d81d498a2d3eaf165196e65481f0d2ea85281463d856b1e51b09f62dce"},
1023 | {file = "webcolors-1.12.tar.gz", hash = "sha256:16d043d3a08fd6a1b1b7e3e9e62640d09790dce80d2bdd4792a175b35fe794a9"},
1024 | ]
1025 | zipp = [
1026 | {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"},
1027 | {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"},
1028 | ]
1029 |
--------------------------------------------------------------------------------