pax_global_header00006660000000000000000000000064147737102710014523gustar00rootroot0000000000000052 comment=96a76a505ba0f7bfa58e7df302bd4e5433567f69 forecast_solar-4.1.0/000077500000000000000000000000001477371027100145335ustar00rootroot00000000000000forecast_solar-4.1.0/.gitattributes000066400000000000000000000001021477371027100174170ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto forecast_solar-4.1.0/.github/000077500000000000000000000000001477371027100160735ustar00rootroot00000000000000forecast_solar-4.1.0/.github/dependabot.yml000066400000000000000000000004161477371027100207240ustar00rootroot00000000000000--- version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: "pip" directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 forecast_solar-4.1.0/.github/labels.yml000066400000000000000000000062431477371027100200650ustar00rootroot00000000000000--- - name: "breaking-change" color: d93f0b description: "A breaking change for existing users." - name: "bug" color: fc2929 description: "Inconsistencies or issues which will cause a problem for users." - name: "bugfix" color: ededed description: "Fixing a bug." - name: "documentation" color: 0052cc description: "Solely about the documentation of the project." - name: "enhancement" color: 1d76db description: "Enhancement of the code, not introducing new features." - name: "refactor" color: 1d76db description: "Improvement of existing code, not introducing new features." - name: "performance" color: 1d76db description: "Improving performance, not introducing new features." - name: "new-feature" color: 0e8a16 description: "New features or request." - name: "maintenance" color: 2af79e description: "Generic maintenance tasks." - name: "ci" color: 1d76db description: "Work that improves the continue integration." - name: "dependencies" color: 1d76db description: "Upgrade or downgrade of project dependencies." - name: "in-progress" color: fbca04 description: "Issue is currently being resolved by a developer." - name: "stale" color: fef2c0 description: "There has not been activity on this issue or PR for quite some time." - name: "no-stale" color: fef2c0 description: "This issue or PR is exempted from the stable bot." - name: "wontfix" color: ffffff description: "This issue or PR will not be fixed." - name: "cleanup" color: ef75d5 description: "Cleanup of code." - name: "sync" color: 00a6ed description: "Syncing with upstream github config repository." - name: "security" color: ee0701 description: "Marks a security issue that needs to be resolved asap." - name: "incomplete" color: fef2c0 description: "Marks a PR or issue that is missing information." - name: "invalid" color: fef2c0 description: "Marks a PR or issue that is missing information." - name: "duplicate" color: cfd3d7 description: "This issue or pull request already exists." - name: "beginner-friendly" color: 0e8a16 description: "Good first issue for people wanting to contribute to the project." - name: "help-wanted" color: 0e8a16 description: "We need some extra helping hands or expertise in order to resolve this." - name: "hacktoberfest" description: "Issues/PRs are participating in the Hacktoberfest." color: fbca04 - name: "hacktoberfest-accepted" description: "Issues/PRs are participating in the Hacktoberfest." color: fbca04 - name: "priority-critical" color: ee0701 description: "This should be dealt with ASAP. Not fixing this issue would be a serious error." - name: "priority-high" color: b60205 description: "After critical issues are fixed, these should be dealt with before any further issues." - name: "priority-medium" color: 0e8a16 description: "This issue may be useful, and needs some attention." - name: "priority-low" color: e4ea8a description: "Nice addition, maybe... someday..." - name: "major" color: b60205 description: "This PR causes a major version bump in the version number." - name: "minor" color: 0e8a16 description: "This PR causes a minor version bump in the version number." forecast_solar-4.1.0/.github/release-drafter.yml000066400000000000000000000022411477371027100216620ustar00rootroot00000000000000--- name-template: "v$RESOLVED_VERSION" tag-template: "v$RESOLVED_VERSION" change-template: "- #$NUMBER $TITLE @$AUTHOR" sort-direction: ascending categories: - title: "๐Ÿšจ Breaking changes" labels: - "breaking-change" - title: "โœจ New features" labels: - "new-feature" - title: "๐Ÿ› Bug fixes" labels: - "bugfix" - title: "๐Ÿš€ Enhancements" labels: - "enhancement" - "refactor" - "performance" - title: "๐Ÿงฐ Maintenance" labels: - "maintenance" - "ci" - title: "๐Ÿ“š Documentation" labels: - "documentation" - title: "โฌ†๏ธ Dependency updates" collapse-after: 5 labels: - "dependencies" version-resolver: major: labels: - "major" - "breaking-change" minor: labels: - "minor" - "new-feature" patch: labels: - "bugfix" - "chore" - "ci" - "dependencies" - "documentation" - "enhancement" - "performance" - "refactor" default: patch template: | ## What's changed $CHANGES **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION forecast_solar-4.1.0/.github/workflows/000077500000000000000000000000001477371027100201305ustar00rootroot00000000000000forecast_solar-4.1.0/.github/workflows/linting.yaml000066400000000000000000000074521477371027100224700ustar00rootroot00000000000000--- name: Linting # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.11" jobs: ruff: name: Ruff runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install Python dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Run ruff linter run: poetry run ruff check --output-format=github . - name: ๐Ÿš€ Run ruff formatter run: poetry run ruff format --check . pre-commit-hooks: name: pre-commit-hooks runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install Python dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Check Python AST run: poetry run pre-commit run check-ast --all-files - name: ๐Ÿš€ Check for case conflicts run: poetry run pre-commit run check-case-conflict --all-files - name: ๐Ÿš€ Check docstring is first run: poetry run pre-commit run check-docstring-first --all-files - name: ๐Ÿš€ Check that executables have shebangs run: poetry run pre-commit run check-executables-have-shebangs --all-files - name: ๐Ÿš€ Check JSON files run: poetry run pre-commit run check-json --all-files - name: ๐Ÿš€ Check for merge conflicts run: poetry run pre-commit run check-merge-conflict --all-files - name: ๐Ÿš€ Check for broken symlinks run: poetry run pre-commit run check-symlinks --all-files - name: ๐Ÿš€ Check TOML files run: poetry run pre-commit run check-toml --all-files - name: ๐Ÿš€ Check XML files run: poetry run pre-commit run check-xml --all-files - name: ๐Ÿš€ Check YAML files run: poetry run pre-commit run check-yaml --all-files - name: ๐Ÿš€ Detect Private Keys run: poetry run pre-commit run detect-private-key --all-files - name: ๐Ÿš€ Check End of Files run: poetry run pre-commit run end-of-file-fixer --all-files - name: ๐Ÿš€ Trim Trailing Whitespace run: poetry run pre-commit run trailing-whitespace --all-files yamllint: name: yamllint runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install Python dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Run yamllint run: poetry run yamllint . forecast_solar-4.1.0/.github/workflows/pr-labels.yaml000066400000000000000000000013021477371027100226710ustar00rootroot00000000000000--- name: PR Labels # yamllint disable-line rule:truthy on: pull_request_target: types: - opened - labeled - unlabeled - synchronize workflow_call: jobs: pr_labels: name: Verify runs-on: ubuntu-latest steps: - name: ๐Ÿท Verify PR has a valid label uses: jesusvasquez333/verify-pr-label-action@v1.4.0 with: pull-request-number: "${{ github.event.pull_request.number }}" github-token: "${{ secrets.GITHUB_TOKEN }}" valid-labels: >- breaking-change, bugfix, documentation, enhancement, refactor, performance, new-feature, maintenance, ci, dependencies disable-reviews: true forecast_solar-4.1.0/.github/workflows/release-drafter.yaml000066400000000000000000000006771477371027100240730ustar00rootroot00000000000000--- name: Release Drafter # yamllint disable-line rule:truthy on: push: branches: - master workflow_dispatch: jobs: update_release_draft: name: โœ๏ธ Draft release runs-on: ubuntu-latest permissions: contents: write pull-requests: read steps: - name: ๐Ÿš€ Run Release Drafter uses: release-drafter/release-drafter@v6.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} forecast_solar-4.1.0/.github/workflows/release.yaml000066400000000000000000000024601477371027100224360ustar00rootroot00000000000000--- name: Release # yamllint disable rule:line-length # yamllint disable-line rule:truthy on: release: types: - published env: DEFAULT_PYTHON: "3.11" jobs: release: name: Releasing to PyPi runs-on: ubuntu-latest environment: release permissions: id-token: write steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install dependencies run: poetry install --no-interaction - name: ๐Ÿ— Set package version run: | version="${{ github.event.release.tag_name }}" version="${version,,}" version="${version#v}" poetry version --no-interaction "${version}" - name: ๐Ÿ— Build package run: poetry build --no-interaction - name: ๐Ÿš€ Publish package to PyPi uses: pypa/gh-action-pypi-publish@v1.12.4 forecast_solar-4.1.0/.github/workflows/sync-labels.yml000066400000000000000000000010141477371027100230630ustar00rootroot00000000000000--- name: Sync labels # yamllint disable-line rule:truthy on: push: branches: - master paths: - .github/labels.yml workflow_dispatch: jobs: labels: name: โ™ป๏ธ Sync labels runs-on: ubuntu-latest permissions: pull-requests: write steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿš€ Run Label Syncer uses: micnncim/action-label-syncer@v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} forecast_solar-4.1.0/.github/workflows/tests.yaml000066400000000000000000000042051477371027100221570ustar00rootroot00000000000000--- name: Testing # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.11" jobs: pytest: name: Python ${{ matrix.python }} runs-on: ubuntu-latest strategy: matrix: python: ["3.11", "3.12", "3.13"] steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ matrix.python }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ matrix.python }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Run pytest run: poetry run pytest -v --cov-report xml:coverage.xml --cov src tests - name: โฌ†๏ธ Upload coverage artifact uses: actions/upload-artifact@v4.6.2 with: name: coverage-${{ matrix.python }} path: coverage.xml coverage: runs-on: ubuntu-latest needs: pytest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 with: fetch-depth: 0 - name: โฌ‡๏ธ Download coverage data uses: actions/download-artifact@v4.2.1 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: 'poetry' - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Upload coverage report uses: codecov/codecov-action@v5.4.0 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true forecast_solar-4.1.0/.github/workflows/typing.yaml000066400000000000000000000015731477371027100223340ustar00rootroot00000000000000--- name: Typing # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.11" jobs: mypy: name: mypy runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v4.2.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v5.5.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: ๐Ÿ— Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: ๐Ÿ— Install dependencies run: poetry install --no-interaction - name: ๐Ÿš€ Run mypy run: poetry run mypy examples src tests forecast_solar-4.1.0/.gitignore000066400000000000000000000032361477371027100165270ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ forecast_solar-4.1.0/.pre-commit-config.yaml000066400000000000000000000066201477371027100210200ustar00rootroot00000000000000--- repos: - repo: local hooks: - id: ruff-check name: ๐Ÿถ Ruff Linter language: system types: [python] entry: poetry run ruff check --fix require_serial: true stages: [pre-commit, pre-push, manual] - id: ruff-format name: ๐Ÿถ Ruff Formatter language: system types: [python] entry: poetry run ruff format require_serial: true stages: [pre-commit, pre-push, manual] - id: check-ast name: ๐Ÿ Check Python AST language: system types: [python] entry: poetry run check-ast - id: check-case-conflict name: ๐Ÿ”  Check for case conflicts language: system entry: poetry run check-case-conflict - id: check-docstring-first name: โ„น๏ธ Check docstring is first language: system types: [python] entry: poetry run check-docstring-first - id: check-executables-have-shebangs name: ๐Ÿง Check that executables have shebangs language: system types: [text, executable] entry: poetry run check-executables-have-shebangs stages: [pre-commit, pre-push, manual] - id: check-json name: ๏ฝ› Check JSON files language: system types: [json] entry: poetry run check-json - id: check-merge-conflict name: ๐Ÿ’ฅ Check for merge conflicts language: system types: [text] entry: poetry run check-merge-conflict - id: check-symlinks name: ๐Ÿ”— Check for broken symlinks language: system types: [symlink] entry: poetry run check-symlinks - id: check-toml name: โœ… Check TOML files language: system types: [toml] entry: poetry run check-toml - id: check-xml name: โœ… Check XML files entry: poetry run check-xml language: system types: [xml] - id: check-yaml name: โœ… Check YAML files language: system types: [yaml] entry: poetry run check-yaml - id: detect-private-key name: ๐Ÿ•ต๏ธ Detect Private Keys language: system types: [text] entry: poetry run detect-private-key - id: end-of-file-fixer name: โฎ Fix End of Files language: system types: [text] entry: poetry run end-of-file-fixer stages: [pre-commit, pre-push, manual] - id: no-commit-to-branch name: ๐Ÿ›‘ Don't commit to main branch language: system entry: poetry run no-commit-to-branch pass_filenames: false always_run: true args: - --branch=master - id: poetry name: ๐Ÿ“œ Check pyproject with Poetry language: system entry: poetry check pass_filenames: false always_run: true - id: pytest name: ๐Ÿงช Running tests and test coverage with pytest language: system types: [python] entry: poetry run pytest pass_filenames: false - id: trailing-whitespace name: โœ„ Trim Trailing Whitespace language: system types: [text] entry: poetry run trailing-whitespace-fixer stages: [pre-commit, pre-push, manual] - id: yamllint name: ๐ŸŽ— Check YAML files with yamllint language: system types: [yaml] entry: poetry run yamllint forecast_solar-4.1.0/.yamllint000066400000000000000000000024041477371027100163650ustar00rootroot00000000000000--- ignore: | .venv/lib rules: braces: level: error min-spaces-inside: 0 max-spaces-inside: 1 min-spaces-inside-empty: -1 max-spaces-inside-empty: -1 brackets: level: error min-spaces-inside: 0 max-spaces-inside: 0 min-spaces-inside-empty: -1 max-spaces-inside-empty: -1 colons: level: error max-spaces-before: 0 max-spaces-after: 1 commas: level: error max-spaces-before: 0 min-spaces-after: 1 max-spaces-after: 1 comments: level: error require-starting-space: true min-spaces-from-content: 1 comments-indentation: level: error document-end: level: error present: false document-start: level: error present: true empty-lines: level: error max: 1 max-start: 0 max-end: 1 hyphens: level: error max-spaces-after: 1 indentation: level: error spaces: 2 indent-sequences: true check-multi-line-strings: false key-duplicates: level: error line-length: level: warning max: 120 allow-non-breakable-words: true allow-non-breakable-inline-mappings: true new-line-at-end-of-file: level: error new-lines: level: error type: unix trailing-spaces: level: error truthy: level: error forecast_solar-4.1.0/CONTRIBUTING.md000066400000000000000000000022311477371027100167620ustar00rootroot00000000000000# Contributing When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change. Please note we have a code of conduct, please follow it in all your interactions with the project. ## Issues and feature requests You've found a bug in the source code, a mistake in the documentation or maybe you'd like a new feature? You can help us by submitting an issue to our [GitHub Repository][github]. Before you create an issue, make sure you search the archive, maybe your question was already answered. Even better: You could submit a pull request with a fix / new feature! ## Pull request process 1. Search our repository for open or closed [pull requests][prs] that relates to your submission. You don't want to duplicate effort. 1. You may merge the pull request in once you have the sign-off of two other developers, or if you do not have permission to do that, you may request the second reviewer to merge it for you. [github]: https://github.com/klaasnicolaas/forecast_solar/issues [prs]: https://github.com/klaasnicolaas/forecast_solar/pulls forecast_solar-4.1.0/LICENSE000066400000000000000000000020651477371027100155430ustar00rootroot00000000000000# MIT License Copyright (c) 2021-2025 Klaas Schoute Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. forecast_solar-4.1.0/README.md000066400000000000000000000164651477371027100160260ustar00rootroot00000000000000 ## Python API fetching Solarpanels forecast information. ![Project Maintenance][maintenance-shield] [![License][license-shield]](LICENSE) [![GitHub Activity][commits-shield]][commits] [![GitHub Last Commit][last-commit-shield]][commits] [![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] ## About With this python library you can request data from [forecast.solar](https://forecast.solar) and see what your solar panels may produce in the coming days. ## Installation ```bash pip install forecast-solar ``` ## Data This library returns a lot of different data, based on the API: ### Energy - Total Estimated Energy Production - today/tomorrow (kWh) - Estimated Energy Production - This Hour (kWh) - Estimated Energy Production - Next Hour (kWh) - Estimated Energy Production - Remaining today (kWh) ### Power - Highest Power Peak Time - Today (datetime) - Highest Power Peak Time - Tomorrow (datetime) - Estimated Power Production - Now (W) - Estimated Power Production - Next Hour (W) - Estimated Power Production - In +6 Hours (W) - Estimated Power Production - In +12 Hours (W) - Estimated Power Production - In +24 Hours (W) ### API Info - Timezone - Rate limit - Account type - Rate remaining ### Validation - API key (bool) - Plane (bool) ## Example ```python import asyncio from forecast_solar import ForecastSolar async def main() -> None: """Show example on how to use the library.""" async with ForecastSolar( api_key="YOUR_API_KEY", latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, damping=0, damping_morning=0.5, damping_evening=0.5, horizon="0,0,0,10,10,20,20,30,30", ) as forecast: estimate = await forecast.estimate(actual=2.315) print(estimate) if __name__ == "__main__": asyncio.run(main()) ``` ## ForecastSolar object | Parameter | value type | Description | | --------- | ---------- | ----------- | | `api_key` | `str` | Your API key from [forecast.solar](https://forecast.solar) (optional) | | `declination` | `int` | The tilt of the solar panels (required) | | `azimuth` | `int` | The direction the solar panels are facing (required) | | `kwp` | `float` | The size of the solar panels in kWp (required) | | `damping` | `float` | The damping of the solar panels, [read this][forecast-damping] for more information (optional) | | `damping_morning` | `float` | The damping of the solar panels in the morning (optional) | | `damping_evening` | `float` | The damping of the solar panels in the evening (optional) | | `inverter` | `float` | The maximum power of your inverter in kilo watts (optional) | | `horizon` | `str` | A list of **comma separated** degrees values, [read this][forecast-horizon] for more information (optional) | ## estimate() method | Parameter | value type | Description | | --------- | ---------- | -------------------------------------------------------------------------------------------------- | | `actual` | `float` | The production in kWh for the current day so far. Only used when an API key is provided (optional) | ## Contributing Would you like to contribute to the development of this project? Then read the prepared [contribution guidelines](CONTRIBUTING.md) and go ahead! Thank you for being involved! :heart_eyes: ## Setting up development environment This Python project relies on [Poetry][poetry] as its dependency manager, providing comprehensive management and control over project dependencies. You need at least: - Python 3.11+ - [Poetry][poetry-install] ### Installation Install all packages, including all development requirements: ```bash poetry install ``` _Poetry creates by default an virtual environment where it installs all necessary pip packages_. ### Pre-commit This repository uses the [pre-commit][pre-commit] framework, all changes are linted and tested with each commit. To setup the pre-commit check, run: ```bash poetry run pre-commit install ``` And to run all checks and tests manually, use the following command: ```bash poetry run pre-commit run --all-files ``` ### Testing It uses [pytest](https://docs.pytest.org/en/stable/) as the test framework. To run the tests: ```bash poetry run pytest ``` To update the [syrupy](https://github.com/tophat/syrupy) snapshot tests: ```bash poetry run pytest --snapshot-update ``` ## License MIT License Copyright (c) 2021-2025 Klaas Schoute Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [forecast-horizon]: https://doc.forecast.solar/doku.php?id=api#horizon [forecast-damping]: https://doc.forecast.solar/doku.php?id=damping [maintenance-shield]: https://img.shields.io/maintenance/yes/2025.svg?style=for-the-badge [contributors-shield]: https://img.shields.io/github/contributors/home-assistant-libs/forecast_solar.svg?style=for-the-badge [contributors-url]: https://github.com/home-assistant-libs/forecast_solar/graphs/contributors [forks-shield]: https://img.shields.io/github/forks/home-assistant-libs/forecast_solar.svg?style=for-the-badge [forks-url]: https://github.com/home-assistant-libs/forecast_solar/network/members [stars-shield]: https://img.shields.io/github/stars/home-assistant-libs/forecast_solar.svg?style=for-the-badge [stars-url]: https://github.com/home-assistant-libs/forecast_solar/stargazers [issues-shield]: https://img.shields.io/github/issues/home-assistant-libs/forecast_solar.svg?style=for-the-badge [issues-url]: https://github.com/home-assistant-libs/forecast_solar/issues [license-shield]: https://img.shields.io/github/license/home-assistant-libs/forecast_solar.svg?style=for-the-badge [commits-shield]: https://img.shields.io/github/commit-activity/y/home-assistant-libs/forecast_solar.svg?style=for-the-badge [commits]: https://github.com/home-assistant-libs/forecast_solar/commits/master [last-commit-shield]: https://img.shields.io/github/last-commit/home-assistant-libs/forecast_solar.svg?style=for-the-badge [poetry-install]: https://python-poetry.org/docs/#installation [poetry]: https://python-poetry.org [pre-commit]: https://pre-commit.com forecast_solar-4.1.0/codecov.yml000066400000000000000000000001551477371027100167010ustar00rootroot00000000000000--- comment: false coverage: status: project: default: target: 90 threshold: 10% forecast_solar-4.1.0/examples/000077500000000000000000000000001477371027100163515ustar00rootroot00000000000000forecast_solar-4.1.0/examples/estimate.py000066400000000000000000000057431477371027100205470ustar00rootroot00000000000000"""Example of how to get an estimate from the Forecast.Solar API.""" import asyncio from datetime import UTC, datetime, timedelta from pprint import pprint # noqa: F401 from forecast_solar import ForecastSolar, ForecastSolarRatelimitError async def main() -> None: """Get an estimate from the Forecast.Solar API.""" async with ForecastSolar( latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, damping=0, horizon="0,0,0,10,10,20,20,30,30", ) as forecast: try: estimate = await forecast.estimate() except ForecastSolarRatelimitError as err: print("Ratelimit reached") print(f"Rate limit resets at {err.reset_at}") reset_period = err.reset_at - datetime.now(UTC) # Strip microseconds as they are not informative reset_period -= timedelta(microseconds=reset_period.microseconds) print(f"That's in {reset_period}") return # Uncomment this if you want to see what's in the estimate arrays # pprint(dataclasses.asdict(estimate)) print() print(f"energy_production_today: {estimate.energy_production_today}") print( "energy_production_today_remaining: " f"{estimate.energy_production_today_remaining}" ) print( f"power_highest_peak_time_today: {estimate.power_highest_peak_time_today}" ) print(f"energy_production_tomorrow: {estimate.energy_production_tomorrow}") print( "power_highest_peak_time_tomorrow: " f"{estimate.power_highest_peak_time_tomorrow}" ) print() print(f"power_production_now: {estimate.power_production_now}") print( "power_production in 1 hour: " f"{estimate.power_production_at_time(estimate.now() + timedelta(hours=1))}" ) print( "power_production in 6 hours: " f"{estimate.power_production_at_time(estimate.now() + timedelta(hours=6))}" ) print( "power_production in 12 hours: " f"{estimate.power_production_at_time(estimate.now() + timedelta(hours=12))}" ) print( "power_production in 24 hours: " f"{estimate.power_production_at_time(estimate.now() + timedelta(hours=24))}" ) print() print(f"energy_current_hour: {estimate.energy_current_hour}") print(f"energy_production next hour: {estimate.sum_energy_production(1)}") print(f"energy_production next 6 hours: {estimate.sum_energy_production(6)}") print(f"energy_production next 12 hours: {estimate.sum_energy_production(12)}") print(f"energy_production next 24 hours: {estimate.sum_energy_production(24)}") print(f"timezone: {estimate.timezone}") print(f"account_type: {estimate.account_type}") print(forecast.ratelimit) if __name__ == "__main__": asyncio.run(main()) forecast_solar-4.1.0/examples/ruff.toml000066400000000000000000000003411477371027100202060ustar00rootroot00000000000000# This extend our general Ruff rules specifically for the examples extend = "../pyproject.toml" lint.extend-ignore = [ "T201", # Allow the use of print() in examples "ERA001", # Allow the use of comments in examples ] forecast_solar-4.1.0/poetry.lock000066400000000000000000004277551477371027100167530ustar00rootroot00000000000000# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand. [[package]] name = "aiodns" version = "3.2.0" description = "Simple DNS resolver for asyncio" optional = false python-versions = "*" groups = ["main"] files = [ {file = "aiodns-3.2.0-py3-none-any.whl", hash = "sha256:e443c0c27b07da3174a109fd9e736d69058d808f144d3c9d56dbd1776964c5f5"}, {file = "aiodns-3.2.0.tar.gz", hash = "sha256:62869b23409349c21b072883ec8998316b234c9a9e36675756e8e317e8768f72"}, ] [package.dependencies] pycares = ">=4.0.0" [[package]] name = "aiohappyeyeballs" version = "2.4.3" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572"}, {file = "aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586"}, ] [[package]] name = "aiohttp" version = "3.11.11" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a60804bff28662cbcf340a4d61598891f12eea3a66af48ecfdc975ceec21e3c8"}, {file = "aiohttp-3.11.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b4fa1cb5f270fb3eab079536b764ad740bb749ce69a94d4ec30ceee1b5940d5"}, {file = "aiohttp-3.11.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:731468f555656767cda219ab42e033355fe48c85fbe3ba83a349631541715ba2"}, {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb23d8bb86282b342481cad4370ea0853a39e4a32a0042bb52ca6bdde132df43"}, {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f047569d655f81cb70ea5be942ee5d4421b6219c3f05d131f64088c73bb0917f"}, {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd7659baae9ccf94ae5fe8bfaa2c7bc2e94d24611528395ce88d009107e00c6d"}, {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af01e42ad87ae24932138f154105e88da13ce7d202a6de93fafdafb2883a00ef"}, {file = "aiohttp-3.11.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5854be2f3e5a729800bac57a8d76af464e160f19676ab6aea74bde18ad19d438"}, {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6526e5fb4e14f4bbf30411216780c9967c20c5a55f2f51d3abd6de68320cc2f3"}, {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85992ee30a31835fc482468637b3e5bd085fa8fe9392ba0bdcbdc1ef5e9e3c55"}, {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:88a12ad8ccf325a8a5ed80e6d7c3bdc247d66175afedbe104ee2aaca72960d8e"}, {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0a6d3fbf2232e3a08c41eca81ae4f1dff3d8f1a30bae415ebe0af2d2458b8a33"}, {file = "aiohttp-3.11.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84a585799c58b795573c7fa9b84c455adf3e1d72f19a2bf498b54a95ae0d194c"}, {file = "aiohttp-3.11.11-cp310-cp310-win32.whl", hash = "sha256:bfde76a8f430cf5c5584553adf9926534352251d379dcb266ad2b93c54a29745"}, {file = "aiohttp-3.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0fd82b8e9c383af11d2b26f27a478640b6b83d669440c0a71481f7c865a51da9"}, {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76"}, {file = "aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538"}, {file = "aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204"}, {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9"}, {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03"}, {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287"}, {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e"}, {file = "aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665"}, {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b"}, {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34"}, {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d"}, {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2"}, {file = "aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773"}, {file = "aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62"}, {file = "aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac"}, {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886"}, {file = "aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2"}, {file = "aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c"}, {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a"}, {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231"}, {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e"}, {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8"}, {file = "aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8"}, {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c"}, {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab"}, {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da"}, {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853"}, {file = "aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e"}, {file = "aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600"}, {file = "aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d"}, {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:541d823548ab69d13d23730a06f97460f4238ad2e5ed966aaf850d7c369782d9"}, {file = "aiohttp-3.11.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:929f3ed33743a49ab127c58c3e0a827de0664bfcda566108989a14068f820194"}, {file = "aiohttp-3.11.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0882c2820fd0132240edbb4a51eb8ceb6eef8181db9ad5291ab3332e0d71df5f"}, {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b63de12e44935d5aca7ed7ed98a255a11e5cb47f83a9fded7a5e41c40277d104"}, {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa54f8ef31d23c506910c21163f22b124facb573bff73930735cf9fe38bf7dff"}, {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344d5dc18074e3872777b62f5f7d584ae4344cd6006c17ba12103759d407af3"}, {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7fb429ab1aafa1f48578eb315ca45bd46e9c37de11fe45c7f5f4138091e2f1"}, {file = "aiohttp-3.11.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c341c7d868750e31961d6d8e60ff040fb9d3d3a46d77fd85e1ab8e76c3e9a5c4"}, {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ed9ee95614a71e87f1a70bc81603f6c6760128b140bc4030abe6abaa988f1c3d"}, {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:de8d38f1c2810fa2a4f1d995a2e9c70bb8737b18da04ac2afbf3971f65781d87"}, {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a9b7371665d4f00deb8f32208c7c5e652059b0fda41cf6dbcac6114a041f1cc2"}, {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:620598717fce1b3bd14dd09947ea53e1ad510317c85dda2c9c65b622edc96b12"}, {file = "aiohttp-3.11.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bf8d9bfee991d8acc72d060d53860f356e07a50f0e0d09a8dfedea1c554dd0d5"}, {file = "aiohttp-3.11.11-cp313-cp313-win32.whl", hash = "sha256:9d73ee3725b7a737ad86c2eac5c57a4a97793d9f442599bea5ec67ac9f4bdc3d"}, {file = "aiohttp-3.11.11-cp313-cp313-win_amd64.whl", hash = "sha256:c7a06301c2fb096bdb0bd25fe2011531c1453b9f2c163c8031600ec73af1cc99"}, {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3e23419d832d969f659c208557de4a123e30a10d26e1e14b73431d3c13444c2e"}, {file = "aiohttp-3.11.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21fef42317cf02e05d3b09c028712e1d73a9606f02467fd803f7c1f39cc59add"}, {file = "aiohttp-3.11.11-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1f21bb8d0235fc10c09ce1d11ffbd40fc50d3f08a89e4cf3a0c503dc2562247a"}, {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1642eceeaa5ab6c9b6dfeaaa626ae314d808188ab23ae196a34c9d97efb68350"}, {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2170816e34e10f2fd120f603e951630f8a112e1be3b60963a1f159f5699059a6"}, {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8be8508d110d93061197fd2d6a74f7401f73b6d12f8822bbcd6d74f2b55d71b1"}, {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4eed954b161e6b9b65f6be446ed448ed3921763cc432053ceb606f89d793927e"}, {file = "aiohttp-3.11.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6c9af134da4bc9b3bd3e6a70072509f295d10ee60c697826225b60b9959acdd"}, {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:44167fc6a763d534a6908bdb2592269b4bf30a03239bcb1654781adf5e49caf1"}, {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:479b8c6ebd12aedfe64563b85920525d05d394b85f166b7873c8bde6da612f9c"}, {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:10b4ff0ad793d98605958089fabfa350e8e62bd5d40aa65cdc69d6785859f94e"}, {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b540bd67cfb54e6f0865ceccd9979687210d7ed1a1cc8c01f8e67e2f1e883d28"}, {file = "aiohttp-3.11.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1dac54e8ce2ed83b1f6b1a54005c87dfed139cf3f777fdc8afc76e7841101226"}, {file = "aiohttp-3.11.11-cp39-cp39-win32.whl", hash = "sha256:568c1236b2fde93b7720f95a890741854c1200fba4a3471ff48b2934d2d93fd3"}, {file = "aiohttp-3.11.11-cp39-cp39-win_amd64.whl", hash = "sha256:943a8b052e54dfd6439fd7989f67fc6a7f2138d0a2cf0a7de5f18aa4fe7eb3b1"}, {file = "aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e"}, ] [package.dependencies] aiohappyeyeballs = ">=2.3.0" aiosignal = ">=1.1.2" attrs = ">=17.3.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" propcache = ">=0.2.0" yarl = ">=1.17.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"] [[package]] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, ] [package.dependencies] frozenlist = ">=1.1.0" [[package]] name = "aresponses" version = "3.0.0" description = "Asyncio response mocking. Similar to the responses library used for 'requests'" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "aresponses-3.0.0-py3-none-any.whl", hash = "sha256:8093ab4758eb4aba91c765a50295b269ecfc0a9e7c7158954760bc0c23503970"}, {file = "aresponses-3.0.0.tar.gz", hash = "sha256:8731d0609fe4c954e21f17753dc868dca9e2e002b020a33dc9212004599b11e7"}, ] [package.dependencies] aiohttp = [ {version = ">=3.7.0", markers = "python_version >= \"3.10\" and python_version < \"3.12\""}, {version = ">=3.7.0,<3.8.dev0 || >=3.9.dev0", markers = "python_version >= \"3.12\""}, ] pytest-asyncio = {version = ">=0.17.0", markers = "python_version >= \"3.7\""} [[package]] name = "attrs" version = "24.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" groups = ["main", "dev"] files = [ {file = "attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2"}, {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] [package.extras] benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"] cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"] tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"] [[package]] name = "cffi" version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" groups = ["main"] files = [ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] pycparser = "*" [[package]] name = "cfgv" version = "3.4.0" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, ] [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] [[package]] name = "covdefaults" version = "2.3.0" description = "A coverage plugin to provide sensible default settings" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "covdefaults-2.3.0-py2.py3-none-any.whl", hash = "sha256:2832961f6ffcfe4b57c338bc3418a3526f495c26fb9c54565409c5532f7c41be"}, {file = "covdefaults-2.3.0.tar.gz", hash = "sha256:4e99f679f12d792bc62e5510fa3eb59546ed47bd569e36e4fddc4081c9c3ebf7"}, ] [package.dependencies] coverage = ">=6.0.2" [[package]] name = "coverage" version = "7.6.4" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [package.extras] toml = ["tomli"] [[package]] name = "distlib" version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] name = "filelock" version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "freezegun" version = "1.5.1" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "freezegun-1.5.1-py3-none-any.whl", hash = "sha256:bf111d7138a8abe55ab48a71755673dbaa4ab87f4cff5634a4442dfec34c15f1"}, {file = "freezegun-1.5.1.tar.gz", hash = "sha256:b29dedfcda6d5e8e083ce71b2b542753ad48cfec44037b3fc79702e2980a89e9"}, ] [package.dependencies] python-dateutil = ">=2.7" [[package]] name = "frozenlist" version = "1.5.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"}, {file = "frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec"}, {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5"}, {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76"}, {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17"}, {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba"}, {file = "frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d"}, {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2"}, {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f"}, {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c"}, {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab"}, {file = "frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5"}, {file = "frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb"}, {file = "frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4"}, {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30"}, {file = "frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5"}, {file = "frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778"}, {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a"}, {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869"}, {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d"}, {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45"}, {file = "frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d"}, {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3"}, {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a"}, {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9"}, {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2"}, {file = "frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf"}, {file = "frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942"}, {file = "frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d"}, {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21"}, {file = "frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d"}, {file = "frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e"}, {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a"}, {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a"}, {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee"}, {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6"}, {file = "frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e"}, {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9"}, {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039"}, {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784"}, {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631"}, {file = "frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f"}, {file = "frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8"}, {file = "frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f"}, {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953"}, {file = "frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0"}, {file = "frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2"}, {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f"}, {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608"}, {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b"}, {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840"}, {file = "frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439"}, {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de"}, {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641"}, {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e"}, {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9"}, {file = "frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03"}, {file = "frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c"}, {file = "frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28"}, {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:dd94994fc91a6177bfaafd7d9fd951bc8689b0a98168aa26b5f543868548d3ca"}, {file = "frozenlist-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0da8bbec082bf6bf18345b180958775363588678f64998c2b7609e34719b10"}, {file = "frozenlist-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:73f2e31ea8dd7df61a359b731716018c2be196e5bb3b74ddba107f694fbd7604"}, {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:828afae9f17e6de596825cf4228ff28fbdf6065974e5ac1410cecc22f699d2b3"}, {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1577515d35ed5649d52ab4319db757bb881ce3b2b796d7283e6634d99ace307"}, {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2150cc6305a2c2ab33299453e2968611dacb970d2283a14955923062c8d00b10"}, {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a72b7a6e3cd2725eff67cd64c8f13335ee18fc3c7befc05aed043d24c7b9ccb9"}, {file = "frozenlist-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c16d2fa63e0800723139137d667e1056bee1a1cf7965153d2d104b62855e9b99"}, {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:17dcc32fc7bda7ce5875435003220a457bcfa34ab7924a49a1c19f55b6ee185c"}, {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:97160e245ea33d8609cd2b8fd997c850b56db147a304a262abc2b3be021a9171"}, {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f1e6540b7fa044eee0bb5111ada694cf3dc15f2b0347ca125ee9ca984d5e9e6e"}, {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:91d6c171862df0a6c61479d9724f22efb6109111017c87567cfeb7b5d1449fdf"}, {file = "frozenlist-1.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c1fac3e2ace2eb1052e9f7c7db480818371134410e1f5c55d65e8f3ac6d1407e"}, {file = "frozenlist-1.5.0-cp38-cp38-win32.whl", hash = "sha256:b97f7b575ab4a8af9b7bc1d2ef7f29d3afee2226bd03ca3875c16451ad5a7723"}, {file = "frozenlist-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:374ca2dabdccad8e2a76d40b1d037f5bd16824933bf7bcea3e59c891fd4a0923"}, {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9bbcdfaf4af7ce002694a4e10a0159d5a8d20056a12b05b45cea944a4953f972"}, {file = "frozenlist-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1893f948bf6681733aaccf36c5232c231e3b5166d607c5fa77773611df6dc336"}, {file = "frozenlist-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2b5e23253bb709ef57a8e95e6ae48daa9ac5f265637529e4ce6b003a37b2621f"}, {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f253985bb515ecd89629db13cb58d702035ecd8cfbca7d7a7e29a0e6d39af5f"}, {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04a5c6babd5e8fb7d3c871dc8b321166b80e41b637c31a995ed844a6139942b6"}, {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9fe0f1c29ba24ba6ff6abf688cb0b7cf1efab6b6aa6adc55441773c252f7411"}, {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:226d72559fa19babe2ccd920273e767c96a49b9d3d38badd7c91a0fdeda8ea08"}, {file = "frozenlist-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b731db116ab3aedec558573c1a5eec78822b32292fe4f2f0345b7f697745c2"}, {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:366d8f93e3edfe5a918c874702f78faac300209a4d5bf38352b2c1bdc07a766d"}, {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1b96af8c582b94d381a1c1f51ffaedeb77c821c690ea5f01da3d70a487dd0a9b"}, {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c03eff4a41bd4e38415cbed054bbaff4a075b093e2394b6915dca34a40d1e38b"}, {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:50cf5e7ee9b98f22bdecbabf3800ae78ddcc26e4a435515fc72d97903e8488e0"}, {file = "frozenlist-1.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1e76bfbc72353269c44e0bc2cfe171900fbf7f722ad74c9a7b638052afe6a00c"}, {file = "frozenlist-1.5.0-cp39-cp39-win32.whl", hash = "sha256:666534d15ba8f0fda3f53969117383d5dc021266b3c1a42c9ec4855e4b58b9d3"}, {file = "frozenlist-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:5c28f4b5dbef8a0d8aad0d4de24d1e9e981728628afaf4ea0792f5d0939372f0"}, {file = "frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3"}, {file = "frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817"}, ] [[package]] name = "identify" version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] license = ["ukkonen"] [[package]] name = "idna" version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" groups = ["main", "dev"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] name = "multidict" version = "6.1.0" description = "multidict implementation" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"}, {file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"}, {file = "multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53"}, {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5"}, {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581"}, {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56"}, {file = "multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429"}, {file = "multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748"}, {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db"}, {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056"}, {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76"}, {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160"}, {file = "multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7"}, {file = "multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0"}, {file = "multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d"}, {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6"}, {file = "multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156"}, {file = "multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb"}, {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b"}, {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72"}, {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304"}, {file = "multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351"}, {file = "multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb"}, {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3"}, {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399"}, {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423"}, {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3"}, {file = "multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753"}, {file = "multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80"}, {file = "multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926"}, {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa"}, {file = "multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436"}, {file = "multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761"}, {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e"}, {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef"}, {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95"}, {file = "multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925"}, {file = "multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966"}, {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305"}, {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2"}, {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2"}, {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6"}, {file = "multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3"}, {file = "multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133"}, {file = "multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1"}, {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008"}, {file = "multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f"}, {file = "multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28"}, {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b"}, {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c"}, {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3"}, {file = "multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44"}, {file = "multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2"}, {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3"}, {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa"}, {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa"}, {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4"}, {file = "multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6"}, {file = "multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81"}, {file = "multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774"}, {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:db7457bac39421addd0c8449933ac32d8042aae84a14911a757ae6ca3eef1392"}, {file = "multidict-6.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d094ddec350a2fb899fec68d8353c78233debde9b7d8b4beeafa70825f1c281a"}, {file = "multidict-6.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5845c1fd4866bb5dd3125d89b90e57ed3138241540897de748cdf19de8a2fca2"}, {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9079dfc6a70abe341f521f78405b8949f96db48da98aeb43f9907f342f627cdc"}, {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3914f5aaa0f36d5d60e8ece6a308ee1c9784cd75ec8151062614657a114c4478"}, {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08be4f460903e5a9d0f76818db3250f12e9c344e79314d1d570fc69d7f4eae4"}, {file = "multidict-6.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d093be959277cb7dee84b801eb1af388b6ad3ca6a6b6bf1ed7585895789d027d"}, {file = "multidict-6.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3702ea6872c5a2a4eeefa6ffd36b042e9773f05b1f37ae3ef7264b1163c2dcf6"}, {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2090f6a85cafc5b2db085124d752757c9d251548cedabe9bd31afe6363e0aff2"}, {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:f67f217af4b1ff66c68a87318012de788dd95fcfeb24cc889011f4e1c7454dfd"}, {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:189f652a87e876098bbc67b4da1049afb5f5dfbaa310dd67c594b01c10388db6"}, {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6bb5992037f7a9eff7991ebe4273ea7f51f1c1c511e6a2ce511d0e7bdb754492"}, {file = "multidict-6.1.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f4c2b9e770c4e393876e35a7046879d195cd123b4f116d299d442b335bcd"}, {file = "multidict-6.1.0-cp38-cp38-win32.whl", hash = "sha256:e27bbb6d14416713a8bd7aaa1313c0fc8d44ee48d74497a0ff4c3a1b6ccb5167"}, {file = "multidict-6.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:22f3105d4fb15c8f57ff3959a58fcab6ce36814486500cd7485651230ad4d4ef"}, {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:4e18b656c5e844539d506a0a06432274d7bd52a7487e6828c63a63d69185626c"}, {file = "multidict-6.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a185f876e69897a6f3325c3f19f26a297fa058c5e456bfcff8015e9a27e83ae1"}, {file = "multidict-6.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ab7c4ceb38d91570a650dba194e1ca87c2b543488fe9309b4212694174fd539c"}, {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e617fb6b0b6953fffd762669610c1c4ffd05632c138d61ac7e14ad187870669c"}, {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16e5f4bf4e603eb1fdd5d8180f1a25f30056f22e55ce51fb3d6ad4ab29f7d96f"}, {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c035da3f544b1882bac24115f3e2e8760f10a0107614fc9839fd232200b875"}, {file = "multidict-6.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:957cf8e4b6e123a9eea554fa7ebc85674674b713551de587eb318a2df3e00255"}, {file = "multidict-6.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:483a6aea59cb89904e1ceabd2b47368b5600fb7de78a6e4a2c2987b2d256cf30"}, {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:87701f25a2352e5bf7454caa64757642734da9f6b11384c1f9d1a8e699758057"}, {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:682b987361e5fd7a139ed565e30d81fd81e9629acc7d925a205366877d8c8657"}, {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2186a7df133a9c895dea3331ddc5ddad42cdd0d1ea2f0a51e5d161e4762f28"}, {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:9f636b730f7e8cb19feb87094949ba54ee5357440b9658b2a32a5ce4bce53972"}, {file = "multidict-6.1.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:73eae06aa53af2ea5270cc066dcaf02cc60d2994bbb2c4ef5764949257d10f43"}, {file = "multidict-6.1.0-cp39-cp39-win32.whl", hash = "sha256:1ca0083e80e791cffc6efce7660ad24af66c8d4079d2a750b29001b53ff59ada"}, {file = "multidict-6.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa466da5b15ccea564bdab9c89175c762bc12825f4659c11227f515cee76fa4a"}, {file = "multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506"}, {file = "multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a"}, ] [[package]] name = "mypy" version = "1.14.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "mypy-1.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52686e37cf13d559f668aa398dd7ddf1f92c5d613e4f8cb262be2fb4fedb0fcb"}, {file = "mypy-1.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1fb545ca340537d4b45d3eecdb3def05e913299ca72c290326be19b3804b39c0"}, {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90716d8b2d1f4cd503309788e51366f07c56635a3309b0f6a32547eaaa36a64d"}, {file = "mypy-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ae753f5c9fef278bcf12e1a564351764f2a6da579d4a81347e1d5a15819997b"}, {file = "mypy-1.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e0fe0f5feaafcb04505bcf439e991c6d8f1bf8b15f12b05feeed96e9e7bf1427"}, {file = "mypy-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:7d54bd85b925e501c555a3227f3ec0cfc54ee8b6930bd6141ec872d1c572f81f"}, {file = "mypy-1.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f995e511de847791c3b11ed90084a7a0aafdc074ab88c5a9711622fe4751138c"}, {file = "mypy-1.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d64169ec3b8461311f8ce2fd2eb5d33e2d0f2c7b49116259c51d0d96edee48d1"}, {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba24549de7b89b6381b91fbc068d798192b1b5201987070319889e93038967a8"}, {file = "mypy-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:183cf0a45457d28ff9d758730cd0210419ac27d4d3f285beda038c9083363b1f"}, {file = "mypy-1.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f2a0ecc86378f45347f586e4163d1769dd81c5a223d577fe351f26b179e148b1"}, {file = "mypy-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:ad3301ebebec9e8ee7135d8e3109ca76c23752bac1e717bc84cd3836b4bf3eae"}, {file = "mypy-1.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:30ff5ef8519bbc2e18b3b54521ec319513a26f1bba19a7582e7b1f58a6e69f14"}, {file = "mypy-1.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cb9f255c18052343c70234907e2e532bc7e55a62565d64536dbc7706a20b78b9"}, {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b4e3413e0bddea671012b063e27591b953d653209e7a4fa5e48759cda77ca11"}, {file = "mypy-1.14.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:553c293b1fbdebb6c3c4030589dab9fafb6dfa768995a453d8a5d3b23784af2e"}, {file = "mypy-1.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fad79bfe3b65fe6a1efaed97b445c3d37f7be9fdc348bdb2d7cac75579607c89"}, {file = "mypy-1.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:8fa2220e54d2946e94ab6dbb3ba0a992795bd68b16dc852db33028df2b00191b"}, {file = "mypy-1.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:92c3ed5afb06c3a8e188cb5da4984cab9ec9a77ba956ee419c68a388b4595255"}, {file = "mypy-1.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:dbec574648b3e25f43d23577309b16534431db4ddc09fda50841f1e34e64ed34"}, {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c6d94b16d62eb3e947281aa7347d78236688e21081f11de976376cf010eb31a"}, {file = "mypy-1.14.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4b19b03fdf54f3c5b2fa474c56b4c13c9dbfb9a2db4370ede7ec11a2c5927d9"}, {file = "mypy-1.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0c911fde686394753fff899c409fd4e16e9b294c24bfd5e1ea4675deae1ac6fd"}, {file = "mypy-1.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8b21525cb51671219f5307be85f7e646a153e5acc656e5cebf64bfa076c50107"}, {file = "mypy-1.14.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7084fb8f1128c76cd9cf68fe5971b37072598e7c31b2f9f95586b65c741a9d31"}, {file = "mypy-1.14.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8f845a00b4f420f693f870eaee5f3e2692fa84cc8514496114649cfa8fd5e2c6"}, {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:44bf464499f0e3a2d14d58b54674dee25c031703b2ffc35064bd0df2e0fac319"}, {file = "mypy-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c99f27732c0b7dc847adb21c9d47ce57eb48fa33a17bc6d7d5c5e9f9e7ae5bac"}, {file = "mypy-1.14.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:bce23c7377b43602baa0bd22ea3265c49b9ff0b76eb315d6c34721af4cdf1d9b"}, {file = "mypy-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:8edc07eeade7ebc771ff9cf6b211b9a7d93687ff892150cb5692e4f4272b0837"}, {file = "mypy-1.14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3888a1816d69f7ab92092f785a462944b3ca16d7c470d564165fe703b0970c35"}, {file = "mypy-1.14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:46c756a444117c43ee984bd055db99e498bc613a70bbbc120272bd13ca579fbc"}, {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:27fc248022907e72abfd8e22ab1f10e903915ff69961174784a3900a8cba9ad9"}, {file = "mypy-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:499d6a72fb7e5de92218db961f1a66d5f11783f9ae549d214617edab5d4dbdbb"}, {file = "mypy-1.14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57961db9795eb566dc1d1b4e9139ebc4c6b0cb6e7254ecde69d1552bf7613f60"}, {file = "mypy-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:07ba89fdcc9451f2ebb02853deb6aaaa3d2239a236669a63ab3801bbf923ef5c"}, {file = "mypy-1.14.1-py3-none-any.whl", hash = "sha256:b66a60cc4073aeb8ae00057f9c1f64d49e90f918fbcef9a977eb121da8b8f1d1"}, {file = "mypy-1.14.1.tar.gz", hash = "sha256:7ec88144fe9b510e8475ec2f5f251992690fcf89ccb4500b214b4226abcd32d6"}, ] [package.dependencies] mypy_extensions = ">=1.0.0" typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" groups = ["dev"] files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] name = "nodeenv" version = "1.9.1" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] [[package]] name = "packaging" version = "24.1" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "pathspec" version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "platformdirs" version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" version = "4.0.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, ] [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" [[package]] name = "pre-commit-hooks" version = "5.0.0" description = "Some out-of-the-box hooks for pre-commit." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "pre_commit_hooks-5.0.0-py2.py3-none-any.whl", hash = "sha256:8d71cfb582c5c314a5498d94e0104b6567a8b93fb35903ea845c491f4e290a7a"}, {file = "pre_commit_hooks-5.0.0.tar.gz", hash = "sha256:10626959a9eaf602fbfc22bc61b6e75801436f82326bfcee82bb1f2fc4bc646e"}, ] [package.dependencies] "ruamel.yaml" = ">=0.15" [[package]] name = "propcache" version = "0.2.0" description = "Accelerated property cache" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, ] [[package]] name = "pycares" version = "4.4.0" description = "Python interface for c-ares" optional = false python-versions = ">=3.8" groups = ["main"] files = [ {file = "pycares-4.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:24da119850841d16996713d9c3374ca28a21deee056d609fbbed29065d17e1f6"}, {file = "pycares-4.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8f64cb58729689d4d0e78f0bfb4c25ce2f851d0274c0273ac751795c04b8798a"}, {file = "pycares-4.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33e2a1120887e89075f7f814ec144f66a6ce06a54f5722ccefc62fbeda83cff"}, {file = "pycares-4.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c680fef1b502ee680f8f0b95a41af4ec2c234e50e16c0af5bbda31999d3584bd"}, {file = "pycares-4.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fff16b09042ba077f7b8aa5868d1d22456f0002574d0ba43462b10a009331677"}, {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:229a1675eb33bc9afb1fc463e73ee334950ccc485bc83a43f6ae5839fb4d5fa3"}, {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3aebc73e5ad70464f998f77f2da2063aa617cbd8d3e8174dd7c5b4518f967153"}, {file = "pycares-4.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6ef64649eba56448f65e26546d85c860709844d2fc22ef14d324fe0b27f761a9"}, {file = "pycares-4.4.0-cp310-cp310-win32.whl", hash = "sha256:4afc2644423f4eef97857a9fd61be9758ce5e336b4b0bd3d591238bb4b8b03e0"}, {file = "pycares-4.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5ed4e04af4012f875b78219d34434a6d08a67175150ac1b79eb70ab585d4ba8c"}, {file = "pycares-4.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bce8db2fc6f3174bd39b81405210b9b88d7b607d33e56a970c34a0c190da0490"}, {file = "pycares-4.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9a0303428d013ccf5c51de59c83f9127aba6200adb7fd4be57eddb432a1edd2a"}, {file = "pycares-4.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afb91792f1556f97be7f7acb57dc7756d89c5a87bd8b90363a77dbf9ea653817"}, {file = "pycares-4.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b61579cecf1f4d616e5ea31a6e423a16680ab0d3a24a2ffe7bb1d4ee162477ff"}, {file = "pycares-4.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7af06968cbf6851566e806bf3e72825b0e6671832a2cbe840be1d2d65350710"}, {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ceb12974367b0a68a05d52f4162b29f575d241bd53de155efe632bf2c943c7f6"}, {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2eeec144bcf6a7b6f2d74d6e70cbba7886a84dd373c886f06cb137a07de4954c"}, {file = "pycares-4.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e3a6f7cfdfd11eb5493d6d632e582408c8f3b429f295f8799c584c108b28db6f"}, {file = "pycares-4.4.0-cp311-cp311-win32.whl", hash = "sha256:34736a2ffaa9c08ca9c707011a2d7b69074bbf82d645d8138bba771479b2362f"}, {file = "pycares-4.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:eb66c30eb11e877976b7ead13632082a8621df648c408b8e15cdb91a452dd502"}, {file = "pycares-4.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fd644505a8cfd7f6584d33a9066d4e3d47700f050ef1490230c962de5dfb28c6"}, {file = "pycares-4.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52084961262232ec04bd75f5043aed7e5d8d9695e542ff691dfef0110209f2d4"}, {file = "pycares-4.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0c5368206057884cde18602580083aeaad9b860e2eac14fd253543158ce1e93"}, {file = "pycares-4.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:112a4979c695b1c86f6782163d7dec58d57a3b9510536dcf4826550f9053dd9a"}, {file = "pycares-4.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d186dafccdaa3409194c0f94db93c1a5d191145a275f19da6591f9499b8e7b8"}, {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:64965dc19c578a683ea73487a215a8897276224e004d50eeb21f0bc7a0b63c88"}, {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ed2a38e34bec6f2586435f6ff0bc5fe11d14bebd7ed492cf739a424e81681540"}, {file = "pycares-4.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:94d6962db81541eb0396d2f0dfcbb18cdb8c8b251d165efc2d974ae652c547d4"}, {file = "pycares-4.4.0-cp312-cp312-win32.whl", hash = "sha256:1168a48a834813aa80f412be2df4abaf630528a58d15c704857448b20b1675c0"}, {file = "pycares-4.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:db24c4e7fea4a052c6e869cbf387dd85d53b9736cfe1ef5d8d568d1ca925e977"}, {file = "pycares-4.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:21a5a0468861ec7df7befa69050f952da13db5427ae41ffe4713bc96291d1d95"}, {file = "pycares-4.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:22c00bf659a9fa44d7b405cf1cd69b68b9d37537899898d8cbe5dffa4016b273"}, {file = "pycares-4.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23aa3993a352491a47fcf17867f61472f32f874df4adcbb486294bd9fbe8abee"}, {file = "pycares-4.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:813d661cbe2e37d87da2d16b7110a6860e93ddb11735c6919c8a3545c7b9c8d8"}, {file = "pycares-4.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77cf5a2fd5583c670de41a7f4a7b46e5cbabe7180d8029f728571f4d2e864084"}, {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3eaa6681c0a3e3f3868c77aca14b7760fed35fdfda2fe587e15c701950e7bc69"}, {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad58e284a658a8a6a84af2e0b62f2f961f303cedfe551854d7bd40c3cbb61912"}, {file = "pycares-4.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bfb89ca9e3d0a9b5332deeb666b2ede9d3469107742158f4aeda5ce032d003f4"}, {file = "pycares-4.4.0-cp38-cp38-win32.whl", hash = "sha256:f36bdc1562142e3695555d2f4ac0cb69af165eddcefa98efc1c79495b533481f"}, {file = "pycares-4.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:902461a92b6a80fd5041a2ec5235680c7cc35e43615639ec2a40e63fca2dfb51"}, {file = "pycares-4.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7bddc6adba8f699728f7fc1c9ce8cef359817ad78e2ed52b9502cb5f8dc7f741"}, {file = "pycares-4.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cb49d5805cd347c404f928c5ae7c35e86ba0c58ffa701dbe905365e77ce7d641"}, {file = "pycares-4.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56cf3349fa3a2e67ed387a7974c11d233734636fe19facfcda261b411af14d80"}, {file = "pycares-4.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bf2eaa83a5987e48fa63302f0fe7ce3275cfda87b34d40fef9ce703fb3ac002"}, {file = "pycares-4.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82bba2ab77eb5addbf9758d514d9bdef3c1bfe7d1649a47bd9a0d55a23ef478b"}, {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c6a8bde63106f162fca736e842a916853cad3c8d9d137e11c9ffa37efa818b02"}, {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5f646eec041db6ffdbcaf3e0756fb92018f7af3266138c756bb09d2b5baadec"}, {file = "pycares-4.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9dc04c54c6ea615210c1b9e803d0e2d2255f87a3d5d119b6482c8f0dfa15b26b"}, {file = "pycares-4.4.0-cp39-cp39-win32.whl", hash = "sha256:97892cced5794d721fb4ff8765764aa4ea48fe8b2c3820677505b96b83d4ef47"}, {file = "pycares-4.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:917f08f0b5d9324e9a34211e68d27447c552b50ab967044776bbab7e42a553a2"}, {file = "pycares-4.4.0.tar.gz", hash = "sha256:f47579d508f2f56eddd16ce72045782ad3b1b3b678098699e2b6a1b30733e1c2"}, ] [package.dependencies] cffi = ">=1.5.0" [package.extras] idna = ["idna (>=2.1)"] [[package]] name = "pycparser" version = "2.22" description = "C parser in Python" optional = false python-versions = ">=3.8" groups = ["main"] files = [ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] [[package]] name = "pytest" version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} iniconfig = "*" packaging = "*" pluggy = ">=1.5,<2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.25.2" description = "Pytest support for asyncio" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075"}, {file = "pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f"}, ] [package.dependencies] pytest = ">=8.2,<9" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" version = "6.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"}, {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"}, ] [package.dependencies] coverage = {version = ">=7.5", extras = ["toml"]} pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-freezer" version = "0.4.9" description = "Pytest plugin providing a fixture interface for spulec/freezegun" optional = false python-versions = ">=3.6" groups = ["dev"] files = [ {file = "pytest_freezer-0.4.9-py3-none-any.whl", hash = "sha256:8b6c50523b7d4aec4590b52bfa5ff766d772ce506e2bf4846c88041ea9ccae59"}, {file = "pytest_freezer-0.4.9.tar.gz", hash = "sha256:21bf16bc9cc46bf98f94382c4b5c3c389be7056ff0be33029111ae11b3f1c82a"}, ] [package.dependencies] freezegun = ">=1.1" pytest = ">=3.6" [[package]] name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, ] [package.dependencies] six = ">=1.5" [[package]] name = "pyyaml" version = "6.0.2" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "ruamel-yaml" version = "0.18.6" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, ] [package.dependencies] "ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} [package.extras] docs = ["mercurial (>5.7)", "ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] [[package]] name = "ruamel-yaml-clib" version = "0.2.12" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" optional = false python-versions = ">=3.9" groups = ["dev"] markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\"" files = [ {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:11f891336688faf5156a36293a9c362bdc7c88f03a8a027c2c1d8e0bcde998e5"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:a606ef75a60ecf3d924613892cc603b154178ee25abb3055db5062da811fd969"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd5415dded15c3822597455bc02bcd66e81ef8b7a48cb71a33628fc9fdde39df"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f66efbc1caa63c088dead1c4170d148eabc9b80d95fb75b6c92ac0aad2437d76"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:22353049ba4181685023b25b5b51a574bce33e7f51c759371a7422dcae5402a6"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:932205970b9f9991b34f55136be327501903f7c66830e9760a8ffb15b07f05cd"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win32.whl", hash = "sha256:3eac5a91891ceb88138c113f9db04f3cebdae277f5d44eaa3651a4f573e6a5da"}, {file = "ruamel.yaml.clib-0.2.12-cp310-cp310-win_amd64.whl", hash = "sha256:ab007f2f5a87bd08ab1499bdf96f3d5c6ad4dcfa364884cb4549aa0154b13a28"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:4a6679521a58256a90b0d89e03992c15144c5f3858f40d7c18886023d7943db6"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d84318609196d6bd6da0edfa25cedfbabd8dbde5140a0a23af29ad4b8f91fb1e"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb43a269eb827806502c7c8efb7ae7e9e9d0573257a46e8e952f4d4caba4f31e"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:811ea1594b8a0fb466172c384267a4e5e367298af6b228931f273b111f17ef52"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cf12567a7b565cbf65d438dec6cfbe2917d3c1bdddfce84a9930b7d35ea59642"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7dd5adc8b930b12c8fc5b99e2d535a09889941aa0d0bd06f4749e9a9397c71d2"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win32.whl", hash = "sha256:bd0a08f0bab19093c54e18a14a10b4322e1eacc5217056f3c063bd2f59853ce4"}, {file = "ruamel.yaml.clib-0.2.12-cp311-cp311-win_amd64.whl", hash = "sha256:a274fb2cb086c7a3dea4322ec27f4cb5cc4b6298adb583ab0e211a4682f241eb"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:20b0f8dc160ba83b6dcc0e256846e1a02d044e13f7ea74a3d1d56ede4e48c632"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:943f32bc9dedb3abff9879edc134901df92cfce2c3d5c9348f172f62eb2d771d"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95c3829bb364fdb8e0332c9931ecf57d9be3519241323c5274bd82f709cebc0c"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:749c16fcc4a2b09f28843cda5a193e0283e47454b63ec4b81eaa2242f50e4ccd"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bf165fef1f223beae7333275156ab2022cffe255dcc51c27f066b4370da81e31"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:32621c177bbf782ca5a18ba4d7af0f1082a3f6e517ac2a18b3974d4edf349680"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win32.whl", hash = "sha256:e8c4ebfcfd57177b572e2040777b8abc537cdef58a2120e830124946aa9b42c5"}, {file = "ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:4c8c5d82f50bb53986a5e02d1b3092b03622c02c2eb78e29bec33fd9593bae1a"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux2014_aarch64.whl", hash = "sha256:e7e3736715fbf53e9be2a79eb4db68e4ed857017344d697e8b9749444ae57475"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b7e75b4965e1d4690e93021adfcecccbca7d61c7bddd8e22406ef2ff20d74ef"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96777d473c05ee3e5e3c3e999f5d23c6f4ec5b0c38c098b3a5229085f74236c6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:3bc2a80e6420ca8b7d3590791e2dfc709c88ab9152c00eeb511c9875ce5778bf"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e188d2699864c11c36cdfdada94d781fd5d6b0071cd9c427bceb08ad3d7c70e1"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win32.whl", hash = "sha256:6442cb36270b3afb1b4951f060eccca1ce49f3d087ca1ca4563a6eb479cb3de6"}, {file = "ruamel.yaml.clib-0.2.12-cp313-cp313-win_amd64.whl", hash = "sha256:e5b8daf27af0b90da7bb903a876477a9e6d7270be6146906b276605997c7e9a3"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:fc4b630cd3fa2cf7fce38afa91d7cfe844a9f75d7f0f36393fa98815e911d987"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bc5f1e1c28e966d61d2519f2a3d451ba989f9ea0f2307de7bc45baa526de9e45"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a0e060aace4c24dcaf71023bbd7d42674e3b230f7e7b97317baf1e953e5b519"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2f1c3765db32be59d18ab3953f43ab62a761327aafc1594a2a1fbe038b8b8a7"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d85252669dc32f98ebcd5d36768f5d4faeaeaa2d655ac0473be490ecdae3c285"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e143ada795c341b56de9418c58d028989093ee611aa27ffb9b7f609c00d813ed"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win32.whl", hash = "sha256:beffaed67936fbbeffd10966a4eb53c402fafd3d6833770516bf7314bc6ffa12"}, {file = "ruamel.yaml.clib-0.2.12-cp39-cp39-win_amd64.whl", hash = "sha256:040ae85536960525ea62868b642bdb0c2cc6021c9f9d507810c0c604e66f5a7b"}, {file = "ruamel.yaml.clib-0.2.12.tar.gz", hash = "sha256:6c8fbb13ec503f99a91901ab46e0b07ae7941cd527393187039aec586fdfd36f"}, ] [[package]] name = "ruff" version = "0.9.1" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "ruff-0.9.1-py3-none-linux_armv6l.whl", hash = "sha256:84330dda7abcc270e6055551aca93fdde1b0685fc4fd358f26410f9349cf1743"}, {file = "ruff-0.9.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3cae39ba5d137054b0e5b472aee3b78a7c884e61591b100aeb544bcd1fc38d4f"}, {file = "ruff-0.9.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:50c647ff96f4ba288db0ad87048257753733763b409b2faf2ea78b45c8bb7fcb"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0c8b149e9c7353cace7d698e1656ffcf1e36e50f8ea3b5d5f7f87ff9986a7ca"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:beb3298604540c884d8b282fe7625651378e1986c25df51dec5b2f60cafc31ce"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39d0174ccc45c439093971cc06ed3ac4dc545f5e8bdacf9f067adf879544d969"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69572926c0f0c9912288915214ca9b2809525ea263603370b9e00bed2ba56dbd"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:937267afce0c9170d6d29f01fcd1f4378172dec6760a9f4dface48cdabf9610a"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:186c2313de946f2c22bdf5954b8dd083e124bcfb685732cfb0beae0c47233d9b"}, {file = "ruff-0.9.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f94942a3bb767675d9a051867c036655fe9f6c8a491539156a6f7e6b5f31831"}, {file = "ruff-0.9.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:728d791b769cc28c05f12c280f99e8896932e9833fef1dd8756a6af2261fd1ab"}, {file = "ruff-0.9.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:2f312c86fb40c5c02b44a29a750ee3b21002bd813b5233facdaf63a51d9a85e1"}, {file = "ruff-0.9.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ae017c3a29bee341ba584f3823f805abbe5fe9cd97f87ed07ecbf533c4c88366"}, {file = "ruff-0.9.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5dc40a378a0e21b4cfe2b8a0f1812a6572fc7b230ef12cd9fac9161aa91d807f"}, {file = "ruff-0.9.1-py3-none-win32.whl", hash = "sha256:46ebf5cc106cf7e7378ca3c28ce4293b61b449cd121b98699be727d40b79ba72"}, {file = "ruff-0.9.1-py3-none-win_amd64.whl", hash = "sha256:342a824b46ddbcdddd3abfbb332fa7fcaac5488bf18073e841236aadf4ad5c19"}, {file = "ruff-0.9.1-py3-none-win_arm64.whl", hash = "sha256:1cd76c7f9c679e6e8f2af8f778367dca82b95009bc7b1a85a47f1521ae524fa7"}, {file = "ruff-0.9.1.tar.gz", hash = "sha256:fd2b25ecaf907d6458fa842675382c8597b3c746a2dde6717fe3415425df0c17"}, ] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" groups = ["dev"] files = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] [[package]] name = "syrupy" version = "4.8.0" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.8.1" groups = ["dev"] files = [ {file = "syrupy-4.8.0-py3-none-any.whl", hash = "sha256:544f4ec6306f4b1c460fdab48fd60b2c7fe54a6c0a8243aeea15f9ad9c638c3f"}, {file = "syrupy-4.8.0.tar.gz", hash = "sha256:648f0e9303aaa8387c8365d7314784c09a6bab0a407455c6a01d6a4f5c6a8ede"}, ] [package.dependencies] pytest = ">=7.0.0,<9.0.0" [[package]] name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "virtualenv" version = "20.27.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "yamllint" version = "1.35.1" description = "A linter for YAML files." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "yamllint-1.35.1-py3-none-any.whl", hash = "sha256:2e16e504bb129ff515b37823b472750b36b6de07963bd74b307341ef5ad8bdc3"}, {file = "yamllint-1.35.1.tar.gz", hash = "sha256:7a003809f88324fd2c877734f2d575ee7881dd9043360657cc8049c809eba6cd"}, ] [package.dependencies] pathspec = ">=0.5.3" pyyaml = "*" [package.extras] dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [[package]] name = "yarl" version = "1.18.3" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" propcache = ">=0.2.0" [metadata] lock-version = "2.1" python-versions = "^3.11" content-hash = "d86aa754311be8e8a8e54272c9b33c86360fbed75598ad5bd78f1c42b1833c36" forecast_solar-4.1.0/pyproject.toml000066400000000000000000000071401477371027100174510ustar00rootroot00000000000000[project] name = "forecast-solar" version = "0.0.0" description = "Asynchronous Python client for getting forecast solar information" authors = [{ name="Klaas Schoute", email=""}] maintainers = [{name="Klaas Schoute", email=""}] license = "MIT" requires-python = ">=3.11" readme = "README.md" keywords = ["forecast", "solar", "power", "energy", "api", "async", "client"] classifiers = [ "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", ] dynamic = ["dependencies"] packages = [ { include = "forecast_solar", from = "src" }, ] [tool.poetry.dependencies] aiohttp = ">=3.0.0" aiodns = ">=3.0.0" python = "^3.11" yarl = ">=1.6.0" [project.urls] homepage = "https://github.com/home-assistant-libs/forecast_solar" repository = "https://github.com/home-assistant-libs/forecast_solar" documentation = "https://github.com/home-assistant-libs/forecast_solar" "Bug Tracker" = "https://github.com/home-assistant-libs/forecast_solar/issues" Changelog = "https://github.com/home-assistant-libs/forecast_solar/releases" [tool.poetry.group.dev.dependencies] aresponses = "3.0.0" covdefaults = "2.3.0" mypy = "1.14.1" pre-commit = "4.0.1" pre-commit-hooks = "5.0.0" pytest = "8.3.4" pytest-asyncio = "0.25.2" pytest-cov = "6.0.0" pytest-freezer = "0.4.9" ruff = "0.9.1" syrupy = "4.8.0" yamllint = "1.35.1" [tool.coverage.run] plugins = ["covdefaults"] source = ["forecast_solar"] [tool.coverage.report] fail_under = 90 show_missing = true [tool.mypy] # Specify the target platform details in config, so your developers are # free to run mypy on Windows, Linux, or macOS and get consistent # results. platform = "linux" python_version = "3.11" # flake8-mypy expects the two following for sensible formatting show_column_numbers = true # show error messages from unrelated files follow_imports = "normal" # suppress errors about unsatisfied imports ignore_missing_imports = true # be strict check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_subclassing_any = true disallow_untyped_calls = true disallow_untyped_decorators = true disallow_untyped_defs = true no_implicit_optional = true no_implicit_reexport = true strict_optional = true warn_incomplete_stub = true warn_no_return = true warn_redundant_casts = true warn_return_any = true warn_unused_configs = true warn_unused_ignores = true [tool.pytest.ini_options] addopts = "--cov" asyncio_mode = "auto" [tool.ruff] target-version = "py311" lint.select = ["ALL"] lint.ignore = [ "ANN401", # Opinioated warning on disallowing dynamically typed expressions "D203", # Conflicts with other rules "D213", # Conflicts with other rules "D417", # False positives in some occasions "EM101", # Allow exceptions with string literials "PLR2004", # Just annoying, not really useful "SLOT000", # Has a bug with enums: https://github.com/astral-sh/ruff/issues/5748 "TRY003", # Allow long message outside exception class # Conflicts with the Ruff formatter "COM812", ] [tool.ruff.lint.flake8-pytest-style] mark-parentheses = false fixture-parentheses = false [tool.ruff.lint.isort] known-first-party = ["forecast_solar"] [tool.ruff.lint.mccabe] max-complexity = 25 [build-system] build-backend = "poetry.core.masonry.api" requires = ["poetry-core>=1.0.0"] forecast_solar-4.1.0/src/000077500000000000000000000000001477371027100153225ustar00rootroot00000000000000forecast_solar-4.1.0/src/forecast_solar/000077500000000000000000000000001477371027100203305ustar00rootroot00000000000000forecast_solar-4.1.0/src/forecast_solar/__init__.py000066400000000000000000000012311477371027100224360ustar00rootroot00000000000000"""Asynchronous Python client for the Forecast.Solar API.""" from .exceptions import ( ForecastSolarAuthenticationError, ForecastSolarConfigError, ForecastSolarConnectionError, ForecastSolarError, ForecastSolarRatelimitError, ForecastSolarRequestError, ) from .forecast_solar import ForecastSolar from .models import AccountType, Estimate, Ratelimit __all__ = [ "AccountType", "Estimate", "ForecastSolar", "ForecastSolarAuthenticationError", "ForecastSolarConfigError", "ForecastSolarConnectionError", "ForecastSolarError", "ForecastSolarRatelimitError", "ForecastSolarRequestError", "Ratelimit", ] forecast_solar-4.1.0/src/forecast_solar/exceptions.py000066400000000000000000000033261477371027100230670ustar00rootroot00000000000000"""Exceptions for Forecast.Solar.""" from datetime import datetime from typing import Any class ForecastSolarError(Exception): """Generic Forecast.Solar exception.""" class ForecastSolarConnectionError(ForecastSolarError): """Forecast.Solar API connection exception.""" class ForecastSolarConfigError(ForecastSolarError): """Forecast.Solar API configuration exception.""" def __init__(self, data: dict[str, str]) -> None: """Init a solar config error.""" super().__init__(f"{data['text']} (error 422)") class ForecastSolarAuthenticationError(ForecastSolarError): """Forecast.Solar API authentication exception.""" def __init__(self, data: dict[str, str]) -> None: """Init a solar auth error. https://doc.forecast.solar/doku.php?id=api#invalid_request """ # seems that code is missing in response in some endpoints (i.e /info) code = data.get("code") super().__init__(f"{data['text']} (error {code})") self.code = code class ForecastSolarRequestError(ForecastSolarError): """Forecast.Solar wrong request input variables.""" def __init__(self, data: dict[str, str]) -> None: """Init a solar request error. https://doc.forecast.solar/doku.php?id=api#invalid_request """ super().__init__(f"{data['text']} (error {data['code']})") self.code = data["code"] class ForecastSolarRatelimitError(ForecastSolarRequestError): """Forecast.Solar maximum number of requests reached exception.""" def __init__(self, data: dict[str, Any]) -> None: """Init a rate limit error.""" super().__init__(data) self.reset_at = datetime.fromisoformat(data["ratelimit"]["retry-at"]) forecast_solar-4.1.0/src/forecast_solar/forecast_solar.py000066400000000000000000000163151477371027100237160ustar00rootroot00000000000000"""Asynchronous Python client for the Forecast.Solar API.""" from __future__ import annotations from dataclasses import dataclass from typing import Any, Self from aiodns import DNSResolver from aiodns.error import DNSError from aiohttp import ClientSession from yarl import URL from .exceptions import ( ForecastSolarAuthenticationError, ForecastSolarConfigError, ForecastSolarConnectionError, ForecastSolarError, ForecastSolarRatelimitError, ForecastSolarRequestError, ) from .models import Estimate, Ratelimit @dataclass class ForecastSolar: """Main class for handling connections with the Forecast.Solar API.""" azimuth: float declination: float kwp: float latitude: float longitude: float api_key: str | None = None damping: float = 0 damping_morning: float | None = None damping_evening: float | None = None horizon: str | None = None session: ClientSession | None = None ratelimit: Ratelimit | None = None inverter: float | None = None _close_session: bool = False async def _request( self, uri: str, *, rate_limit: bool = True, authenticate: bool = True, params: dict[str, Any] | None = None, ) -> Any: """Handle a request to the Forecast.Solar API. A generic method for sending/handling HTTP requests done against the Forecast.Solar API. Args: ---- uri: Request URI, for example, 'estimate' rate_limit: Parse rate limit from response. Set to False for endpoints that are missing rate limiting headers in response. authenticate: Prefix request with api_key. Set to False for endpoints that do not provide authentication. Returns: ------- A Python dictionary (JSON decoded) with the response from the Forecast.Solar API. Raises: ------ ForecastSolarAuthenticationError: If the API key is invalid. ForecastSolarConnectionError: An error occurred while communicating with the Forecast.Solar API. ForecastSolarError: Received an unexpected response from the Forecast.Solar API. ForecastSolarRequestError: There is something wrong with the variables used in the request. ForecastSolarRatelimitError: The number of requests has exceeded the rate limit of the Forecast.Solar API. """ # Forecast.Solar is currently experiencing IPv6 issues. # However, their DNS does return an non-working IPv6 address. # This ensures we use the IPv4 address. dns = DNSResolver() try: result = await dns.query("api.forecast.solar", "A") except DNSError as err: raise ForecastSolarConnectionError( "Error while resolving Forecast.Solar API address" ) from err if not result: raise ForecastSolarConnectionError( "Could not resolve Forecast.Solar API address" ) # Connect as normal url = URL.build(scheme="https", host=result[0].host) # Add API key if one is provided if authenticate and self.api_key is not None: url = url.with_path(f"{self.api_key}/") url = url.join(URL(uri)) if self.session is None: self.session = ClientSession() self._close_session = True response = await self.session.request( "GET", url, params=params, headers={"Host": "api.forecast.solar"}, ssl=False, ) if response.status in (502, 503): raise ForecastSolarConnectionError("The Forecast.Solar API is unreachable") if response.status == 400: data = await response.json() raise ForecastSolarRequestError(data["message"]) if response.status in (401, 403): data = await response.json() raise ForecastSolarAuthenticationError(data["message"]) if response.status == 422: data = await response.json() raise ForecastSolarConfigError(data["message"]) if response.status == 429: data = await response.json() raise ForecastSolarRatelimitError(data["message"]) if rate_limit and response.status == 200: self.ratelimit = Ratelimit.from_response(response) response.raise_for_status() content_type = response.headers.get("Content-Type", "") if "application/json" not in content_type: text = await response.text() raise ForecastSolarError( "Unexpected response from the Forecast.Solar API", {"Content-Type": content_type, "response": text}, ) return await response.json() async def validate_plane(self) -> bool: """Validate plane by calling the Forecast.Solar API. Returns ------- True, if plane is valid. """ await self._request( f"check/{self.latitude}/{self.longitude}" f"/{self.declination}/{self.azimuth}/{self.kwp}", rate_limit=False, authenticate=False, ) return True async def validate_api_key(self) -> bool: """Validate api key by calling the Forecast.Solar API. Returns ------- True, if api key is valid """ await self._request("info", rate_limit=False) return True async def estimate(self, actual: float = 0) -> Estimate: """Get solar production estimations from the Forecast.Solar API. Args: ---- actual: The production for the day in kWh so far. Used to improve the estimation for the current day if an API key is provided. Returns: ------- A Estimate object, with a estimated production forecast. """ params = {"time": "utc", "damping": str(self.damping)} if self.inverter is not None: params["inverter"] = str(self.inverter) if self.horizon is not None: params["horizon"] = str(self.horizon) if self.damping_morning is not None and self.damping_evening is not None: params["damping_morning"] = str(self.damping_morning) params["damping_evening"] = str(self.damping_evening) if self.api_key is not None: params["actual"] = str(actual) data = await self._request( f"estimate/{self.latitude}/{self.longitude}" f"/{self.declination}/{self.azimuth}/{self.kwp}", params=params, ) return Estimate.from_dict(data) async def close(self) -> None: """Close open client session.""" if self.session and self._close_session: await self.session.close() async def __aenter__(self) -> Self: """Async enter. Returns ------- The ForecastSolar object. """ return self async def __aexit__(self, *_exc_info: object) -> None: """Async exit. Args: ---- _exc_info: Exec type. """ await self.close() forecast_solar-4.1.0/src/forecast_solar/models.py000066400000000000000000000157001477371027100221700ustar00rootroot00000000000000"""Data models for the Forecast.Solar API.""" from __future__ import annotations from dataclasses import dataclass from datetime import date, datetime, timedelta from enum import Enum from typing import TYPE_CHECKING, Any from zoneinfo import ZoneInfo if TYPE_CHECKING: from aiohttp import ClientResponse def _timed_value(at: datetime, data: dict[datetime, int]) -> int | None: """Return the value for a specific time.""" value = None for timestamp, cur_value in data.items(): if timestamp > at: return value value = cur_value return None def _interval_value_sum( interval_begin: datetime, interval_end: datetime, data: dict[datetime, int] ) -> int: """Return the sum of values in interval.""" total = 0 for timestamp, wh in data.items(): # Skip all until this hour if timestamp < interval_begin: continue if timestamp >= interval_end: break total += wh return total class AccountType(str, Enum): """Enumeration representing the Forecast.Solar account type.""" PUBLIC = "public" PERSONAL = "personal" PROFESSIONAL = "professional" @dataclass class Estimate: """Object holding estimate forecast results from Forecast.Solar. Attributes ---------- watts: Estimated solar power output per time period. wh_period: Estimated solar energy production differences per hour. wh_days: Estimated solar energy production per day. """ watts: dict[datetime, int] wh_period: dict[datetime, int] wh_days: dict[datetime, int] api_rate_limit: int api_timezone: str @property def timezone(self) -> str: """Return API timezone information.""" return self.api_timezone @property def account_type(self) -> AccountType: """Return API account_type information.""" if self.api_rate_limit == 60: return AccountType.PERSONAL if self.api_rate_limit == 5: return AccountType.PROFESSIONAL return AccountType.PUBLIC @property def energy_production_today(self) -> int: """Return estimated energy produced today.""" return self.day_production(self.now().date()) @property def energy_production_tomorrow(self) -> int: """Return estimated energy produced today.""" return self.day_production(self.now().date() + timedelta(days=1)) @property def energy_production_today_remaining(self) -> int: """Return estimated energy produced in rest of today.""" return _interval_value_sum( self.now(), self.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1), self.wh_period, ) @property def power_production_now(self) -> int: """Return estimated power production right now.""" return self.power_production_at_time(self.now()) @property def power_highest_peak_time_today(self) -> datetime: """Return datetime with highest power production moment today.""" return self.peak_production_time(self.now().date()) @property def power_highest_peak_time_tomorrow(self) -> datetime: """Return datetime with highest power production moment tomorrow.""" return self.peak_production_time(self.now().date() + timedelta(days=1)) @property def energy_current_hour(self) -> int: """Return the estimated energy production for the current hour.""" return _interval_value_sum( self.now().replace(minute=0, second=0, microsecond=0), self.now().replace(minute=0, second=0, microsecond=0) + timedelta(hours=1), self.wh_period, ) def day_production(self, specific_date: date) -> int: """Return the day production.""" for timestamp, production in self.wh_days.items(): if timestamp.date() == specific_date: return production return 0 def now(self) -> datetime: """Return the current timestamp in the API timezone.""" return datetime.now(tz=ZoneInfo(self.api_timezone)) def peak_production_time(self, specific_date: date) -> datetime: """Return the peak time on a specific date.""" value = max( (watt for date, watt in self.watts.items() if date.date() == specific_date), default=None, ) for timestamp, watt in self.watts.items(): if watt == value: return timestamp raise RuntimeError("No peak production time found") def power_production_at_time(self, time: datetime) -> int: """Return estimated power production at a specific time.""" return _timed_value(time, self.watts) or 0 def sum_energy_production(self, period_hours: int) -> int: """Return the sum of the energy production.""" now = self.now().replace(minute=59, second=59, microsecond=999) until = now + timedelta(hours=period_hours) return _interval_value_sum(now, until, self.wh_period) @classmethod def from_dict(cls: type[Estimate], data: dict[str, Any]) -> Estimate: """Return a Estimate object from a Forecast.Solar API response. Converts a dictionary, obtained from the Forecast.Solar API into a Estimate object. Args: ---- data: The estimate response from the Forecast.Solar API. Returns: ------- An Estimate object. """ return cls( watts={ datetime.fromisoformat(d): w for d, w in data["result"]["watts"].items() }, wh_period={ datetime.fromisoformat(d): e for d, e in data["result"]["watt_hours_period"].items() }, wh_days={ datetime.fromisoformat(d): e for d, e in data["result"]["watt_hours_day"].items() }, api_rate_limit=data["message"]["ratelimit"]["limit"], api_timezone=data["message"]["info"]["timezone"], ) @dataclass class Ratelimit: """Information about the current rate limit.""" call_limit: int remaining_calls: int period: int retry_at: datetime | None @classmethod def from_response(cls: type[Ratelimit], response: ClientResponse) -> Ratelimit: """Initialize rate limit object from response.""" # The documented headers do not match the returned headers # https://doc.forecast.solar/doku.php?id=api#headers limit = int(response.headers["X-Ratelimit-Limit"]) period = int(response.headers["X-Ratelimit-Period"]) # Remaining is not there if we exceeded limit remaining = int(response.headers.get("X-Ratelimit-Remaining", 0)) if "X-Ratelimit-Retry-At" in response.headers: retry_at = datetime.fromisoformat(response.headers["X-Ratelimit-Retry-At"]) else: retry_at = None return cls(limit, remaining, period, retry_at) forecast_solar-4.1.0/src/forecast_solar/py.typed000066400000000000000000000000001477371027100220150ustar00rootroot00000000000000forecast_solar-4.1.0/tests/000077500000000000000000000000001477371027100156755ustar00rootroot00000000000000forecast_solar-4.1.0/tests/__init__.py000066400000000000000000000003611477371027100200060ustar00rootroot00000000000000"""Asynchronous Python client for the Forecast.Solar API.""" from pathlib import Path def load_fixtures(filename: str) -> str: """Load a fixture.""" path = Path(__file__).parent / "fixtures" / filename return path.read_text() forecast_solar-4.1.0/tests/__snapshots__/000077500000000000000000000000001477371027100205135ustar00rootroot00000000000000forecast_solar-4.1.0/tests/__snapshots__/test_models.ambr000066400000000000000000001614561477371027100237150ustar00rootroot00000000000000# serializer version: 1 # name: test_estimated_forecast Estimate(watts={FakeDatetime(2024, 4, 26, 6, 20, 17, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 26, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 270, FakeDatetime(2024, 4, 26, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 481, FakeDatetime(2024, 4, 26, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 594, FakeDatetime(2024, 4, 26, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 781, FakeDatetime(2024, 4, 26, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 869, FakeDatetime(2024, 4, 26, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 773, FakeDatetime(2024, 4, 26, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 710, FakeDatetime(2024, 4, 26, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 620, FakeDatetime(2024, 4, 26, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 517, FakeDatetime(2024, 4, 26, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 430, FakeDatetime(2024, 4, 26, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 325, FakeDatetime(2024, 4, 26, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 204, FakeDatetime(2024, 4, 26, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 89, FakeDatetime(2024, 4, 26, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 38, FakeDatetime(2024, 4, 26, 20, 59, 23, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 6, 18, 17, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 194, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 325, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 432, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 514, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 572, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 604, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 602, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 563, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 502, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 422, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 320, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 201, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 87, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 22, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 9, FakeDatetime(2024, 4, 27, 21, 1, 5, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0}, wh_period={FakeDatetime(2024, 4, 26, 6, 20, 17, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 26, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 89, FakeDatetime(2024, 4, 26, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 376, FakeDatetime(2024, 4, 26, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 538, FakeDatetime(2024, 4, 26, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 688, FakeDatetime(2024, 4, 26, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 825, FakeDatetime(2024, 4, 26, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 821, FakeDatetime(2024, 4, 26, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 742, FakeDatetime(2024, 4, 26, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 665, FakeDatetime(2024, 4, 26, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 569, FakeDatetime(2024, 4, 26, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 474, FakeDatetime(2024, 4, 26, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 378, FakeDatetime(2024, 4, 26, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 265, FakeDatetime(2024, 4, 26, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 147, FakeDatetime(2024, 4, 26, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 64, FakeDatetime(2024, 4, 26, 20, 59, 23, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 19, FakeDatetime(2024, 4, 27, 6, 18, 17, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 67, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 260, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 379, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 473, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 543, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 588, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 603, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 583, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 533, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 462, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 371, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 261, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 144, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 55, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 16, FakeDatetime(2024, 4, 27, 21, 1, 5, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0}, wh_days={FakeDatetime(2024, 4, 26, 0, 0): 6660, FakeDatetime(2024, 4, 27, 0, 0): 5338}, api_rate_limit=12, api_timezone='Europe/Amsterdam') # --- # name: test_estimated_forecast_with_subscription Estimate(watts={FakeDatetime(2024, 4, 27, 6, 18, 15, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 47, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 92, FakeDatetime(2024, 4, 27, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 153, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 279, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 342, FakeDatetime(2024, 4, 27, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 402, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 457, FakeDatetime(2024, 4, 27, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 501, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 545, FakeDatetime(2024, 4, 27, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 587, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 616, FakeDatetime(2024, 4, 27, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 625, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 635, FakeDatetime(2024, 4, 27, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 639, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 635, FakeDatetime(2024, 4, 27, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 619, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 600, FakeDatetime(2024, 4, 27, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 570, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 536, FakeDatetime(2024, 4, 27, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 500, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 458, FakeDatetime(2024, 4, 27, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 403, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 344, FakeDatetime(2024, 4, 27, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 281, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 147, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 85, FakeDatetime(2024, 4, 27, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 42, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 18, FakeDatetime(2024, 4, 27, 21, 1, 7, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 16, 16, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 45, FakeDatetime(2024, 4, 28, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 88, FakeDatetime(2024, 4, 28, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 147, FakeDatetime(2024, 4, 28, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 208, FakeDatetime(2024, 4, 28, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 270, FakeDatetime(2024, 4, 28, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 332, FakeDatetime(2024, 4, 28, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 396, FakeDatetime(2024, 4, 28, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 487, FakeDatetime(2024, 4, 28, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 636, FakeDatetime(2024, 4, 28, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 778, FakeDatetime(2024, 4, 28, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 822, FakeDatetime(2024, 4, 28, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 801, FakeDatetime(2024, 4, 28, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 751, FakeDatetime(2024, 4, 28, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 746, FakeDatetime(2024, 4, 28, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 787, FakeDatetime(2024, 4, 28, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 837, FakeDatetime(2024, 4, 28, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 865, FakeDatetime(2024, 4, 28, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 855, FakeDatetime(2024, 4, 28, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 804, FakeDatetime(2024, 4, 28, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 765, FakeDatetime(2024, 4, 28, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 739, FakeDatetime(2024, 4, 28, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 687, FakeDatetime(2024, 4, 28, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 594, FakeDatetime(2024, 4, 28, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 500, FakeDatetime(2024, 4, 28, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 408, FakeDatetime(2024, 4, 28, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 309, FakeDatetime(2024, 4, 28, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 201, FakeDatetime(2024, 4, 28, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 103, FakeDatetime(2024, 4, 28, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 47, FakeDatetime(2024, 4, 28, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 19, FakeDatetime(2024, 4, 28, 21, 2, 49, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 14, 18, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 41, FakeDatetime(2024, 4, 29, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 93, FakeDatetime(2024, 4, 29, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 184, FakeDatetime(2024, 4, 29, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 291, FakeDatetime(2024, 4, 29, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 426, FakeDatetime(2024, 4, 29, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 569, FakeDatetime(2024, 4, 29, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 695, FakeDatetime(2024, 4, 29, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 735, FakeDatetime(2024, 4, 29, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 691, FakeDatetime(2024, 4, 29, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 707, FakeDatetime(2024, 4, 29, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 815, FakeDatetime(2024, 4, 29, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 910, FakeDatetime(2024, 4, 29, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 935, FakeDatetime(2024, 4, 29, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 919, FakeDatetime(2024, 4, 29, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 854, FakeDatetime(2024, 4, 29, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 768, FakeDatetime(2024, 4, 29, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 683, FakeDatetime(2024, 4, 29, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 628, FakeDatetime(2024, 4, 29, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 585, FakeDatetime(2024, 4, 29, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 544, FakeDatetime(2024, 4, 29, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 499, FakeDatetime(2024, 4, 29, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 452, FakeDatetime(2024, 4, 29, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 398, FakeDatetime(2024, 4, 29, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 339, FakeDatetime(2024, 4, 29, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 275, FakeDatetime(2024, 4, 29, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 208, FakeDatetime(2024, 4, 29, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 140, FakeDatetime(2024, 4, 29, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 79, FakeDatetime(2024, 4, 29, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 39, FakeDatetime(2024, 4, 29, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 16, FakeDatetime(2024, 4, 29, 21, 4, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 12, 21, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 41, FakeDatetime(2024, 4, 30, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 82, FakeDatetime(2024, 4, 30, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 141, FakeDatetime(2024, 4, 30, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 203, FakeDatetime(2024, 4, 30, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 266, FakeDatetime(2024, 4, 30, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 329, FakeDatetime(2024, 4, 30, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 390, FakeDatetime(2024, 4, 30, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 445, FakeDatetime(2024, 4, 30, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 490, FakeDatetime(2024, 4, 30, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 531, FakeDatetime(2024, 4, 30, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 566, FakeDatetime(2024, 4, 30, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 594, FakeDatetime(2024, 4, 30, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 611, FakeDatetime(2024, 4, 30, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 623, FakeDatetime(2024, 4, 30, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 625, FakeDatetime(2024, 4, 30, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 623, FakeDatetime(2024, 4, 30, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 615, FakeDatetime(2024, 4, 30, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 599, FakeDatetime(2024, 4, 30, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 570, FakeDatetime(2024, 4, 30, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 535, FakeDatetime(2024, 4, 30, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 496, FakeDatetime(2024, 4, 30, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 452, FakeDatetime(2024, 4, 30, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 401, FakeDatetime(2024, 4, 30, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 343, FakeDatetime(2024, 4, 30, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 278, FakeDatetime(2024, 4, 30, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 209, FakeDatetime(2024, 4, 30, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 138, FakeDatetime(2024, 4, 30, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 76, FakeDatetime(2024, 4, 30, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 37, FakeDatetime(2024, 4, 30, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 15, FakeDatetime(2024, 4, 30, 21, 6, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0}, wh_period={FakeDatetime(2024, 4, 27, 6, 18, 15, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 35, FakeDatetime(2024, 4, 27, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 61, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 92, FakeDatetime(2024, 4, 27, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 124, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 155, FakeDatetime(2024, 4, 27, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 186, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 240, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 262, FakeDatetime(2024, 4, 27, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 283, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 301, FakeDatetime(2024, 4, 27, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 310, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 315, FakeDatetime(2024, 4, 27, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 319, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 319, FakeDatetime(2024, 4, 27, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 314, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 305, FakeDatetime(2024, 4, 27, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 293, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 277, FakeDatetime(2024, 4, 27, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 259, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 240, FakeDatetime(2024, 4, 27, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 187, FakeDatetime(2024, 4, 27, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 156, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 124, FakeDatetime(2024, 4, 27, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 91, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 58, FakeDatetime(2024, 4, 27, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 32, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 15, FakeDatetime(2024, 4, 27, 21, 1, 7, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 16, 16, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 28, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 33, FakeDatetime(2024, 4, 28, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 59, FakeDatetime(2024, 4, 28, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 89, FakeDatetime(2024, 4, 28, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 120, FakeDatetime(2024, 4, 28, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 151, FakeDatetime(2024, 4, 28, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 182, FakeDatetime(2024, 4, 28, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 221, FakeDatetime(2024, 4, 28, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 281, FakeDatetime(2024, 4, 28, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 354, FakeDatetime(2024, 4, 28, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 400, FakeDatetime(2024, 4, 28, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 28, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 388, FakeDatetime(2024, 4, 28, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 374, FakeDatetime(2024, 4, 28, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 383, FakeDatetime(2024, 4, 28, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 28, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 426, FakeDatetime(2024, 4, 28, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 430, FakeDatetime(2024, 4, 28, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 415, FakeDatetime(2024, 4, 28, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 392, FakeDatetime(2024, 4, 28, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 376, FakeDatetime(2024, 4, 28, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 357, FakeDatetime(2024, 4, 28, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 320, FakeDatetime(2024, 4, 28, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 274, FakeDatetime(2024, 4, 28, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 227, FakeDatetime(2024, 4, 28, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 179, FakeDatetime(2024, 4, 28, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 128, FakeDatetime(2024, 4, 28, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 76, FakeDatetime(2024, 4, 28, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 38, FakeDatetime(2024, 4, 28, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 17, FakeDatetime(2024, 4, 28, 21, 2, 49, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 14, 18, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 29, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 34, FakeDatetime(2024, 4, 29, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 69, FakeDatetime(2024, 4, 29, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 119, FakeDatetime(2024, 4, 29, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 179, FakeDatetime(2024, 4, 29, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 249, FakeDatetime(2024, 4, 29, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 316, FakeDatetime(2024, 4, 29, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 358, FakeDatetime(2024, 4, 29, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 357, FakeDatetime(2024, 4, 29, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 350, FakeDatetime(2024, 4, 29, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 381, FakeDatetime(2024, 4, 29, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 431, FakeDatetime(2024, 4, 29, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 461, FakeDatetime(2024, 4, 29, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 464, FakeDatetime(2024, 4, 29, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 443, FakeDatetime(2024, 4, 29, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 29, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 363, FakeDatetime(2024, 4, 29, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 328, FakeDatetime(2024, 4, 29, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 303, FakeDatetime(2024, 4, 29, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 282, FakeDatetime(2024, 4, 29, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 261, FakeDatetime(2024, 4, 29, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 238, FakeDatetime(2024, 4, 29, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 213, FakeDatetime(2024, 4, 29, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 184, FakeDatetime(2024, 4, 29, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 154, FakeDatetime(2024, 4, 29, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 121, FakeDatetime(2024, 4, 29, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 87, FakeDatetime(2024, 4, 29, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 55, FakeDatetime(2024, 4, 29, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 30, FakeDatetime(2024, 4, 29, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 14, FakeDatetime(2024, 4, 29, 21, 4, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 1, FakeDatetime(2024, 4, 30, 6, 12, 21, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 6, FakeDatetime(2024, 4, 30, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 31, FakeDatetime(2024, 4, 30, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 56, FakeDatetime(2024, 4, 30, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 86, FakeDatetime(2024, 4, 30, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 117, FakeDatetime(2024, 4, 30, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 149, FakeDatetime(2024, 4, 30, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 180, FakeDatetime(2024, 4, 30, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 209, FakeDatetime(2024, 4, 30, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 234, FakeDatetime(2024, 4, 30, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 255, FakeDatetime(2024, 4, 30, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 274, FakeDatetime(2024, 4, 30, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 290, FakeDatetime(2024, 4, 30, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 301, FakeDatetime(2024, 4, 30, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 309, FakeDatetime(2024, 4, 30, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 312, FakeDatetime(2024, 4, 30, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 312, FakeDatetime(2024, 4, 30, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 310, FakeDatetime(2024, 4, 30, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 304, FakeDatetime(2024, 4, 30, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 292, FakeDatetime(2024, 4, 30, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 276, FakeDatetime(2024, 4, 30, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 258, FakeDatetime(2024, 4, 30, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 237, FakeDatetime(2024, 4, 30, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 213, FakeDatetime(2024, 4, 30, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 186, FakeDatetime(2024, 4, 30, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 155, FakeDatetime(2024, 4, 30, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 122, FakeDatetime(2024, 4, 30, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 87, FakeDatetime(2024, 4, 30, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 54, FakeDatetime(2024, 4, 30, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 28, FakeDatetime(2024, 4, 30, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 13, FakeDatetime(2024, 4, 30, 21, 6, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 1}, wh_days={FakeDatetime(2024, 4, 27, 0, 0): 5788, FakeDatetime(2024, 4, 28, 0, 0): 7507, FakeDatetime(2024, 4, 29, 0, 0): 7256, FakeDatetime(2024, 4, 30, 0, 0): 5657}, api_rate_limit=60, api_timezone='Europe/Amsterdam') # --- # name: test_estimated_forecast_with_subscription_and_actual_value Estimate(watts={FakeDatetime(2024, 4, 27, 6, 18, 15, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 47, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 92, FakeDatetime(2024, 4, 27, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 153, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 279, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 342, FakeDatetime(2024, 4, 27, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 402, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 457, FakeDatetime(2024, 4, 27, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 501, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 545, FakeDatetime(2024, 4, 27, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 587, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 616, FakeDatetime(2024, 4, 27, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 625, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 635, FakeDatetime(2024, 4, 27, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 639, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 635, FakeDatetime(2024, 4, 27, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 619, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 600, FakeDatetime(2024, 4, 27, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 570, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 536, FakeDatetime(2024, 4, 27, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 500, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 458, FakeDatetime(2024, 4, 27, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 403, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 344, FakeDatetime(2024, 4, 27, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 281, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 147, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 85, FakeDatetime(2024, 4, 27, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 42, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 18, FakeDatetime(2024, 4, 27, 21, 1, 7, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 16, 16, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 45, FakeDatetime(2024, 4, 28, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 88, FakeDatetime(2024, 4, 28, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 147, FakeDatetime(2024, 4, 28, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 208, FakeDatetime(2024, 4, 28, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 270, FakeDatetime(2024, 4, 28, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 332, FakeDatetime(2024, 4, 28, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 396, FakeDatetime(2024, 4, 28, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 487, FakeDatetime(2024, 4, 28, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 636, FakeDatetime(2024, 4, 28, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 778, FakeDatetime(2024, 4, 28, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 822, FakeDatetime(2024, 4, 28, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 801, FakeDatetime(2024, 4, 28, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 751, FakeDatetime(2024, 4, 28, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 746, FakeDatetime(2024, 4, 28, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 787, FakeDatetime(2024, 4, 28, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 837, FakeDatetime(2024, 4, 28, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 865, FakeDatetime(2024, 4, 28, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 855, FakeDatetime(2024, 4, 28, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 804, FakeDatetime(2024, 4, 28, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 765, FakeDatetime(2024, 4, 28, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 739, FakeDatetime(2024, 4, 28, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 687, FakeDatetime(2024, 4, 28, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 594, FakeDatetime(2024, 4, 28, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 500, FakeDatetime(2024, 4, 28, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 408, FakeDatetime(2024, 4, 28, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 309, FakeDatetime(2024, 4, 28, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 201, FakeDatetime(2024, 4, 28, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 103, FakeDatetime(2024, 4, 28, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 47, FakeDatetime(2024, 4, 28, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 19, FakeDatetime(2024, 4, 28, 21, 2, 49, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 14, 18, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 41, FakeDatetime(2024, 4, 29, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 93, FakeDatetime(2024, 4, 29, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 184, FakeDatetime(2024, 4, 29, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 291, FakeDatetime(2024, 4, 29, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 426, FakeDatetime(2024, 4, 29, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 569, FakeDatetime(2024, 4, 29, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 695, FakeDatetime(2024, 4, 29, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 735, FakeDatetime(2024, 4, 29, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 691, FakeDatetime(2024, 4, 29, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 707, FakeDatetime(2024, 4, 29, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 815, FakeDatetime(2024, 4, 29, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 910, FakeDatetime(2024, 4, 29, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 935, FakeDatetime(2024, 4, 29, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 919, FakeDatetime(2024, 4, 29, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 854, FakeDatetime(2024, 4, 29, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 768, FakeDatetime(2024, 4, 29, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 683, FakeDatetime(2024, 4, 29, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 628, FakeDatetime(2024, 4, 29, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 585, FakeDatetime(2024, 4, 29, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 544, FakeDatetime(2024, 4, 29, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 499, FakeDatetime(2024, 4, 29, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 452, FakeDatetime(2024, 4, 29, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 398, FakeDatetime(2024, 4, 29, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 339, FakeDatetime(2024, 4, 29, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 275, FakeDatetime(2024, 4, 29, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 208, FakeDatetime(2024, 4, 29, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 140, FakeDatetime(2024, 4, 29, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 79, FakeDatetime(2024, 4, 29, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 39, FakeDatetime(2024, 4, 29, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 16, FakeDatetime(2024, 4, 29, 21, 4, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 12, 21, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 41, FakeDatetime(2024, 4, 30, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 82, FakeDatetime(2024, 4, 30, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 141, FakeDatetime(2024, 4, 30, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 203, FakeDatetime(2024, 4, 30, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 266, FakeDatetime(2024, 4, 30, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 329, FakeDatetime(2024, 4, 30, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 390, FakeDatetime(2024, 4, 30, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 445, FakeDatetime(2024, 4, 30, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 490, FakeDatetime(2024, 4, 30, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 531, FakeDatetime(2024, 4, 30, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 566, FakeDatetime(2024, 4, 30, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 594, FakeDatetime(2024, 4, 30, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 611, FakeDatetime(2024, 4, 30, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 623, FakeDatetime(2024, 4, 30, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 625, FakeDatetime(2024, 4, 30, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 623, FakeDatetime(2024, 4, 30, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 615, FakeDatetime(2024, 4, 30, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 599, FakeDatetime(2024, 4, 30, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 570, FakeDatetime(2024, 4, 30, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 535, FakeDatetime(2024, 4, 30, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 496, FakeDatetime(2024, 4, 30, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 452, FakeDatetime(2024, 4, 30, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 401, FakeDatetime(2024, 4, 30, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 343, FakeDatetime(2024, 4, 30, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 278, FakeDatetime(2024, 4, 30, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 209, FakeDatetime(2024, 4, 30, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 138, FakeDatetime(2024, 4, 30, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 76, FakeDatetime(2024, 4, 30, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 37, FakeDatetime(2024, 4, 30, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 15, FakeDatetime(2024, 4, 30, 21, 6, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0}, wh_period={FakeDatetime(2024, 4, 27, 6, 18, 15, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 27, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 27, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 35, FakeDatetime(2024, 4, 27, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 61, FakeDatetime(2024, 4, 27, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 92, FakeDatetime(2024, 4, 27, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 124, FakeDatetime(2024, 4, 27, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 155, FakeDatetime(2024, 4, 27, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 186, FakeDatetime(2024, 4, 27, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 240, FakeDatetime(2024, 4, 27, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 262, FakeDatetime(2024, 4, 27, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 283, FakeDatetime(2024, 4, 27, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 301, FakeDatetime(2024, 4, 27, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 310, FakeDatetime(2024, 4, 27, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 315, FakeDatetime(2024, 4, 27, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 319, FakeDatetime(2024, 4, 27, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 319, FakeDatetime(2024, 4, 27, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 314, FakeDatetime(2024, 4, 27, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 305, FakeDatetime(2024, 4, 27, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 293, FakeDatetime(2024, 4, 27, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 277, FakeDatetime(2024, 4, 27, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 259, FakeDatetime(2024, 4, 27, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 240, FakeDatetime(2024, 4, 27, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 215, FakeDatetime(2024, 4, 27, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 187, FakeDatetime(2024, 4, 27, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 156, FakeDatetime(2024, 4, 27, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 124, FakeDatetime(2024, 4, 27, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 91, FakeDatetime(2024, 4, 27, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 58, FakeDatetime(2024, 4, 27, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 32, FakeDatetime(2024, 4, 27, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 15, FakeDatetime(2024, 4, 27, 21, 1, 7, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 16, 16, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 28, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 28, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 33, FakeDatetime(2024, 4, 28, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 59, FakeDatetime(2024, 4, 28, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 89, FakeDatetime(2024, 4, 28, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 120, FakeDatetime(2024, 4, 28, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 151, FakeDatetime(2024, 4, 28, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 182, FakeDatetime(2024, 4, 28, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 221, FakeDatetime(2024, 4, 28, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 281, FakeDatetime(2024, 4, 28, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 354, FakeDatetime(2024, 4, 28, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 400, FakeDatetime(2024, 4, 28, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 28, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 388, FakeDatetime(2024, 4, 28, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 374, FakeDatetime(2024, 4, 28, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 383, FakeDatetime(2024, 4, 28, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 28, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 426, FakeDatetime(2024, 4, 28, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 430, FakeDatetime(2024, 4, 28, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 415, FakeDatetime(2024, 4, 28, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 392, FakeDatetime(2024, 4, 28, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 376, FakeDatetime(2024, 4, 28, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 357, FakeDatetime(2024, 4, 28, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 320, FakeDatetime(2024, 4, 28, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 274, FakeDatetime(2024, 4, 28, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 227, FakeDatetime(2024, 4, 28, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 179, FakeDatetime(2024, 4, 28, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 128, FakeDatetime(2024, 4, 28, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 76, FakeDatetime(2024, 4, 28, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 38, FakeDatetime(2024, 4, 28, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 17, FakeDatetime(2024, 4, 28, 21, 2, 49, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 14, 18, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 29, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 5, FakeDatetime(2024, 4, 29, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 34, FakeDatetime(2024, 4, 29, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 69, FakeDatetime(2024, 4, 29, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 119, FakeDatetime(2024, 4, 29, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 179, FakeDatetime(2024, 4, 29, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 249, FakeDatetime(2024, 4, 29, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 316, FakeDatetime(2024, 4, 29, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 358, FakeDatetime(2024, 4, 29, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 357, FakeDatetime(2024, 4, 29, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 350, FakeDatetime(2024, 4, 29, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 381, FakeDatetime(2024, 4, 29, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 431, FakeDatetime(2024, 4, 29, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 461, FakeDatetime(2024, 4, 29, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 464, FakeDatetime(2024, 4, 29, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 443, FakeDatetime(2024, 4, 29, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 406, FakeDatetime(2024, 4, 29, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 363, FakeDatetime(2024, 4, 29, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 328, FakeDatetime(2024, 4, 29, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 303, FakeDatetime(2024, 4, 29, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 282, FakeDatetime(2024, 4, 29, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 261, FakeDatetime(2024, 4, 29, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 238, FakeDatetime(2024, 4, 29, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 213, FakeDatetime(2024, 4, 29, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 184, FakeDatetime(2024, 4, 29, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 154, FakeDatetime(2024, 4, 29, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 121, FakeDatetime(2024, 4, 29, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 87, FakeDatetime(2024, 4, 29, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 55, FakeDatetime(2024, 4, 29, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 30, FakeDatetime(2024, 4, 29, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 14, FakeDatetime(2024, 4, 29, 21, 4, 31, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 1, FakeDatetime(2024, 4, 30, 6, 12, 21, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 0, FakeDatetime(2024, 4, 30, 6, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 6, FakeDatetime(2024, 4, 30, 7, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 31, FakeDatetime(2024, 4, 30, 7, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 56, FakeDatetime(2024, 4, 30, 8, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 86, FakeDatetime(2024, 4, 30, 8, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 117, FakeDatetime(2024, 4, 30, 9, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 149, FakeDatetime(2024, 4, 30, 9, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 180, FakeDatetime(2024, 4, 30, 10, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 209, FakeDatetime(2024, 4, 30, 10, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 234, FakeDatetime(2024, 4, 30, 11, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 255, FakeDatetime(2024, 4, 30, 11, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 274, FakeDatetime(2024, 4, 30, 12, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 290, FakeDatetime(2024, 4, 30, 12, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 301, FakeDatetime(2024, 4, 30, 13, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 309, FakeDatetime(2024, 4, 30, 13, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 312, FakeDatetime(2024, 4, 30, 14, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 312, FakeDatetime(2024, 4, 30, 14, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 310, FakeDatetime(2024, 4, 30, 15, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 304, FakeDatetime(2024, 4, 30, 15, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 292, FakeDatetime(2024, 4, 30, 16, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 276, FakeDatetime(2024, 4, 30, 16, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 258, FakeDatetime(2024, 4, 30, 17, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 237, FakeDatetime(2024, 4, 30, 17, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 213, FakeDatetime(2024, 4, 30, 18, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 186, FakeDatetime(2024, 4, 30, 18, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 155, FakeDatetime(2024, 4, 30, 19, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 122, FakeDatetime(2024, 4, 30, 19, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 87, FakeDatetime(2024, 4, 30, 20, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 54, FakeDatetime(2024, 4, 30, 20, 30, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 28, FakeDatetime(2024, 4, 30, 21, 0, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 13, FakeDatetime(2024, 4, 30, 21, 6, 12, tzinfo=datetime.timezone(datetime.timedelta(seconds=7200))): 1}, wh_days={FakeDatetime(2024, 4, 27, 0, 0): 5788, FakeDatetime(2024, 4, 28, 0, 0): 7507, FakeDatetime(2024, 4, 29, 0, 0): 7256, FakeDatetime(2024, 4, 30, 0, 0): 5657}, api_rate_limit=60, api_timezone='Europe/Amsterdam') # --- forecast_solar-4.1.0/tests/conftest.py000066400000000000000000000024041477371027100200740ustar00rootroot00000000000000"""Fixtures for the Forecast.Solar tests.""" from collections.abc import AsyncGenerator import pytest from aiohttp import ClientSession from forecast_solar import ForecastSolar @pytest.fixture(name="forecast_client") async def client() -> AsyncGenerator[ForecastSolar, None]: """Return a Forecast.Solar client.""" async with ( ClientSession() as session, ForecastSolar( latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, damping=0, horizon="0,0,0,10,10,20,20,30,30", session=session, ) as forecast_client, ): yield forecast_client @pytest.fixture(name="forecast_key_client") async def client_api_key() -> AsyncGenerator[ForecastSolar, None]: """Return a Forecast.Solar client.""" async with ( ClientSession() as session, ForecastSolar( api_key="myapikey", latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, damping_morning=0, damping_evening=0, inverter=1.300, session=session, ) as forecast_key_client, ): yield forecast_key_client forecast_solar-4.1.0/tests/fixtures/000077500000000000000000000000001477371027100175465ustar00rootroot00000000000000forecast_solar-4.1.0/tests/fixtures/forecast.json000066400000000000000000000110721477371027100222500ustar00rootroot00000000000000{ "result": { "watts": { "2024-04-26T06:20:17+02:00": 0, "2024-04-26T07:00:00+02:00": 270, "2024-04-26T08:00:00+02:00": 481, "2024-04-26T09:00:00+02:00": 594, "2024-04-26T10:00:00+02:00": 781, "2024-04-26T11:00:00+02:00": 869, "2024-04-26T12:00:00+02:00": 773, "2024-04-26T13:00:00+02:00": 710, "2024-04-26T14:00:00+02:00": 620, "2024-04-26T15:00:00+02:00": 517, "2024-04-26T16:00:00+02:00": 430, "2024-04-26T17:00:00+02:00": 325, "2024-04-26T18:00:00+02:00": 204, "2024-04-26T19:00:00+02:00": 89, "2024-04-26T20:00:00+02:00": 38, "2024-04-26T20:59:23+02:00": 0, "2024-04-27T06:18:17+02:00": 0, "2024-04-27T07:00:00+02:00": 194, "2024-04-27T08:00:00+02:00": 325, "2024-04-27T09:00:00+02:00": 432, "2024-04-27T10:00:00+02:00": 514, "2024-04-27T11:00:00+02:00": 572, "2024-04-27T12:00:00+02:00": 604, "2024-04-27T13:00:00+02:00": 602, "2024-04-27T14:00:00+02:00": 563, "2024-04-27T15:00:00+02:00": 502, "2024-04-27T16:00:00+02:00": 422, "2024-04-27T17:00:00+02:00": 320, "2024-04-27T18:00:00+02:00": 201, "2024-04-27T19:00:00+02:00": 87, "2024-04-27T20:00:00+02:00": 22, "2024-04-27T21:00:00+02:00": 9, "2024-04-27T21:01:05+02:00": 0 }, "watt_hours_period": { "2024-04-26T06:20:17+02:00": 0, "2024-04-26T07:00:00+02:00": 89, "2024-04-26T08:00:00+02:00": 376, "2024-04-26T09:00:00+02:00": 538, "2024-04-26T10:00:00+02:00": 688, "2024-04-26T11:00:00+02:00": 825, "2024-04-26T12:00:00+02:00": 821, "2024-04-26T13:00:00+02:00": 742, "2024-04-26T14:00:00+02:00": 665, "2024-04-26T15:00:00+02:00": 569, "2024-04-26T16:00:00+02:00": 474, "2024-04-26T17:00:00+02:00": 378, "2024-04-26T18:00:00+02:00": 265, "2024-04-26T19:00:00+02:00": 147, "2024-04-26T20:00:00+02:00": 64, "2024-04-26T20:59:23+02:00": 19, "2024-04-27T06:18:17+02:00": 0, "2024-04-27T07:00:00+02:00": 67, "2024-04-27T08:00:00+02:00": 260, "2024-04-27T09:00:00+02:00": 379, "2024-04-27T10:00:00+02:00": 473, "2024-04-27T11:00:00+02:00": 543, "2024-04-27T12:00:00+02:00": 588, "2024-04-27T13:00:00+02:00": 603, "2024-04-27T14:00:00+02:00": 583, "2024-04-27T15:00:00+02:00": 533, "2024-04-27T16:00:00+02:00": 462, "2024-04-27T17:00:00+02:00": 371, "2024-04-27T18:00:00+02:00": 261, "2024-04-27T19:00:00+02:00": 144, "2024-04-27T20:00:00+02:00": 55, "2024-04-27T21:00:00+02:00": 16, "2024-04-27T21:01:05+02:00": 0 }, "watt_hours": { "2024-04-26T06:20:17+02:00": 0, "2024-04-26T07:00:00+02:00": 89, "2024-04-26T08:00:00+02:00": 465, "2024-04-26T09:00:00+02:00": 1003, "2024-04-26T10:00:00+02:00": 1691, "2024-04-26T11:00:00+02:00": 2516, "2024-04-26T12:00:00+02:00": 3337, "2024-04-26T13:00:00+02:00": 4079, "2024-04-26T14:00:00+02:00": 4744, "2024-04-26T15:00:00+02:00": 5313, "2024-04-26T16:00:00+02:00": 5787, "2024-04-26T17:00:00+02:00": 6165, "2024-04-26T18:00:00+02:00": 6430, "2024-04-26T19:00:00+02:00": 6577, "2024-04-26T20:00:00+02:00": 6641, "2024-04-26T20:59:23+02:00": 6660, "2024-04-27T06:18:17+02:00": 0, "2024-04-27T07:00:00+02:00": 67, "2024-04-27T08:00:00+02:00": 327, "2024-04-27T09:00:00+02:00": 706, "2024-04-27T10:00:00+02:00": 1179, "2024-04-27T11:00:00+02:00": 1722, "2024-04-27T12:00:00+02:00": 2310, "2024-04-27T13:00:00+02:00": 2913, "2024-04-27T14:00:00+02:00": 3496, "2024-04-27T15:00:00+02:00": 4029, "2024-04-27T16:00:00+02:00": 4491, "2024-04-27T17:00:00+02:00": 4862, "2024-04-27T18:00:00+02:00": 5123, "2024-04-27T19:00:00+02:00": 5267, "2024-04-27T20:00:00+02:00": 5322, "2024-04-27T21:00:00+02:00": 5338, "2024-04-27T21:01:05+02:00": 5338 }, "watt_hours_day": { "2024-04-26": 6660, "2024-04-27": 5338 } }, "message": { "code": 0, "type": "success", "text": "", "pid": "D8aH09A5", "info": { "latitude": 52.16, "longitude": 4.47, "distance": 0, "place": "34, Vondellaan, Lage Mors, Leiden, Zuid-Holland, Nederland, 2332 AE, Nederland", "timezone": "Europe/Amsterdam", "time": "2024-04-26T18:56:01+02:00", "time_utc": "2024-04-26T16:56:01+00:00" }, "ratelimit": { "zone": "IP ADDRESS", "period": 3600, "limit": 12, "remaining": 11 } } } forecast_solar-4.1.0/tests/fixtures/forecast_personal.json000066400000000000000000000373421477371027100241630ustar00rootroot00000000000000{ "result": { "watts": { "2024-04-27T06:18:15+02:00": 0, "2024-04-27T06:30:00+02:00": 47, "2024-04-27T07:00:00+02:00": 92, "2024-04-27T07:30:00+02:00": 153, "2024-04-27T08:00:00+02:00": 215, "2024-04-27T08:30:00+02:00": 279, "2024-04-27T09:00:00+02:00": 342, "2024-04-27T09:30:00+02:00": 402, "2024-04-27T10:00:00+02:00": 457, "2024-04-27T10:30:00+02:00": 501, "2024-04-27T11:00:00+02:00": 545, "2024-04-27T11:30:00+02:00": 587, "2024-04-27T12:00:00+02:00": 616, "2024-04-27T12:30:00+02:00": 625, "2024-04-27T13:00:00+02:00": 635, "2024-04-27T13:30:00+02:00": 639, "2024-04-27T14:00:00+02:00": 635, "2024-04-27T14:30:00+02:00": 619, "2024-04-27T15:00:00+02:00": 600, "2024-04-27T15:30:00+02:00": 570, "2024-04-27T16:00:00+02:00": 536, "2024-04-27T16:30:00+02:00": 500, "2024-04-27T17:00:00+02:00": 458, "2024-04-27T17:30:00+02:00": 403, "2024-04-27T18:00:00+02:00": 344, "2024-04-27T18:30:00+02:00": 281, "2024-04-27T19:00:00+02:00": 215, "2024-04-27T19:30:00+02:00": 147, "2024-04-27T20:00:00+02:00": 85, "2024-04-27T20:30:00+02:00": 42, "2024-04-27T21:00:00+02:00": 18, "2024-04-27T21:01:07+02:00": 0, "2024-04-28T06:16:16+02:00": 0, "2024-04-28T06:30:00+02:00": 45, "2024-04-28T07:00:00+02:00": 88, "2024-04-28T07:30:00+02:00": 147, "2024-04-28T08:00:00+02:00": 208, "2024-04-28T08:30:00+02:00": 270, "2024-04-28T09:00:00+02:00": 332, "2024-04-28T09:30:00+02:00": 396, "2024-04-28T10:00:00+02:00": 487, "2024-04-28T10:30:00+02:00": 636, "2024-04-28T11:00:00+02:00": 778, "2024-04-28T11:30:00+02:00": 822, "2024-04-28T12:00:00+02:00": 801, "2024-04-28T12:30:00+02:00": 751, "2024-04-28T13:00:00+02:00": 746, "2024-04-28T13:30:00+02:00": 787, "2024-04-28T14:00:00+02:00": 837, "2024-04-28T14:30:00+02:00": 865, "2024-04-28T15:00:00+02:00": 855, "2024-04-28T15:30:00+02:00": 804, "2024-04-28T16:00:00+02:00": 765, "2024-04-28T16:30:00+02:00": 739, "2024-04-28T17:00:00+02:00": 687, "2024-04-28T17:30:00+02:00": 594, "2024-04-28T18:00:00+02:00": 500, "2024-04-28T18:30:00+02:00": 408, "2024-04-28T19:00:00+02:00": 309, "2024-04-28T19:30:00+02:00": 201, "2024-04-28T20:00:00+02:00": 103, "2024-04-28T20:30:00+02:00": 47, "2024-04-28T21:00:00+02:00": 19, "2024-04-28T21:02:49+02:00": 0, "2024-04-29T06:14:18+02:00": 0, "2024-04-29T06:30:00+02:00": 41, "2024-04-29T07:00:00+02:00": 93, "2024-04-29T07:30:00+02:00": 184, "2024-04-29T08:00:00+02:00": 291, "2024-04-29T08:30:00+02:00": 426, "2024-04-29T09:00:00+02:00": 569, "2024-04-29T09:30:00+02:00": 695, "2024-04-29T10:00:00+02:00": 735, "2024-04-29T10:30:00+02:00": 691, "2024-04-29T11:00:00+02:00": 707, "2024-04-29T11:30:00+02:00": 815, "2024-04-29T12:00:00+02:00": 910, "2024-04-29T12:30:00+02:00": 935, "2024-04-29T13:00:00+02:00": 919, "2024-04-29T13:30:00+02:00": 854, "2024-04-29T14:00:00+02:00": 768, "2024-04-29T14:30:00+02:00": 683, "2024-04-29T15:00:00+02:00": 628, "2024-04-29T15:30:00+02:00": 585, "2024-04-29T16:00:00+02:00": 544, "2024-04-29T16:30:00+02:00": 499, "2024-04-29T17:00:00+02:00": 452, "2024-04-29T17:30:00+02:00": 398, "2024-04-29T18:00:00+02:00": 339, "2024-04-29T18:30:00+02:00": 275, "2024-04-29T19:00:00+02:00": 208, "2024-04-29T19:30:00+02:00": 140, "2024-04-29T20:00:00+02:00": 79, "2024-04-29T20:30:00+02:00": 39, "2024-04-29T21:00:00+02:00": 16, "2024-04-29T21:04:31+02:00": 0, "2024-04-30T06:12:21+02:00": 0, "2024-04-30T06:30:00+02:00": 41, "2024-04-30T07:00:00+02:00": 82, "2024-04-30T07:30:00+02:00": 141, "2024-04-30T08:00:00+02:00": 203, "2024-04-30T08:30:00+02:00": 266, "2024-04-30T09:00:00+02:00": 329, "2024-04-30T09:30:00+02:00": 390, "2024-04-30T10:00:00+02:00": 445, "2024-04-30T10:30:00+02:00": 490, "2024-04-30T11:00:00+02:00": 531, "2024-04-30T11:30:00+02:00": 566, "2024-04-30T12:00:00+02:00": 594, "2024-04-30T12:30:00+02:00": 611, "2024-04-30T13:00:00+02:00": 623, "2024-04-30T13:30:00+02:00": 625, "2024-04-30T14:00:00+02:00": 623, "2024-04-30T14:30:00+02:00": 615, "2024-04-30T15:00:00+02:00": 599, "2024-04-30T15:30:00+02:00": 570, "2024-04-30T16:00:00+02:00": 535, "2024-04-30T16:30:00+02:00": 496, "2024-04-30T17:00:00+02:00": 452, "2024-04-30T17:30:00+02:00": 401, "2024-04-30T18:00:00+02:00": 343, "2024-04-30T18:30:00+02:00": 278, "2024-04-30T19:00:00+02:00": 209, "2024-04-30T19:30:00+02:00": 138, "2024-04-30T20:00:00+02:00": 76, "2024-04-30T20:30:00+02:00": 37, "2024-04-30T21:00:00+02:00": 15, "2024-04-30T21:06:12+02:00": 0 }, "watt_hours_period": { "2024-04-27T06:18:15+02:00": 0, "2024-04-27T06:30:00+02:00": 5, "2024-04-27T07:00:00+02:00": 35, "2024-04-27T07:30:00+02:00": 61, "2024-04-27T08:00:00+02:00": 92, "2024-04-27T08:30:00+02:00": 124, "2024-04-27T09:00:00+02:00": 155, "2024-04-27T09:30:00+02:00": 186, "2024-04-27T10:00:00+02:00": 215, "2024-04-27T10:30:00+02:00": 240, "2024-04-27T11:00:00+02:00": 262, "2024-04-27T11:30:00+02:00": 283, "2024-04-27T12:00:00+02:00": 301, "2024-04-27T12:30:00+02:00": 310, "2024-04-27T13:00:00+02:00": 315, "2024-04-27T13:30:00+02:00": 319, "2024-04-27T14:00:00+02:00": 319, "2024-04-27T14:30:00+02:00": 314, "2024-04-27T15:00:00+02:00": 305, "2024-04-27T15:30:00+02:00": 293, "2024-04-27T16:00:00+02:00": 277, "2024-04-27T16:30:00+02:00": 259, "2024-04-27T17:00:00+02:00": 240, "2024-04-27T17:30:00+02:00": 215, "2024-04-27T18:00:00+02:00": 187, "2024-04-27T18:30:00+02:00": 156, "2024-04-27T19:00:00+02:00": 124, "2024-04-27T19:30:00+02:00": 91, "2024-04-27T20:00:00+02:00": 58, "2024-04-27T20:30:00+02:00": 32, "2024-04-27T21:00:00+02:00": 15, "2024-04-27T21:01:07+02:00": 0, "2024-04-28T06:16:16+02:00": 0, "2024-04-28T06:30:00+02:00": 5, "2024-04-28T07:00:00+02:00": 33, "2024-04-28T07:30:00+02:00": 59, "2024-04-28T08:00:00+02:00": 89, "2024-04-28T08:30:00+02:00": 120, "2024-04-28T09:00:00+02:00": 151, "2024-04-28T09:30:00+02:00": 182, "2024-04-28T10:00:00+02:00": 221, "2024-04-28T10:30:00+02:00": 281, "2024-04-28T11:00:00+02:00": 354, "2024-04-28T11:30:00+02:00": 400, "2024-04-28T12:00:00+02:00": 406, "2024-04-28T12:30:00+02:00": 388, "2024-04-28T13:00:00+02:00": 374, "2024-04-28T13:30:00+02:00": 383, "2024-04-28T14:00:00+02:00": 406, "2024-04-28T14:30:00+02:00": 426, "2024-04-28T15:00:00+02:00": 430, "2024-04-28T15:30:00+02:00": 415, "2024-04-28T16:00:00+02:00": 392, "2024-04-28T16:30:00+02:00": 376, "2024-04-28T17:00:00+02:00": 357, "2024-04-28T17:30:00+02:00": 320, "2024-04-28T18:00:00+02:00": 274, "2024-04-28T18:30:00+02:00": 227, "2024-04-28T19:00:00+02:00": 179, "2024-04-28T19:30:00+02:00": 128, "2024-04-28T20:00:00+02:00": 76, "2024-04-28T20:30:00+02:00": 38, "2024-04-28T21:00:00+02:00": 17, "2024-04-28T21:02:49+02:00": 0, "2024-04-29T06:14:18+02:00": 0, "2024-04-29T06:30:00+02:00": 5, "2024-04-29T07:00:00+02:00": 34, "2024-04-29T07:30:00+02:00": 69, "2024-04-29T08:00:00+02:00": 119, "2024-04-29T08:30:00+02:00": 179, "2024-04-29T09:00:00+02:00": 249, "2024-04-29T09:30:00+02:00": 316, "2024-04-29T10:00:00+02:00": 358, "2024-04-29T10:30:00+02:00": 357, "2024-04-29T11:00:00+02:00": 350, "2024-04-29T11:30:00+02:00": 381, "2024-04-29T12:00:00+02:00": 431, "2024-04-29T12:30:00+02:00": 461, "2024-04-29T13:00:00+02:00": 464, "2024-04-29T13:30:00+02:00": 443, "2024-04-29T14:00:00+02:00": 406, "2024-04-29T14:30:00+02:00": 363, "2024-04-29T15:00:00+02:00": 328, "2024-04-29T15:30:00+02:00": 303, "2024-04-29T16:00:00+02:00": 282, "2024-04-29T16:30:00+02:00": 261, "2024-04-29T17:00:00+02:00": 238, "2024-04-29T17:30:00+02:00": 213, "2024-04-29T18:00:00+02:00": 184, "2024-04-29T18:30:00+02:00": 154, "2024-04-29T19:00:00+02:00": 121, "2024-04-29T19:30:00+02:00": 87, "2024-04-29T20:00:00+02:00": 55, "2024-04-29T20:30:00+02:00": 30, "2024-04-29T21:00:00+02:00": 14, "2024-04-29T21:04:31+02:00": 1, "2024-04-30T06:12:21+02:00": 0, "2024-04-30T06:30:00+02:00": 6, "2024-04-30T07:00:00+02:00": 31, "2024-04-30T07:30:00+02:00": 56, "2024-04-30T08:00:00+02:00": 86, "2024-04-30T08:30:00+02:00": 117, "2024-04-30T09:00:00+02:00": 149, "2024-04-30T09:30:00+02:00": 180, "2024-04-30T10:00:00+02:00": 209, "2024-04-30T10:30:00+02:00": 234, "2024-04-30T11:00:00+02:00": 255, "2024-04-30T11:30:00+02:00": 274, "2024-04-30T12:00:00+02:00": 290, "2024-04-30T12:30:00+02:00": 301, "2024-04-30T13:00:00+02:00": 309, "2024-04-30T13:30:00+02:00": 312, "2024-04-30T14:00:00+02:00": 312, "2024-04-30T14:30:00+02:00": 310, "2024-04-30T15:00:00+02:00": 304, "2024-04-30T15:30:00+02:00": 292, "2024-04-30T16:00:00+02:00": 276, "2024-04-30T16:30:00+02:00": 258, "2024-04-30T17:00:00+02:00": 237, "2024-04-30T17:30:00+02:00": 213, "2024-04-30T18:00:00+02:00": 186, "2024-04-30T18:30:00+02:00": 155, "2024-04-30T19:00:00+02:00": 122, "2024-04-30T19:30:00+02:00": 87, "2024-04-30T20:00:00+02:00": 54, "2024-04-30T20:30:00+02:00": 28, "2024-04-30T21:00:00+02:00": 13, "2024-04-30T21:06:12+02:00": 1 }, "watt_hours": { "2024-04-27T06:18:15+02:00": 0, "2024-04-27T06:30:00+02:00": 5, "2024-04-27T07:00:00+02:00": 40, "2024-04-27T07:30:00+02:00": 101, "2024-04-27T08:00:00+02:00": 193, "2024-04-27T08:30:00+02:00": 317, "2024-04-27T09:00:00+02:00": 472, "2024-04-27T09:30:00+02:00": 658, "2024-04-27T10:00:00+02:00": 873, "2024-04-27T10:30:00+02:00": 1113, "2024-04-27T11:00:00+02:00": 1375, "2024-04-27T11:30:00+02:00": 1658, "2024-04-27T12:00:00+02:00": 1959, "2024-04-27T12:30:00+02:00": 2269, "2024-04-27T13:00:00+02:00": 2584, "2024-04-27T13:30:00+02:00": 2903, "2024-04-27T14:00:00+02:00": 3222, "2024-04-27T14:30:00+02:00": 3536, "2024-04-27T15:00:00+02:00": 3841, "2024-04-27T15:30:00+02:00": 4134, "2024-04-27T16:00:00+02:00": 4411, "2024-04-27T16:30:00+02:00": 4670, "2024-04-27T17:00:00+02:00": 4910, "2024-04-27T17:30:00+02:00": 5125, "2024-04-27T18:00:00+02:00": 5312, "2024-04-27T18:30:00+02:00": 5468, "2024-04-27T19:00:00+02:00": 5592, "2024-04-27T19:30:00+02:00": 5683, "2024-04-27T20:00:00+02:00": 5741, "2024-04-27T20:30:00+02:00": 5773, "2024-04-27T21:00:00+02:00": 5788, "2024-04-27T21:01:07+02:00": 5788, "2024-04-28T06:16:16+02:00": 0, "2024-04-28T06:30:00+02:00": 5, "2024-04-28T07:00:00+02:00": 38, "2024-04-28T07:30:00+02:00": 97, "2024-04-28T08:00:00+02:00": 186, "2024-04-28T08:30:00+02:00": 306, "2024-04-28T09:00:00+02:00": 457, "2024-04-28T09:30:00+02:00": 639, "2024-04-28T10:00:00+02:00": 860, "2024-04-28T10:30:00+02:00": 1141, "2024-04-28T11:00:00+02:00": 1495, "2024-04-28T11:30:00+02:00": 1895, "2024-04-28T12:00:00+02:00": 2301, "2024-04-28T12:30:00+02:00": 2689, "2024-04-28T13:00:00+02:00": 3063, "2024-04-28T13:30:00+02:00": 3446, "2024-04-28T14:00:00+02:00": 3852, "2024-04-28T14:30:00+02:00": 4278, "2024-04-28T15:00:00+02:00": 4708, "2024-04-28T15:30:00+02:00": 5123, "2024-04-28T16:00:00+02:00": 5515, "2024-04-28T16:30:00+02:00": 5891, "2024-04-28T17:00:00+02:00": 6248, "2024-04-28T17:30:00+02:00": 6568, "2024-04-28T18:00:00+02:00": 6842, "2024-04-28T18:30:00+02:00": 7069, "2024-04-28T19:00:00+02:00": 7248, "2024-04-28T19:30:00+02:00": 7376, "2024-04-28T20:00:00+02:00": 7452, "2024-04-28T20:30:00+02:00": 7490, "2024-04-28T21:00:00+02:00": 7507, "2024-04-28T21:02:49+02:00": 7507, "2024-04-29T06:14:18+02:00": 0, "2024-04-29T06:30:00+02:00": 5, "2024-04-29T07:00:00+02:00": 39, "2024-04-29T07:30:00+02:00": 108, "2024-04-29T08:00:00+02:00": 227, "2024-04-29T08:30:00+02:00": 406, "2024-04-29T09:00:00+02:00": 655, "2024-04-29T09:30:00+02:00": 971, "2024-04-29T10:00:00+02:00": 1329, "2024-04-29T10:30:00+02:00": 1686, "2024-04-29T11:00:00+02:00": 2036, "2024-04-29T11:30:00+02:00": 2417, "2024-04-29T12:00:00+02:00": 2848, "2024-04-29T12:30:00+02:00": 3309, "2024-04-29T13:00:00+02:00": 3773, "2024-04-29T13:30:00+02:00": 4216, "2024-04-29T14:00:00+02:00": 4622, "2024-04-29T14:30:00+02:00": 4985, "2024-04-29T15:00:00+02:00": 5313, "2024-04-29T15:30:00+02:00": 5616, "2024-04-29T16:00:00+02:00": 5898, "2024-04-29T16:30:00+02:00": 6159, "2024-04-29T17:00:00+02:00": 6397, "2024-04-29T17:30:00+02:00": 6610, "2024-04-29T18:00:00+02:00": 6794, "2024-04-29T18:30:00+02:00": 6948, "2024-04-29T19:00:00+02:00": 7069, "2024-04-29T19:30:00+02:00": 7156, "2024-04-29T20:00:00+02:00": 7211, "2024-04-29T20:30:00+02:00": 7241, "2024-04-29T21:00:00+02:00": 7255, "2024-04-29T21:04:31+02:00": 7256, "2024-04-30T06:12:21+02:00": 0, "2024-04-30T06:30:00+02:00": 6, "2024-04-30T07:00:00+02:00": 37, "2024-04-30T07:30:00+02:00": 93, "2024-04-30T08:00:00+02:00": 179, "2024-04-30T08:30:00+02:00": 296, "2024-04-30T09:00:00+02:00": 445, "2024-04-30T09:30:00+02:00": 625, "2024-04-30T10:00:00+02:00": 834, "2024-04-30T10:30:00+02:00": 1068, "2024-04-30T11:00:00+02:00": 1323, "2024-04-30T11:30:00+02:00": 1597, "2024-04-30T12:00:00+02:00": 1887, "2024-04-30T12:30:00+02:00": 2188, "2024-04-30T13:00:00+02:00": 2497, "2024-04-30T13:30:00+02:00": 2809, "2024-04-30T14:00:00+02:00": 3121, "2024-04-30T14:30:00+02:00": 3431, "2024-04-30T15:00:00+02:00": 3735, "2024-04-30T15:30:00+02:00": 4027, "2024-04-30T16:00:00+02:00": 4303, "2024-04-30T16:30:00+02:00": 4561, "2024-04-30T17:00:00+02:00": 4798, "2024-04-30T17:30:00+02:00": 5011, "2024-04-30T18:00:00+02:00": 5197, "2024-04-30T18:30:00+02:00": 5352, "2024-04-30T19:00:00+02:00": 5474, "2024-04-30T19:30:00+02:00": 5561, "2024-04-30T20:00:00+02:00": 5615, "2024-04-30T20:30:00+02:00": 5643, "2024-04-30T21:00:00+02:00": 5656, "2024-04-30T21:06:12+02:00": 5657 }, "watt_hours_day": { "2024-04-27": 5788, "2024-04-28": 7507, "2024-04-29": 7256, "2024-04-30": 5657 } }, "message": { "code": 0, "type": "success", "text": "", "pid": "wXG62901", "info": { "latitude": 52.17, "longitude": 4.47, "distance": 0, "place": "Pedologisch Instituut De Brug, Pomonapad, 2333 VE Leiden, Netherlands", "timezone": "Europe/Amsterdam", "time": "2024-04-27T04:48:01+02:00", "time_utc": "2024-04-27T02:48:01+00:00" }, "ratelimit": { "zone": "API key", "period": 3600, "limit": 60, "remaining": 57 } } } forecast_solar-4.1.0/tests/fixtures/ratelimit.json000066400000000000000000000005071477371027100224350ustar00rootroot00000000000000{ "result": "Rate limit for API calls reached.", "message": { "code": 429, "type": "error", "text": "Rate limit for API calls reached.", "pid": "0F5m6R53", "ratelimit": { "zone": "YOUR IP ADDRESS", "period": 3600, "limit": 12, "retry-at": "2024-04-27T02:48:53+02:00" } } } forecast_solar-4.1.0/tests/fixtures/validate_key.json000066400000000000000000000007261477371027100231070ustar00rootroot00000000000000{ "result": { "paypal": "paypalid", "email": "email@example.com", "name": "John Doe", "subscription": "subscriptionid", "level": 1, "account": "Personal", "until": "2024-07-11", "created": "2021-06-27 15:14:45" }, "message": { "code": 0, "type": "success", "text": "", "pid": "m0UZ756I", "ratelimit": { "zone": "API key myapikey", "period": 3600, "limit": 60, "remaining": 57 } } } forecast_solar-4.1.0/tests/fixtures/validate_plane.json000066400000000000000000000013071477371027100234120ustar00rootroot00000000000000{ "result": { "latitude": "52ยฐ 09' 36\" N", "longitude": "04ยฐ 28' 12\" E", "declination": "20ยฐ", "azimuth": "10ยฐ", "power": "2.160 kWp", "place": "34, Vondellaan, Lage Mors, Leiden, Zuid-Holland, Nederland, 2332 AE, Nederland", "timezone": "Europe/Amsterdam" }, "message": { "code": 0, "type": "success", "text": "", "pid": "w40kJP6l", "info": { "latitude": 52.16, "longitude": 4.47, "distance": 0, "place": "34, Vondellaan, Lage Mors, Leiden, Zuid-Holland, Nederland, 2332 AE, Nederland", "timezone": "Europe/Amsterdam", "time": "2024-04-27T01:48:53+02:00", "time_utc": "2024-04-26T23:48:53+00:00" } } } forecast_solar-4.1.0/tests/ruff.toml000066400000000000000000000005431477371027100175360ustar00rootroot00000000000000# This extend our general Ruff rules specifically for tests extend = "../pyproject.toml" lint.extend-select = [ "PT", # Use @pytest.fixture without parentheses ] lint.extend-ignore = [ "S101", # Use of assert detected. As these are tests... "SLF001", # Tests will access private/protected members... "TC002", # pytest doesn't like this one... ] forecast_solar-4.1.0/tests/test_exceptions.py000066400000000000000000000067271477371027100215030ustar00rootroot00000000000000"""Text exceptions raised by the Forecast.Solar API client.""" import pytest from aresponses import ResponsesMockServer from forecast_solar import ( ForecastSolar, ForecastSolarAuthenticationError, ForecastSolarConfigError, ForecastSolarConnectionError, ForecastSolarRatelimitError, ForecastSolarRequestError, ) from . import load_fixtures async def test_status_400( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 400.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=400, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) with pytest.raises(ForecastSolarRequestError): assert await forecast_client._request("test") async def test_status_401( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 401 or 403.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=401, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) with pytest.raises(ForecastSolarAuthenticationError): assert await forecast_client._request("test") async def test_status_422( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 422.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=422, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) with pytest.raises(ForecastSolarConfigError): assert await forecast_client._request("test") async def test_status_429( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 429.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=429, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("ratelimit.json"), ), ) with pytest.raises(ForecastSolarRatelimitError): assert await forecast_client._request("test") async def test_status_502( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 502 or 503.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=502, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) with pytest.raises(ForecastSolarConnectionError): assert await forecast_client._request("test") forecast_solar-4.1.0/tests/test_forecast.py000066400000000000000000000064721477371027100211250ustar00rootroot00000000000000"""Tests for Forecast.Solar.""" # pylint: disable=protected-access import asyncio from typing import Any from unittest.mock import patch import pytest from aiodns import DNSResolver from aiodns.error import DNSError from aiohttp import ClientSession from aresponses import ResponsesMockServer from forecast_solar import ( ForecastSolar, ForecastSolarConnectionError, ForecastSolarError, ) from . import load_fixtures async def test_json_request( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test JSON response is handled correctly.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) response = await forecast_client._request("test") assert response is not None await forecast_client.close() async def test_internal_session(aresponses: ResponsesMockServer) -> None: """Test internal session is handled correctly.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) async with ForecastSolar( latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, damping=0, horizon="0,0,0,10,10,20,20,30,30", ) as client: await client._request("test") async def test_content_type( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test content type error handling.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=200, headers={ "Content-Type": "blabla/blabla", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, ), ) with pytest.raises(ForecastSolarError): assert await forecast_client._request("test") async def test_dns_error(forecast_client: ForecastSolar) -> None: """Test request DNS error is handled correctly.""" async with ClientSession(): with ( patch.object( DNSResolver, "query", side_effect=DNSError, ), pytest.raises(ForecastSolarConnectionError), ): assert await forecast_client._request("test") async def test_empty_dns_result(forecast_client: ForecastSolar) -> None: """Test empty DNS result is handled correctly.""" async with ClientSession(): dns_result: Any = asyncio.Future() dns_result.set_result(None) with ( patch.object( DNSResolver, "query", return_value=dns_result, ), pytest.raises(ForecastSolarConnectionError), ): assert await forecast_client._request("test") forecast_solar-4.1.0/tests/test_models.py000066400000000000000000000134071477371027100205760ustar00rootroot00000000000000"""Test the models.""" from datetime import datetime import pytest from aresponses import ResponsesMockServer from syrupy.assertion import SnapshotAssertion from forecast_solar import AccountType, Estimate, ForecastSolar from . import load_fixtures @pytest.mark.freeze_time("2024-04-26T12:00:00+02:00") async def test_estimated_forecast( aresponses: ResponsesMockServer, snapshot: SnapshotAssertion, forecast_client: ForecastSolar, ) -> None: """Test estimated forecast.""" aresponses.add( "api.forecast.solar", "/estimate/52.16/4.47/20/10/2.16", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("forecast.json"), ), ) forecast: Estimate = await forecast_client.estimate() assert forecast == snapshot assert forecast.timezone == "Europe/Amsterdam" assert forecast.account_type == AccountType.PUBLIC assert forecast.energy_production_today == 6660 assert forecast.energy_production_tomorrow == 5338 assert forecast.power_production_now == 773 assert forecast.energy_production_today_remaining == 4144 assert forecast.energy_current_hour == 821 assert forecast.power_highest_peak_time_today == datetime.fromisoformat( "2024-04-26T11:00:00+02:00" ) assert forecast.power_highest_peak_time_tomorrow == datetime.fromisoformat( "2024-04-27T12:00:00+02:00" ) assert forecast.sum_energy_production(1) == 742 assert forecast.sum_energy_production(6) == 3093 assert forecast.sum_energy_production(12) == 3323 assert forecast.sum_energy_production(24) == 5633 @pytest.mark.freeze_time("2024-04-27T07:00:00+02:00") async def test_estimated_forecast_with_subscription( aresponses: ResponsesMockServer, snapshot: SnapshotAssertion, forecast_key_client: ForecastSolar, ) -> None: """Test estimated forecast.""" aresponses.add( "api.forecast.solar", "/myapikey/estimate/52.16/4.47/20/10/2.16", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "60", "X-Ratelimit-Period": "3600", }, text=load_fixtures("forecast_personal.json"), ), ) forecast: Estimate = await forecast_key_client.estimate() assert forecast == snapshot assert forecast.timezone == "Europe/Amsterdam" assert forecast.account_type == AccountType.PERSONAL assert forecast.energy_production_today == 5788 assert forecast.energy_production_tomorrow == 7507 assert forecast.power_production_now == 92 assert forecast.energy_production_today_remaining == 5783 assert forecast.energy_current_hour == 96 assert forecast.power_highest_peak_time_today == datetime.fromisoformat( "2024-04-27T13:30:00+02:00" ) assert forecast.power_highest_peak_time_tomorrow == datetime.fromisoformat( "2024-04-28T14:30:00+02:00" ) assert forecast.sum_energy_production(1) == 216 assert forecast.sum_energy_production(6) == 2802 assert forecast.sum_energy_production(12) == 5582 assert forecast.sum_energy_production(24) == 5784 @pytest.mark.freeze_time("2024-04-27T07:00:00+02:00") async def test_estimated_forecast_with_subscription_and_actual_value( aresponses: ResponsesMockServer, snapshot: SnapshotAssertion, forecast_key_client: ForecastSolar, ) -> None: """Test estimated forecast.""" aresponses.add( "api.forecast.solar", "/myapikey/estimate/52.16/4.47/20/10/2.16", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "60", "X-Ratelimit-Period": "3600", }, text=load_fixtures("forecast_personal.json"), ), ) forecast: Estimate = await forecast_key_client.estimate(actual=2.300) assert forecast == snapshot assert forecast.timezone == "Europe/Amsterdam" assert forecast.account_type == AccountType.PERSONAL assert forecast.energy_production_today == 5788 assert forecast.energy_production_tomorrow == 7507 assert forecast.sum_energy_production(1) == 216 assert forecast.sum_energy_production(6) == 2802 assert forecast.sum_energy_production(12) == 5582 assert forecast.sum_energy_production(24) == 5784 async def test_api_key_validation( aresponses: ResponsesMockServer, forecast_key_client: ForecastSolar, ) -> None: """Test API key validation.""" aresponses.add( "api.forecast.solar", "/myapikey/info", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("validate_key.json"), ), ) assert await forecast_key_client.validate_api_key() is True async def test_plane_validation( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test plane validation.""" aresponses.add( "api.forecast.solar", "/check/52.16/4.47/20/10/2.16", "GET", aresponses.Response( status=200, headers={ "Content-Type": "application/json", "X-Ratelimit-Limit": "10", "X-Ratelimit-Period": "1", }, text=load_fixtures("validate_plane.json"), ), ) assert await forecast_client.validate_plane() is True