pax_global_header00006660000000000000000000000064151464240210014511gustar00rootroot0000000000000052 comment=c95b5ec6fab283b3eec34551172f6b9d20e4008e forecast_solar-5.0.0/000077500000000000000000000000001514642402100145215ustar00rootroot00000000000000forecast_solar-5.0.0/.gitattributes000066400000000000000000000001021514642402100174050ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto forecast_solar-5.0.0/.github/000077500000000000000000000000001514642402100160615ustar00rootroot00000000000000forecast_solar-5.0.0/.github/dependabot.yml000066400000000000000000000004161514642402100207120ustar00rootroot00000000000000--- 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-5.0.0/.github/labels.yml000066400000000000000000000062431514642402100200530ustar00rootroot00000000000000--- - 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-5.0.0/.github/release-drafter.yml000066400000000000000000000022411514642402100216500ustar00rootroot00000000000000--- 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-5.0.0/.github/workflows/000077500000000000000000000000001514642402100201165ustar00rootroot00000000000000forecast_solar-5.0.0/.github/workflows/linting.yaml000066400000000000000000000073201514642402100224500ustar00rootroot00000000000000--- name: Linting # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.12" jobs: ruff: name: Ruff runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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 . prek-hooks: name: prek-hooks runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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 prek run check-ast --all-files - name: ๐Ÿš€ Check for case conflicts run: poetry run prek run check-case-conflict --all-files - name: ๐Ÿš€ Check docstring is first run: poetry run prek run check-docstring-first --all-files - name: ๐Ÿš€ Check that executables have shebangs run: poetry run prek run check-executables-have-shebangs --all-files - name: ๐Ÿš€ Check JSON files run: poetry run prek run check-json --all-files - name: ๐Ÿš€ Check for merge conflicts run: poetry run prek run check-merge-conflict --all-files - name: ๐Ÿš€ Check for broken symlinks run: poetry run prek run check-symlinks --all-files - name: ๐Ÿš€ Check TOML files run: poetry run prek run check-toml --all-files - name: ๐Ÿš€ Check XML files run: poetry run prek run check-xml --all-files - name: ๐Ÿš€ Check YAML files run: poetry run prek run check-yaml --all-files - name: ๐Ÿš€ Detect Private Keys run: poetry run prek run detect-private-key --all-files - name: ๐Ÿš€ Check End of Files run: poetry run prek run end-of-file-fixer --all-files - name: ๐Ÿš€ Trim Trailing Whitespace run: poetry run prek run trailing-whitespace --all-files yamllint: name: yamllint runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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-5.0.0/.github/workflows/pr-labels.yaml000066400000000000000000000013021514642402100226570ustar00rootroot00000000000000--- 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-5.0.0/.github/workflows/release-drafter.yaml000066400000000000000000000006771514642402100240610ustar00rootroot00000000000000--- 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.2.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} forecast_solar-5.0.0/.github/workflows/release.yaml000066400000000000000000000024601514642402100224240ustar00rootroot00000000000000--- name: Release # yamllint disable rule:line-length # yamllint disable-line rule:truthy on: release: types: - published env: DEFAULT_PYTHON: "3.12" 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@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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.13.0 forecast_solar-5.0.0/.github/workflows/sync-labels.yml000066400000000000000000000010141514642402100230510ustar00rootroot00000000000000--- 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@v6.0.2 - name: ๐Ÿš€ Run Label Syncer uses: micnncim/action-label-syncer@v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} forecast_solar-5.0.0/.github/workflows/tests.yaml000066400000000000000000000042051514642402100221450ustar00rootroot00000000000000--- name: Testing # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.12" jobs: pytest: name: Python ${{ matrix.python }} runs-on: ubuntu-latest strategy: matrix: python: ["3.12", "3.13", "3.14"] steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ matrix.python }} id: python uses: actions/setup-python@v6.2.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@v6.0.0 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@v6.0.2 with: fetch-depth: 0 - name: โฌ‡๏ธ Download coverage data uses: actions/download-artifact@v7.0.0 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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.5.2 with: token: ${{ secrets.CODECOV_TOKEN }} fail_ci_if_error: true forecast_solar-5.0.0/.github/workflows/typing.yaml000066400000000000000000000015711514642402100223200ustar00rootroot00000000000000--- name: Typing # yamllint disable-line rule:truthy on: push: pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.12" jobs: ty: name: ty runs-on: ubuntu-latest steps: - name: โคต๏ธ Check out code from GitHub uses: actions/checkout@v6.0.2 - name: ๐Ÿ— Set up Poetry run: pipx install poetry - name: ๐Ÿ— Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v6.2.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 ty run: poetry run ty check examples src tests forecast_solar-5.0.0/.gitignore000066400000000000000000000032361514642402100165150ustar00rootroot00000000000000# 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-5.0.0/.pre-commit-config.yaml000066400000000000000000000067741514642402100210200ustar00rootroot00000000000000--- repos: - repo: local hooks: - id: ruff-check name: ๐Ÿถ Ruff Linter language: system types: [python] entry: poetry run ruff check --fix require_serial: true stages: [commit, push, manual] - id: ruff-format name: ๐Ÿถ Ruff Formatter language: system types: [python] entry: poetry run ruff format require_serial: true stages: [commit, 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: [commit, 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: [commit, push, manual] - id: ty name: ๐Ÿ†Ž Static type checking using ty language: system types: [python] entry: poetry run ty check - 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: [commit, push, manual] - id: yamllint name: ๐ŸŽ— Check YAML files with yamllint language: system types: [yaml] entry: poetry run yamllint forecast_solar-5.0.0/.yamllint000066400000000000000000000024041514642402100163530ustar00rootroot00000000000000--- 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-5.0.0/CONTRIBUTING.md000066400000000000000000000022311514642402100167500ustar00rootroot00000000000000# 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-5.0.0/LICENSE000066400000000000000000000020651514642402100155310ustar00rootroot00000000000000# MIT License Copyright (c) 2021-2026 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-5.0.0/README.md000066400000000000000000000226661514642402100160140ustar00rootroot00000000000000 ## 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()) ``` ### Multiple Planes If you have solar panels facing different directions, you can specify multiple planes. **Note:** Using multiple planes requires both an API key and a Personal Plus (or higher) subscription. If no API key is provided, additional planes will be silently ignored. See the [subscription plan overview][forecast-subscription] for more information. ```python import asyncio from forecast_solar import ForecastSolar, Plane async def main() -> None: """Show example with multiple planes.""" async with ForecastSolar( api_key="YOUR_API_KEY", latitude=52.16, longitude=4.47, # First plane (primary) declination=20, azimuth=10, kwp=2.160, # Additional planes planes=[ Plane(declination=30, azimuth=-90, kwp=1.5), # Second plane Plane(declination=25, azimuth=90, kwp=1.0), # Third plane ], ) as forecast: estimate = await forecast.estimate() 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) | | `planes` | `list[Plane]` | A list of additional Plane objects for multi-plane setups. Only used when an API key is provided (optional) | ## Plane object | Parameter | value type | Description | | --------- | ---------- | ----------- | | `declination` | `float` | The tilt of the solar panels (required) | | `azimuth` | `float` | The direction the solar panels are facing (required) | | `kwp` | `float` | The size of the solar panels in kWp (required) | ## 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.12+ - [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_. ### Prek This repository uses the [prek][prek] framework, all changes are linted and tested with each commit. To setup the prek check, run: ```bash poetry run prek install ``` And to run all checks and tests manually, use the following command: ```bash poetry run prek 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-2026 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 [forecast-subscription]: https://doc.forecast.solar/account_models [maintenance-shield]: https://img.shields.io/maintenance/yes/2026.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 [prek]: https://github.com/j178/prek forecast_solar-5.0.0/codecov.yml000066400000000000000000000001551514642402100166670ustar00rootroot00000000000000--- comment: false coverage: status: project: default: target: 90 threshold: 10% forecast_solar-5.0.0/examples/000077500000000000000000000000001514642402100163375ustar00rootroot00000000000000forecast_solar-5.0.0/examples/estimate.py000066400000000000000000000057431514642402100205350ustar00rootroot00000000000000"""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-5.0.0/examples/planes.py000066400000000000000000000070231514642402100201750ustar00rootroot00000000000000"""Example of how to use multiple planes with the Forecast.Solar API.""" import asyncio from datetime import UTC, datetime, timedelta from pprint import pprint # noqa: F401 from forecast_solar import ForecastSolar, ForecastSolarRatelimitError, Plane async def main() -> None: """Get an estimate from the Forecast.Solar API using multiple planes. This example demonstrates how to configure multiple solar panel arrays (planes) with different orientations. Using multiple planes requires both an API key and a Personal Plus or higher subscription. """ async with ForecastSolar( api_key="your-api-key", # API key is required for multiple planes latitude=52.16, longitude=4.47, # First plane configuration (main roof) declination=20, azimuth=10, kwp=2.160, # Additional planes (e.g., garage roof, secondary array) planes=[ Plane(declination=30, azimuth=-90, kwp=1.5), # West-facing plane Plane(declination=30, azimuth=90, kwp=1.5), # East-facing plane ], ) 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-5.0.0/examples/ruff.toml000066400000000000000000000003411514642402100201740ustar00rootroot00000000000000# 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-5.0.0/poetry.lock000066400000000000000000004545571514642402100167410ustar00rootroot00000000000000# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "aiohappyeyeballs" version = "2.6.1" description = "Happy Eyeballs for asyncio" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"}, {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"}, ] [[package]] name = "aiohttp" version = "3.13.3" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7"}, {file = "aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821"}, {file = "aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455"}, {file = "aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29"}, {file = "aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11"}, {file = "aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd"}, {file = "aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c"}, {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5b6073099fb654e0a068ae678b10feff95c5cae95bbfcbfa7af669d361a8aa6b"}, {file = "aiohttp-3.13.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cb93e166e6c28716c8c6aeb5f99dfb6d5ccf482d29fe9bf9a794110e6d0ab64"}, {file = "aiohttp-3.13.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28e027cf2f6b641693a09f631759b4d9ce9165099d2b5d92af9bd4e197690eea"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3b61b7169ababd7802f9568ed96142616a9118dd2be0d1866e920e77ec8fa92a"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:80dd4c21b0f6237676449c6baaa1039abae86b91636b6c91a7f8e61c87f89540"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65d2ccb7eabee90ce0503c17716fc77226be026dcc3e65cce859a30db715025b"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b179331a481cb5529fca8b432d8d3c7001cb217513c94cd72d668d1248688a3"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d4c940f02f49483b18b079d1c27ab948721852b281f8b015c058100e9421dd1"}, {file = "aiohttp-3.13.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9444f105664c4ce47a2a7171a2418bce5b7bae45fb610f4e2c36045d85911d3"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:694976222c711d1d00ba131904beb60534f93966562f64440d0c9d41b8cdb440"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f33ed1a2bf1997a36661874b017f5c4b760f41266341af36febaf271d179f6d7"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e636b3c5f61da31a92bf0d91da83e58fdfa96f178ba682f11d24f31944cdd28c"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5d2d94f1f5fcbe40838ac51a6ab5704a6f9ea42e72ceda48de5e6b898521da51"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2be0e9ccf23e8a94f6f0650ce06042cefc6ac703d0d7ab6c7a917289f2539ad4"}, {file = "aiohttp-3.13.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9af5e68ee47d6534d36791bbe9b646d2a7c7deb6fc24d7943628edfbb3581f29"}, {file = "aiohttp-3.13.3-cp311-cp311-win32.whl", hash = "sha256:a2212ad43c0833a873d0fb3c63fa1bacedd4cf6af2fee62bf4b739ceec3ab239"}, {file = "aiohttp-3.13.3-cp311-cp311-win_amd64.whl", hash = "sha256:642f752c3eb117b105acbd87e2c143de710987e09860d674e068c4c2c441034f"}, {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c"}, {file = "aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168"}, {file = "aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc"}, {file = "aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce"}, {file = "aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a"}, {file = "aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046"}, {file = "aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57"}, {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5dff64413671b0d3e7d5918ea490bdccb97a4ad29b3f311ed423200b2203e01c"}, {file = "aiohttp-3.13.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:87b9aab6d6ed88235aa2970294f496ff1a1f9adcd724d800e9b952395a80ffd9"}, {file = "aiohttp-3.13.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:425c126c0dc43861e22cb1c14ba4c8e45d09516d0a3ae0a3f7494b79f5f233a3"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7f9120f7093c2a32d9647abcaf21e6ad275b4fbec5b55969f978b1a97c7c86bf"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:697753042d57f4bf7122cab985bf15d0cef23c770864580f5af4f52023a56bd6"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6de499a1a44e7de70735d0b39f67c8f25eb3d91eb3103be99ca0fa882cdd987d"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:37239e9f9a7ea9ac5bf6b92b0260b01f8a22281996da609206a84df860bc1261"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f76c1e3fe7d7c8afad7ed193f89a292e1999608170dcc9751a7462a87dfd5bc0"}, {file = "aiohttp-3.13.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fc290605db2a917f6e81b0e1e0796469871f5af381ce15c604a3c5c7e51cb730"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4021b51936308aeea0367b8f006dc999ca02bc118a0cc78c303f50a2ff6afb91"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:49a03727c1bba9a97d3e93c9f93ca03a57300f484b6e935463099841261195d3"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3d9908a48eb7416dc1f4524e69f1d32e5d90e3981e4e37eb0aa1cd18f9cfa2a4"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2712039939ec963c237286113c68dbad80a82a4281543f3abf766d9d73228998"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7bfdc049127717581866fa4708791220970ce291c23e28ccf3922c700740fdc0"}, {file = "aiohttp-3.13.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8057c98e0c8472d8846b9c79f56766bcc57e3e8ac7bfd510482332366c56c591"}, {file = "aiohttp-3.13.3-cp313-cp313-win32.whl", hash = "sha256:1449ceddcdbcf2e0446957863af03ebaaa03f94c090f945411b61269e2cb5daf"}, {file = "aiohttp-3.13.3-cp313-cp313-win_amd64.whl", hash = "sha256:693781c45a4033d31d4187d2436f5ac701e7bbfe5df40d917736108c1cc7436e"}, {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:ea37047c6b367fd4bd632bff8077449b8fa034b69e812a18e0132a00fae6e808"}, {file = "aiohttp-3.13.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6fc0e2337d1a4c3e6acafda6a78a39d4c14caea625124817420abceed36e2415"}, {file = "aiohttp-3.13.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c685f2d80bb67ca8c3837823ad76196b3694b0159d232206d1e461d3d434666f"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e377758516d262bde50c2584fc6c578af272559c409eecbdd2bae1601184d6"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:34749271508078b261c4abb1767d42b8d0c0cc9449c73a4df494777dc55f0687"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:82611aeec80eb144416956ec85b6ca45a64d76429c1ed46ae1b5f86c6e0c9a26"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2fff83cfc93f18f215896e3a190e8e5cb413ce01553901aca925176e7568963a"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bbe7d4cecacb439e2e2a8a1a7b935c25b812af7a5fd26503a66dadf428e79ec1"}, {file = "aiohttp-3.13.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b928f30fe49574253644b1ca44b1b8adbd903aa0da4b9054a6c20fc7f4092a25"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b5e8fe4de30df199155baaf64f2fcd604f4c678ed20910db8e2c66dc4b11603"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:8542f41a62bcc58fc7f11cf7c90e0ec324ce44950003feb70640fc2a9092c32a"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:5e1d8c8b8f1d91cd08d8f4a3c2b067bfca6ec043d3ff36de0f3a715feeedf926"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:90455115e5da1c3c51ab619ac57f877da8fd6d73c05aacd125c5ae9819582aba"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:042e9e0bcb5fba81886c8b4fbb9a09d6b8a00245fd8d88e4d989c1f96c74164c"}, {file = "aiohttp-3.13.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2eb752b102b12a76ca02dff751a801f028b4ffbbc478840b473597fc91a9ed43"}, {file = "aiohttp-3.13.3-cp314-cp314-win32.whl", hash = "sha256:b556c85915d8efaed322bf1bdae9486aa0f3f764195a0fb6ee962e5c71ef5ce1"}, {file = "aiohttp-3.13.3-cp314-cp314-win_amd64.whl", hash = "sha256:9bf9f7a65e7aa20dd764151fb3d616c81088f91f8df39c3893a536e279b4b984"}, {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:05861afbbec40650d8a07ea324367cb93e9e8cc7762e04dd4405df99fa65159c"}, {file = "aiohttp-3.13.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2fc82186fadc4a8316768d61f3722c230e2c1dcab4200d52d2ebdf2482e47592"}, {file = "aiohttp-3.13.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0add0900ff220d1d5c5ebbf99ed88b0c1bbf87aa7e4262300ed1376a6b13414f"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:568f416a4072fbfae453dcf9a99194bbb8bdeab718e08ee13dfa2ba0e4bebf29"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:add1da70de90a2569c5e15249ff76a631ccacfe198375eead4aadf3b8dc849dc"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:10b47b7ba335d2e9b1239fa571131a87e2d8ec96b333e68b2a305e7a98b0bae2"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4dce1c718e38081c8f35f323209d4c1df7d4db4bab1b5c88a6b4d12b74587"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34bac00a67a812570d4a460447e1e9e06fae622946955f939051e7cc895cfab8"}, {file = "aiohttp-3.13.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19884d2ee70b06d9204b2727a7b9f983d0c684c650254679e716b0b77920632"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5f8ca7f2bb6ba8348a3614c7918cc4bb73268c5ac2a207576b7afea19d3d9f64"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b0d95340658b9d2f11d9697f59b3814a9d3bb4b7a7c20b131df4bcef464037c0"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:a1e53262fd202e4b40b70c3aff944a8155059beedc8a89bba9dc1f9ef06a1b56"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d60ac9663f44168038586cab2157e122e46bdef09e9368b37f2d82d354c23f72"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:90751b8eed69435bac9ff4e3d2f6b3af1f57e37ecb0fbeee59c0174c9e2d41df"}, {file = "aiohttp-3.13.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fc353029f176fd2b3ec6cfc71be166aba1936fe5d73dd1992ce289ca6647a9aa"}, {file = "aiohttp-3.13.3-cp314-cp314t-win32.whl", hash = "sha256:2e41b18a58da1e474a057b3d35248d8320029f61d70a37629535b16a0c8f3767"}, {file = "aiohttp-3.13.3-cp314-cp314t-win_amd64.whl", hash = "sha256:44531a36aa2264a1860089ffd4dce7baf875ee5a6079d5fb42e261c704ef7344"}, {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:31a83ea4aead760dfcb6962efb1d861db48c34379f2ff72db9ddddd4cda9ea2e"}, {file = "aiohttp-3.13.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:988a8c5e317544fdf0d39871559e67b6341065b87fceac641108c2096d5506b7"}, {file = "aiohttp-3.13.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b174f267b5cfb9a7dba9ee6859cecd234e9a681841eb85068059bc867fb8f02"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:947c26539750deeaee933b000fb6517cc770bbd064bad6033f1cff4803881e43"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9ebf57d09e131f5323464bd347135a88622d1c0976e88ce15b670e7ad57e4bd6"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4ae5b5a0e1926e504c81c5b84353e7a5516d8778fbbff00429fe7b05bb25cbce"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ba0eea45eb5cc3172dbfc497c066f19c41bac70963ea1a67d51fc92e4cf9a80"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bae5c2ed2eae26cc382020edad80d01f36cb8e746da40b292e68fec40421dc6a"}, {file = "aiohttp-3.13.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a60e60746623925eab7d25823329941aee7242d559baa119ca2b253c88a7bd6"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e50a2e1404f063427c9d027378472316201a2290959a295169bcf25992d04558"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:9a9dc347e5a3dc7dfdbc1f82da0ef29e388ddb2ed281bfce9dd8248a313e62b7"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b46020d11d23fe16551466c77823df9cc2f2c1e63cc965daf67fa5eec6ca1877"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:69c56fbc1993fa17043e24a546959c0178fe2b5782405ad4559e6c13975c15e3"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:b99281b0704c103d4e11e72a76f1b543d4946fea7dd10767e7e1b5f00d4e5704"}, {file = "aiohttp-3.13.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:40c5e40ecc29ba010656c18052b877a1c28f84344825efa106705e835c28530f"}, {file = "aiohttp-3.13.3-cp39-cp39-win32.whl", hash = "sha256:56339a36b9f1fc708260c76c87e593e2afb30d26de9ae1eb445b5e051b98a7a1"}, {file = "aiohttp-3.13.3-cp39-cp39-win_amd64.whl", hash = "sha256:c6b8568a3bb5819a0ad087f16d40e5a3fb6099f39ea1d5625a3edc1e923fc538"}, {file = "aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88"}, ] [package.dependencies] aiohappyeyeballs = ">=2.5.0" aiosignal = ">=1.4.0" 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 (>=1.2) ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "backports.zstd ; platform_python_implementation == \"CPython\" and python_version < \"3.14\"", "brotlicffi (>=1.2) ; platform_python_implementation != \"CPython\""] [[package]] name = "aiosignal" version = "1.4.0" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"}, {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"}, ] [package.dependencies] frozenlist = ">=1.1.0" typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""} [[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,<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 = "25.4.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373"}, {file = "attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11"}, ] [[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.13.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "coverage-7.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f4af3b01763909f477ea17c962e2cca8f39b350a4e46e3a30838b2c12e31b81b"}, {file = "coverage-7.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:36393bd2841fa0b59498f75466ee9bdec4f770d3254f031f23e8fd8e140ffdd2"}, {file = "coverage-7.13.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:9cc7573518b7e2186bd229b1a0fe24a807273798832c27032c4510f47ffdb896"}, {file = "coverage-7.13.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca9566769b69a5e216a4e176d54b9df88f29d750c5b78dbb899e379b4e14b30c"}, {file = "coverage-7.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c9bdea644e94fd66d75a6f7e9a97bb822371e1fe7eadae2cacd50fcbc28e4dc"}, {file = "coverage-7.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5bd447332ec4f45838c1ad42268ce21ca87c40deb86eabd59888859b66be22a5"}, {file = "coverage-7.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7c79ad5c28a16a1277e1187cf83ea8dafdcc689a784228a7d390f19776db7c31"}, {file = "coverage-7.13.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:76e06ccacd1fb6ada5d076ed98a8c6f66e2e6acd3df02819e2ee29fd637b76ad"}, {file = "coverage-7.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:49d49e9a5e9f4dc3d3dac95278a020afa6d6bdd41f63608a76fa05a719d5b66f"}, {file = "coverage-7.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed2bce0e7bfa53f7b0b01c722da289ef6ad4c18ebd52b1f93704c21f116360c8"}, {file = "coverage-7.13.2-cp310-cp310-win32.whl", hash = "sha256:1574983178b35b9af4db4a9f7328a18a14a0a0ce76ffaa1c1bacb4cc82089a7c"}, {file = "coverage-7.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:a360a8baeb038928ceb996f5623a4cd508728f8f13e08d4e96ce161702f3dd99"}, {file = "coverage-7.13.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:060ebf6f2c51aff5ba38e1f43a2095e087389b1c69d559fde6049a4b0001320e"}, {file = "coverage-7.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1ea8ca9db5e7469cd364552985e15911548ea5b69c48a17291f0cac70484b2e"}, {file = "coverage-7.13.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b780090d15fd58f07cf2011943e25a5f0c1c894384b13a216b6c86c8a8a7c508"}, {file = "coverage-7.13.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:88a800258d83acb803c38175b4495d293656d5fac48659c953c18e5f539a274b"}, {file = "coverage-7.13.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6326e18e9a553e674d948536a04a80d850a5eeefe2aae2e6d7cf05d54046c01b"}, {file = "coverage-7.13.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:59562de3f797979e1ff07c587e2ac36ba60ca59d16c211eceaa579c266c5022f"}, {file = "coverage-7.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:27ba1ed6f66b0e2d61bfa78874dffd4f8c3a12f8e2b5410e515ab345ba7bc9c3"}, {file = "coverage-7.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8be48da4d47cc68754ce643ea50b3234557cbefe47c2f120495e7bd0a2756f2b"}, {file = "coverage-7.13.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:2a47a4223d3361b91176aedd9d4e05844ca67d7188456227b6bf5e436630c9a1"}, {file = "coverage-7.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c6f141b468740197d6bd38f2b26ade124363228cc3f9858bd9924ab059e00059"}, {file = "coverage-7.13.2-cp311-cp311-win32.whl", hash = "sha256:89567798404af067604246e01a49ef907d112edf2b75ef814b1364d5ce267031"}, {file = "coverage-7.13.2-cp311-cp311-win_amd64.whl", hash = "sha256:21dd57941804ae2ac7e921771a5e21bbf9aabec317a041d164853ad0a96ce31e"}, {file = "coverage-7.13.2-cp311-cp311-win_arm64.whl", hash = "sha256:10758e0586c134a0bafa28f2d37dd2cdb5e4a90de25c0fc0c77dabbad46eca28"}, {file = "coverage-7.13.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f106b2af193f965d0d3234f3f83fc35278c7fb935dfbde56ae2da3dd2c03b84d"}, {file = "coverage-7.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f45d21dc4d5d6bd29323f0320089ef7eae16e4bef712dff79d184fa7330af3"}, {file = "coverage-7.13.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fae91dfecd816444c74531a9c3d6ded17a504767e97aa674d44f638107265b99"}, {file = "coverage-7.13.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:264657171406c114787b441484de620e03d8f7202f113d62fcd3d9688baa3e6f"}, {file = "coverage-7.13.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae47d8dcd3ded0155afbb59c62bd8ab07ea0fd4902e1c40567439e6db9dcaf2f"}, {file = "coverage-7.13.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8a0b33e9fd838220b007ce8f299114d406c1e8edb21336af4c97a26ecfd185aa"}, {file = "coverage-7.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b3becbea7f3ce9a2d4d430f223ec15888e4deb31395840a79e916368d6004cce"}, {file = "coverage-7.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f819c727a6e6eeb8711e4ce63d78c620f69630a2e9d53bc95ca5379f57b6ba94"}, {file = "coverage-7.13.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4f7b71757a3ab19f7ba286e04c181004c1d61be921795ee8ba6970fd0ec91da5"}, {file = "coverage-7.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b7fc50d2afd2e6b4f6f2f403b70103d280a8e0cb35320cbbe6debcda02a1030b"}, {file = "coverage-7.13.2-cp312-cp312-win32.whl", hash = "sha256:292250282cf9bcf206b543d7608bda17ca6fc151f4cbae949fc7e115112fbd41"}, {file = "coverage-7.13.2-cp312-cp312-win_amd64.whl", hash = "sha256:eeea10169fac01549a7921d27a3e517194ae254b542102267bef7a93ed38c40e"}, {file = "coverage-7.13.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a5b567f0b635b592c917f96b9a9cb3dbd4c320d03f4bf94e9084e494f2e8894"}, {file = "coverage-7.13.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed75de7d1217cf3b99365d110975f83af0528c849ef5180a12fd91b5064df9d6"}, {file = "coverage-7.13.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97e596de8fa9bada4d88fde64a3f4d37f1b6131e4faa32bad7808abc79887ddc"}, {file = "coverage-7.13.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:68c86173562ed4413345410c9480a8d64864ac5e54a5cda236748031e094229f"}, {file = "coverage-7.13.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7be4d613638d678b2b3773b8f687537b284d7074695a43fe2fbbfc0e31ceaed1"}, {file = "coverage-7.13.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d7f63ce526a96acd0e16c4af8b50b64334239550402fb1607ce6a584a6d62ce9"}, {file = "coverage-7.13.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:406821f37f864f968e29ac14c3fccae0fec9fdeba48327f0341decf4daf92d7c"}, {file = "coverage-7.13.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ee68e5a4e3e5443623406b905db447dceddffee0dceb39f4e0cd9ec2a35004b5"}, {file = "coverage-7.13.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2ee0e58cca0c17dd9c6c1cdde02bb705c7b3fbfa5f3b0b5afeda20d4ebff8ef4"}, {file = "coverage-7.13.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:6e5bbb5018bf76a56aabdb64246b5288d5ae1b7d0dd4d0534fe86df2c2992d1c"}, {file = "coverage-7.13.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a55516c68ef3e08e134e818d5e308ffa6b1337cc8b092b69b24287bf07d38e31"}, {file = "coverage-7.13.2-cp313-cp313-win32.whl", hash = "sha256:5b20211c47a8abf4abc3319d8ce2464864fa9f30c5fcaf958a3eed92f4f1fef8"}, {file = "coverage-7.13.2-cp313-cp313-win_amd64.whl", hash = "sha256:14f500232e521201cf031549fb1ebdfc0a40f401cf519157f76c397e586c3beb"}, {file = "coverage-7.13.2-cp313-cp313-win_arm64.whl", hash = "sha256:9779310cb5a9778a60c899f075a8514c89fa6d10131445c2207fc893e0b14557"}, {file = "coverage-7.13.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:e64fa5a1e41ce5df6b547cbc3d3699381c9e2c2c369c67837e716ed0f549d48e"}, {file = "coverage-7.13.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b01899e82a04085b6561eb233fd688474f57455e8ad35cd82286463ba06332b7"}, {file = "coverage-7.13.2-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:838943bea48be0e2768b0cf7819544cdedc1bbb2f28427eabb6eb8c9eb2285d3"}, {file = "coverage-7.13.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:93d1d25ec2b27e90bcfef7012992d1f5121b51161b8bffcda756a816cf13c2c3"}, {file = "coverage-7.13.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93b57142f9621b0d12349c43fc7741fe578e4bc914c1e5a54142856cfc0bf421"}, {file = "coverage-7.13.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f06799ae1bdfff7ccb8665d75f8291c69110ba9585253de254688aa8a1ccc6c5"}, {file = "coverage-7.13.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f9405ab4f81d490811b1d91c7a20361135a2df4c170e7f0b747a794da5b7f23"}, {file = "coverage-7.13.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:f9ab1d5b86f8fbc97a5b3cd6280a3fd85fef3b028689d8a2c00918f0d82c728c"}, {file = "coverage-7.13.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:f674f59712d67e841525b99e5e2b595250e39b529c3bda14764e4f625a3fa01f"}, {file = "coverage-7.13.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c6cadac7b8ace1ba9144feb1ae3cb787a6065ba6d23ffc59a934b16406c26573"}, {file = "coverage-7.13.2-cp313-cp313t-win32.whl", hash = "sha256:14ae4146465f8e6e6253eba0cccd57423e598a4cb925958b240c805300918343"}, {file = "coverage-7.13.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9074896edd705a05769e3de0eac0a8388484b503b68863dd06d5e473f874fd47"}, {file = "coverage-7.13.2-cp313-cp313t-win_arm64.whl", hash = "sha256:69e526e14f3f854eda573d3cf40cffd29a1a91c684743d904c33dbdcd0e0f3e7"}, {file = "coverage-7.13.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:387a825f43d680e7310e6f325b2167dd093bc8ffd933b83e9aa0983cf6e0a2ef"}, {file = "coverage-7.13.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f0d7fea9d8e5d778cd5a9e8fc38308ad688f02040e883cdc13311ef2748cb40f"}, {file = "coverage-7.13.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:e080afb413be106c95c4ee96b4fffdc9e2fa56a8bbf90b5c0918e5c4449412f5"}, {file = "coverage-7.13.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a7fc042ba3c7ce25b8a9f097eb0f32a5ce1ccdb639d9eec114e26def98e1f8a4"}, {file = "coverage-7.13.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d0ba505e021557f7f8173ee8cd6b926373d8653e5ff7581ae2efce1b11ef4c27"}, {file = "coverage-7.13.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7de326f80e3451bd5cc7239ab46c73ddb658fe0b7649476bc7413572d36cd548"}, {file = "coverage-7.13.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:abaea04f1e7e34841d4a7b343904a3f59481f62f9df39e2cd399d69a187a9660"}, {file = "coverage-7.13.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9f93959ee0c604bccd8e0697be21de0887b1f73efcc3aa73a3ec0fd13feace92"}, {file = "coverage-7.13.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:13fe81ead04e34e105bf1b3c9f9cdf32ce31736ee5d90a8d2de02b9d3e1bcb82"}, {file = "coverage-7.13.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d6d16b0f71120e365741bca2cb473ca6fe38930bc5431c5e850ba949f708f892"}, {file = "coverage-7.13.2-cp314-cp314-win32.whl", hash = "sha256:9b2f4714bb7d99ba3790ee095b3b4ac94767e1347fe424278a0b10acb3ff04fe"}, {file = "coverage-7.13.2-cp314-cp314-win_amd64.whl", hash = "sha256:e4121a90823a063d717a96e0a0529c727fb31ea889369a0ee3ec00ed99bf6859"}, {file = "coverage-7.13.2-cp314-cp314-win_arm64.whl", hash = "sha256:6873f0271b4a15a33e7590f338d823f6f66f91ed147a03938d7ce26efd04eee6"}, {file = "coverage-7.13.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f61d349f5b7cd95c34017f1927ee379bfbe9884300d74e07cf630ccf7a610c1b"}, {file = "coverage-7.13.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a43d34ce714f4ca674c0d90beb760eb05aad906f2c47580ccee9da8fe8bfb417"}, {file = "coverage-7.13.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bff1b04cb9d4900ce5c56c4942f047dc7efe57e2608cb7c3c8936e9970ccdbee"}, {file = "coverage-7.13.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6ae99e4560963ad8e163e819e5d77d413d331fd00566c1e0856aa252303552c1"}, {file = "coverage-7.13.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e79a8c7d461820257d9aa43716c4efc55366d7b292e46b5b37165be1d377405d"}, {file = "coverage-7.13.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:060ee84f6a769d40c492711911a76811b4befb6fba50abb450371abb720f5bd6"}, {file = "coverage-7.13.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bca209d001fd03ea2d978f8a4985093240a355c93078aee3f799852c23f561a"}, {file = "coverage-7.13.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:6b8092aa38d72f091db61ef83cb66076f18f02da3e1a75039a4f218629600e04"}, {file = "coverage-7.13.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4a3158dc2dcce5200d91ec28cd315c999eebff355437d2765840555d765a6e5f"}, {file = "coverage-7.13.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3973f353b2d70bd9796cc12f532a05945232ccae966456c8ed7034cb96bbfd6f"}, {file = "coverage-7.13.2-cp314-cp314t-win32.whl", hash = "sha256:79f6506a678a59d4ded048dc72f1859ebede8ec2b9a2d509ebe161f01c2879d3"}, {file = "coverage-7.13.2-cp314-cp314t-win_amd64.whl", hash = "sha256:196bfeabdccc5a020a57d5a368c681e3a6ceb0447d153aeccc1ab4d70a5032ba"}, {file = "coverage-7.13.2-cp314-cp314t-win_arm64.whl", hash = "sha256:69269ab58783e090bfbf5b916ab3d188126e22d6070bbfc93098fdd474ef937c"}, {file = "coverage-7.13.2-py3-none-any.whl", hash = "sha256:40ce1ea1e25125556d8e76bd0b61500839a07944cc287ac21d5626f3e620cad5"}, {file = "coverage-7.13.2.tar.gz", hash = "sha256:044c6951ec37146b72a50cc81ef02217d27d4c3640efd2640311393cbbf143d3"}, ] [package.extras] toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "freezegun" version = "1.5.5" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "freezegun-1.5.5-py3-none-any.whl", hash = "sha256:cd557f4a75cf074e84bc374249b9dd491eaeacd61376b9eb3c423282211619d2"}, {file = "freezegun-1.5.5.tar.gz", hash = "sha256:ac7742a6cc6c25a2c35e9292dfd554b897b517d2dec26891a2e8debf205cb94a"}, ] [package.dependencies] python-dateutil = ">=2.7" [[package]] name = "frozenlist" version = "1.8.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011"}, {file = "frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565"}, {file = "frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad"}, {file = "frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2"}, {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186"}, {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e"}, {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450"}, {file = "frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef"}, {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4"}, {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff"}, {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c"}, {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f"}, {file = "frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7"}, {file = "frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a"}, {file = "frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6"}, {file = "frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e"}, {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84"}, {file = "frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9"}, {file = "frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93"}, {file = "frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f"}, {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695"}, {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52"}, {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581"}, {file = "frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567"}, {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b"}, {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92"}, {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d"}, {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd"}, {file = "frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967"}, {file = "frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25"}, {file = "frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b"}, {file = "frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a"}, {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1"}, {file = "frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b"}, {file = "frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4"}, {file = "frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383"}, {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4"}, {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8"}, {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b"}, {file = "frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52"}, {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29"}, {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3"}, {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143"}, {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608"}, {file = "frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa"}, {file = "frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf"}, {file = "frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746"}, {file = "frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd"}, {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a"}, {file = "frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7"}, {file = "frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40"}, {file = "frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027"}, {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822"}, {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121"}, {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5"}, {file = "frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e"}, {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11"}, {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1"}, {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1"}, {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8"}, {file = "frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed"}, {file = "frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496"}, {file = "frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231"}, {file = "frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62"}, {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94"}, {file = "frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c"}, {file = "frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52"}, {file = "frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51"}, {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65"}, {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82"}, {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714"}, {file = "frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d"}, {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506"}, {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51"}, {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e"}, {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0"}, {file = "frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41"}, {file = "frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b"}, {file = "frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888"}, {file = "frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042"}, {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0"}, {file = "frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f"}, {file = "frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c"}, {file = "frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2"}, {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8"}, {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686"}, {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e"}, {file = "frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a"}, {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128"}, {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f"}, {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7"}, {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30"}, {file = "frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7"}, {file = "frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806"}, {file = "frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0"}, {file = "frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b"}, {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d"}, {file = "frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed"}, {file = "frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930"}, {file = "frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c"}, {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24"}, {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37"}, {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a"}, {file = "frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2"}, {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef"}, {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe"}, {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8"}, {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a"}, {file = "frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e"}, {file = "frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df"}, {file = "frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd"}, {file = "frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79"}, {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d8b7138e5cd0647e4523d6685b0eac5d4be9a184ae9634492f25c6eb38c12a47"}, {file = "frozenlist-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a6483e309ca809f1efd154b4d37dc6d9f61037d6c6a81c2dc7a15cb22c8c5dca"}, {file = "frozenlist-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1b9290cf81e95e93fdf90548ce9d3c1211cf574b8e3f4b3b7cb0537cf2227068"}, {file = "frozenlist-1.8.0-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:59a6a5876ca59d1b63af8cd5e7ffffb024c3dc1e9cf9301b21a2e76286505c95"}, {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dc4126390929823e2d2d9dc79ab4046ed74680360fc5f38b585c12c66cdf459"}, {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:332db6b2563333c5671fecacd085141b5800cb866be16d5e3eb15a2086476675"}, {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9ff15928d62a0b80bb875655c39bf517938c7d589554cbd2669be42d97c2cb61"}, {file = "frozenlist-1.8.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7bf6cdf8e07c8151fba6fe85735441240ec7f619f935a5205953d58009aef8c6"}, {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:48e6d3f4ec5c7273dfe83ff27c91083c6c9065af655dc2684d2c200c94308bb5"}, {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:1a7607e17ad33361677adcd1443edf6f5da0ce5e5377b798fba20fae194825f3"}, {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3a935c3a4e89c733303a2d5a7c257ea44af3a56c8202df486b7f5de40f37e1"}, {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:940d4a017dbfed9daf46a3b086e1d2167e7012ee297fef9e1c545c4d022f5178"}, {file = "frozenlist-1.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b9be22a69a014bc47e78072d0ecae716f5eb56c15238acca0f43d6eb8e4a5bda"}, {file = "frozenlist-1.8.0-cp39-cp39-win32.whl", hash = "sha256:1aa77cb5697069af47472e39612976ed05343ff2e84a3dcf15437b232cbfd087"}, {file = "frozenlist-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:7398c222d1d405e796970320036b1b563892b65809d9e5261487bb2c7f7b5c6a"}, {file = "frozenlist-1.8.0-cp39-cp39-win_arm64.whl", hash = "sha256:b4f3b365f31c6cd4af24545ca0a244a53688cad8834e32f56831c4923b50a103"}, {file = "frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d"}, {file = "frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad"}, ] [[package]] name = "idna" version = "3.11" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.8" groups = ["main", "dev"] files = [ {file = "idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea"}, {file = "idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902"}, ] [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] [[package]] name = "iniconfig" version = "2.3.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12"}, {file = "iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730"}, ] [[package]] name = "multidict" version = "6.7.1" description = "multidict implementation" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5"}, {file = "multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8"}, {file = "multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872"}, {file = "multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991"}, {file = "multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03"}, {file = "multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981"}, {file = "multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6"}, {file = "multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190"}, {file = "multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962"}, {file = "multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505"}, {file = "multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122"}, {file = "multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df"}, {file = "multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db"}, {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d"}, {file = "multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e"}, {file = "multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855"}, {file = "multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3"}, {file = "multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e"}, {file = "multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a"}, {file = "multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8"}, {file = "multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0"}, {file = "multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0"}, {file = "multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa"}, {file = "multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a"}, {file = "multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b"}, {file = "multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6"}, {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172"}, {file = "multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd"}, {file = "multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7"}, {file = "multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53"}, {file = "multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75"}, {file = "multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b"}, {file = "multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733"}, {file = "multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a"}, {file = "multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a"}, {file = "multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba"}, {file = "multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511"}, {file = "multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19"}, {file = "multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf"}, {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23"}, {file = "multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2"}, {file = "multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445"}, {file = "multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177"}, {file = "multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23"}, {file = "multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060"}, {file = "multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d"}, {file = "multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed"}, {file = "multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d"}, {file = "multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33"}, {file = "multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3"}, {file = "multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5"}, {file = "multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df"}, {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1"}, {file = "multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963"}, {file = "multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd"}, {file = "multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52"}, {file = "multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108"}, {file = "multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32"}, {file = "multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8"}, {file = "multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118"}, {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee"}, {file = "multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2"}, {file = "multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1"}, {file = "multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d"}, {file = "multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31"}, {file = "multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048"}, {file = "multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362"}, {file = "multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37"}, {file = "multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1"}, {file = "multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b"}, {file = "multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d"}, {file = "multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f"}, {file = "multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5"}, {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581"}, {file = "multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a"}, {file = "multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d"}, {file = "multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9"}, {file = "multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2"}, {file = "multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7"}, {file = "multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5"}, {file = "multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2"}, {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:65573858d27cdeaca41893185677dc82395159aa28875a8867af66532d413a8f"}, {file = "multidict-6.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c524c6fb8fc342793708ab111c4dbc90ff9abd568de220432500e47e990c0358"}, {file = "multidict-6.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:aa23b001d968faef416ff70dc0f1ab045517b9b42a90edd3e9bcdb06479e31d5"}, {file = "multidict-6.7.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:6704fa2b7453b2fb121740555fa1ee20cd98c4d011120caf4d2b8d4e7c76eec0"}, {file = "multidict-6.7.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:121a34e5bfa410cdf2c8c49716de160de3b1dbcd86b49656f5681e4543bcd1a8"}, {file = "multidict-6.7.1-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:026d264228bcd637d4e060844e39cdc60f86c479e463d49075dedc21b18fbbe0"}, {file = "multidict-6.7.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e697826df7eb63418ee190fd06ce9f1803593bb4b9517d08c60d9b9a7f69d8f"}, {file = "multidict-6.7.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bb08271280173720e9fea9ede98e5231defcbad90f1624bea26f32ec8a956e2f"}, {file = "multidict-6.7.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c6b3228e1d80af737b72925ce5fb4daf5a335e49cd7ab77ed7b9fdfbf58c526e"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3943debf0fbb57bdde5901695c11094a9a36723e5c03875f87718ee15ca2f4d2"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:98c5787b0a0d9a41d9311eae44c3b76e6753def8d8870ab501320efe75a6a5f8"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:08ccb2a6dc72009093ebe7f3f073e5ec5964cba9a706fa94b1a1484039b87941"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb351f72c26dc9abe338ca7294661aa22969ad8ffe7ef7d5541d19f368dc854a"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ac1c665bad8b5d762f5f85ebe4d94130c26965f11de70c708c75671297c776de"}, {file = "multidict-6.7.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fa6609d0364f4f6f58351b4659a1f3e0e898ba2a8c5cac04cb2c7bc556b0bc5"}, {file = "multidict-6.7.1-cp39-cp39-win32.whl", hash = "sha256:6f77ce314a29263e67adadc7e7c1bc699fcb3a305059ab973d038f87caa42ed0"}, {file = "multidict-6.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:f537b55778cd3cbee430abe3131255d3a78202e0f9ea7ffc6ada893a4bcaeea4"}, {file = "multidict-6.7.1-cp39-cp39-win_arm64.whl", hash = "sha256:749aa54f578f2e5f439538706a475aa844bfa8ef75854b1401e6e528e4937cf9"}, {file = "multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56"}, {file = "multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d"}, ] [[package]] name = "packaging" version = "26.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] [[package]] name = "pathspec" version = "1.0.3" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pathspec-1.0.3-py3-none-any.whl", hash = "sha256:e80767021c1cc524aa3fb14bedda9c34406591343cc42797b386ce7b9354fb6c"}, {file = "pathspec-1.0.3.tar.gz", hash = "sha256:bac5cf97ae2c2876e2d25ebb15078eb04d76e4b98921ee31c6f85ade8b59444d"}, ] [package.extras] hyperscan = ["hyperscan (>=0.7)"] optional = ["typing-extensions (>=4)"] re2 = ["google-re2 (>=1.1)"] tests = ["pytest (>=9)", "typing-extensions (>=4.15)"] [[package]] name = "pluggy" version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pre-commit-hooks" version = "6.0.0" description = "Some out-of-the-box hooks for pre-commit." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pre_commit_hooks-6.0.0-py2.py3-none-any.whl", hash = "sha256:76161b76d321d2f8ee2a8e0b84c30ee8443e01376121fd1c90851e33e3bd7ee2"}, {file = "pre_commit_hooks-6.0.0.tar.gz", hash = "sha256:76d8370c006f5026cdd638a397a678d26dda735a3c88137e05885a020f824034"}, ] [package.dependencies] "ruamel.yaml" = ">=0.15" [[package]] name = "prek" version = "0.3.3" description = "Better `pre-commit`, re-engineered in Rust" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "prek-0.3.3-py3-none-linux_armv6l.whl", hash = "sha256:e8629cac4bdb131be8dc6e5a337f0f76073ad34a8305f3fe2bc1ab6201ede0a4"}, {file = "prek-0.3.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4b9e819b9e4118e1e785047b1c8bd9aec7e4d836ed034cb58b7db5bcaaf49437"}, {file = "prek-0.3.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:bf29db3b5657c083eb8444c25aadeeec5167dc492e9019e188f87932f01ea50a"}, {file = "prek-0.3.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:ae09736149815b26e64a9d350ca05692bab32c2afdf2939114d3211aaad68a3e"}, {file = "prek-0.3.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:856c2b55c51703c366bb4ce81c6a91102b70573a9fc8637db2ac61c66e4565f9"}, {file = "prek-0.3.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3acdf13a018f685beaff0a71d4b0d2ccbab4eaa1aced6d08fd471c1a654183eb"}, {file = "prek-0.3.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0f035667a8bd0a77b2bfa2b2e125da8cb1793949e9eeef0d8daab7f8ac8b57fe"}, {file = "prek-0.3.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d09b2ad14332eede441d977de08eb57fb3f61226ed5fd2ceb7aadf5afcdb6794"}, {file = "prek-0.3.3-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:c0c3ffac16e37a9daba43a7e8316778f5809b70254be138761a8b5b9ef0df28e"}, {file = "prek-0.3.3-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a3dc7720b580c07c0386e17af2486a5b4bc2f6cc57034a288a614dcbc4abe555"}, {file = "prek-0.3.3-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:60e0fa15da5020a03df2ee40268145ec5b88267ec2141a205317ad4df8c992d6"}, {file = "prek-0.3.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:553515da9586d9624dc42db32b744fdb91cf62b053753037a0cadb3c2d8d82a2"}, {file = "prek-0.3.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:9512cf370e0d1496503463a4a65621480efb41b487841a9e9ff1661edf14b238"}, {file = "prek-0.3.3-py3-none-win32.whl", hash = "sha256:b2b328c7c6dc14ccdc79785348589aa39850f47baff33d8f199f2dee80ff774c"}, {file = "prek-0.3.3-py3-none-win_amd64.whl", hash = "sha256:3d7d7acf7ca8db65ba0943c52326c898f84bab0b1c26a35c87e0d177f574ca5f"}, {file = "prek-0.3.3-py3-none-win_arm64.whl", hash = "sha256:8aa87ee7628cd74482c0dd6537a3def1f162b25cd642d78b1b35dd3e81817f60"}, {file = "prek-0.3.3.tar.gz", hash = "sha256:117bd46ebeb39def24298ce021ccc73edcf697b81856fcff36d762dd56093f6f"}, ] [[package]] name = "propcache" version = "0.4.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db"}, {file = "propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8"}, {file = "propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925"}, {file = "propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21"}, {file = "propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5"}, {file = "propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db"}, {file = "propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7"}, {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4"}, {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60"}, {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f"}, {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900"}, {file = "propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c"}, {file = "propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb"}, {file = "propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37"}, {file = "propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581"}, {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:60a8fda9644b7dfd5dece8c61d8a85e271cb958075bfc4e01083c148b61a7caf"}, {file = "propcache-0.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c30b53e7e6bda1d547cabb47c825f3843a0a1a42b0496087bb58d8fedf9f41b5"}, {file = "propcache-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6918ecbd897443087a3b7cd978d56546a812517dcaaca51b49526720571fa93e"}, {file = "propcache-0.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d902a36df4e5989763425a8ab9e98cd8ad5c52c823b34ee7ef307fd50582566"}, {file = "propcache-0.4.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a9695397f85973bb40427dedddf70d8dc4a44b22f1650dd4af9eedf443d45165"}, {file = "propcache-0.4.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2bb07ffd7eaad486576430c89f9b215f9e4be68c4866a96e97db9e97fead85dc"}, {file = "propcache-0.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd6f30fdcf9ae2a70abd34da54f18da086160e4d7d9251f81f3da0ff84fc5a48"}, {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fc38cba02d1acba4e2869eef1a57a43dfbd3d49a59bf90dda7444ec2be6a5570"}, {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:67fad6162281e80e882fb3ec355398cf72864a54069d060321f6cd0ade95fe85"}, {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f10207adf04d08bec185bae14d9606a1444715bc99180f9331c9c02093e1959e"}, {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e9b0d8d0845bbc4cfcdcbcdbf5086886bc8157aa963c31c777ceff7846c77757"}, {file = "propcache-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:981333cb2f4c1896a12f4ab92a9cc8f09ea664e9b7dbdc4eff74627af3a11c0f"}, {file = "propcache-0.4.1-cp311-cp311-win32.whl", hash = "sha256:f1d2f90aeec838a52f1c1a32fe9a619fefd5e411721a9117fbf82aea638fe8a1"}, {file = "propcache-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:364426a62660f3f699949ac8c621aad6977be7126c5807ce48c0aeb8e7333ea6"}, {file = "propcache-0.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:e53f3a38d3510c11953f3e6a33f205c6d1b001129f972805ca9b42fc308bc239"}, {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2"}, {file = "propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403"}, {file = "propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207"}, {file = "propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72"}, {file = "propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367"}, {file = "propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4"}, {file = "propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf"}, {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3"}, {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778"}, {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6"}, {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9"}, {file = "propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75"}, {file = "propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8"}, {file = "propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db"}, {file = "propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1"}, {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:43eedf29202c08550aac1d14e0ee619b0430aaef78f85864c1a892294fbc28cf"}, {file = "propcache-0.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d62cdfcfd89ccb8de04e0eda998535c406bf5e060ffd56be6c586cbcc05b3311"}, {file = "propcache-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cae65ad55793da34db5f54e4029b89d3b9b9490d8abe1b4c7ab5d4b8ec7ebf74"}, {file = "propcache-0.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:333ddb9031d2704a301ee3e506dc46b1fe5f294ec198ed6435ad5b6a085facfe"}, {file = "propcache-0.4.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd0858c20f078a32cf55f7e81473d96dcf3b93fd2ccdb3d40fdf54b8573df3af"}, {file = "propcache-0.4.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:678ae89ebc632c5c204c794f8dab2837c5f159aeb59e6ed0539500400577298c"}, {file = "propcache-0.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d472aeb4fbf9865e0c6d622d7f4d54a4e101a89715d8904282bb5f9a2f476c3f"}, {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4d3df5fa7e36b3225954fba85589da77a0fe6a53e3976de39caf04a0db4c36f1"}, {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ee17f18d2498f2673e432faaa71698032b0127ebf23ae5974eeaf806c279df24"}, {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:580e97762b950f993ae618e167e7be9256b8353c2dcd8b99ec100eb50f5286aa"}, {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:501d20b891688eb8e7aa903021f0b72d5a55db40ffaab27edefd1027caaafa61"}, {file = "propcache-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a0bd56e5b100aef69bd8562b74b46254e7c8812918d3baa700c8a8009b0af66"}, {file = "propcache-0.4.1-cp313-cp313-win32.whl", hash = "sha256:bcc9aaa5d80322bc2fb24bb7accb4a30f81e90ab8d6ba187aec0744bc302ad81"}, {file = "propcache-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:381914df18634f5494334d201e98245c0596067504b9372d8cf93f4bb23e025e"}, {file = "propcache-0.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:8873eb4460fd55333ea49b7d189749ecf6e55bf85080f11b1c4530ed3034cba1"}, {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:92d1935ee1f8d7442da9c0c4fa7ac20d07e94064184811b685f5c4fada64553b"}, {file = "propcache-0.4.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:473c61b39e1460d386479b9b2f337da492042447c9b685f28be4f74d3529e566"}, {file = "propcache-0.4.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c0ef0aaafc66fbd87842a3fe3902fd889825646bc21149eafe47be6072725835"}, {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f95393b4d66bfae908c3ca8d169d5f79cd65636ae15b5e7a4f6e67af675adb0e"}, {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c07fda85708bc48578467e85099645167a955ba093be0a2dcba962195676e859"}, {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:af223b406d6d000830c6f65f1e6431783fc3f713ba3e6cc8c024d5ee96170a4b"}, {file = "propcache-0.4.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a78372c932c90ee474559c5ddfffd718238e8673c340dc21fe45c5b8b54559a0"}, {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:564d9f0d4d9509e1a870c920a89b2fec951b44bf5ba7d537a9e7c1ccec2c18af"}, {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:17612831fda0138059cc5546f4d12a2aacfb9e47068c06af35c400ba58ba7393"}, {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:41a89040cb10bd345b3c1a873b2bf36413d48da1def52f268a055f7398514874"}, {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e35b88984e7fa64aacecea39236cee32dd9bd8c55f57ba8a75cf2399553f9bd7"}, {file = "propcache-0.4.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f8b465489f927b0df505cbe26ffbeed4d6d8a2bbc61ce90eb074ff129ef0ab1"}, {file = "propcache-0.4.1-cp313-cp313t-win32.whl", hash = "sha256:2ad890caa1d928c7c2965b48f3a3815c853180831d0e5503d35cf00c472f4717"}, {file = "propcache-0.4.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f7ee0e597f495cf415bcbd3da3caa3bd7e816b74d0d52b8145954c5e6fd3ff37"}, {file = "propcache-0.4.1-cp313-cp313t-win_arm64.whl", hash = "sha256:929d7cbe1f01bb7baffb33dc14eb5691c95831450a26354cd210a8155170c93a"}, {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3f7124c9d820ba5548d431afb4632301acf965db49e666aa21c305cbe8c6de12"}, {file = "propcache-0.4.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:c0d4b719b7da33599dfe3b22d3db1ef789210a0597bc650b7cee9c77c2be8c5c"}, {file = "propcache-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f302f4783709a78240ebc311b793f123328716a60911d667e0c036bc5dcbded"}, {file = "propcache-0.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c80ee5802e3fb9ea37938e7eecc307fb984837091d5fd262bb37238b1ae97641"}, {file = "propcache-0.4.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ed5a841e8bb29a55fb8159ed526b26adc5bdd7e8bd7bf793ce647cb08656cdf4"}, {file = "propcache-0.4.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:55c72fd6ea2da4c318e74ffdf93c4fe4e926051133657459131a95c846d16d44"}, {file = "propcache-0.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8326e144341460402713f91df60ade3c999d601e7eb5ff8f6f7862d54de0610d"}, {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:060b16ae65bc098da7f6d25bf359f1f31f688384858204fe5d652979e0015e5b"}, {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:89eb3fa9524f7bec9de6e83cf3faed9d79bffa560672c118a96a171a6f55831e"}, {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dee69d7015dc235f526fe80a9c90d65eb0039103fe565776250881731f06349f"}, {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:5558992a00dfd54ccbc64a32726a3357ec93825a418a401f5cc67df0ac5d9e49"}, {file = "propcache-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c9b822a577f560fbd9554812526831712c1436d2c046cedee4c3796d3543b144"}, {file = "propcache-0.4.1-cp314-cp314-win32.whl", hash = "sha256:ab4c29b49d560fe48b696cdcb127dd36e0bc2472548f3bf56cc5cb3da2b2984f"}, {file = "propcache-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:5a103c3eb905fcea0ab98be99c3a9a5ab2de60228aa5aceedc614c0281cf6153"}, {file = "propcache-0.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:74c1fb26515153e482e00177a1ad654721bf9207da8a494a0c05e797ad27b992"}, {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:824e908bce90fb2743bd6b59db36eb4f45cd350a39637c9f73b1c1ea66f5b75f"}, {file = "propcache-0.4.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2b5e7db5328427c57c8e8831abda175421b709672f6cfc3d630c3b7e2146393"}, {file = "propcache-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6f6ff873ed40292cd4969ef5310179afd5db59fdf055897e282485043fc80ad0"}, {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:49a2dc67c154db2c1463013594c458881a069fcf98940e61a0569016a583020a"}, {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:005f08e6a0529984491e37d8dbc3dd86f84bd78a8ceb5fa9a021f4c48d4984be"}, {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5c3310452e0d31390da9035c348633b43d7e7feb2e37be252be6da45abd1abcc"}, {file = "propcache-0.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c3c70630930447f9ef1caac7728c8ad1c56bc5015338b20fed0d08ea2480b3a"}, {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e57061305815dfc910a3634dcf584f08168a8836e6999983569f51a8544cd89"}, {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:521a463429ef54143092c11a77e04056dd00636f72e8c45b70aaa3140d639726"}, {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:120c964da3fdc75e3731aa392527136d4ad35868cc556fd09bb6d09172d9a367"}, {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:d8f353eb14ee3441ee844ade4277d560cdd68288838673273b978e3d6d2c8f36"}, {file = "propcache-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ab2943be7c652f09638800905ee1bab2c544e537edb57d527997a24c13dc1455"}, {file = "propcache-0.4.1-cp314-cp314t-win32.whl", hash = "sha256:05674a162469f31358c30bcaa8883cb7829fa3110bf9c0991fe27d7896c42d85"}, {file = "propcache-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:990f6b3e2a27d683cb7602ed6c86f15ee6b43b1194736f9baaeb93d0016633b1"}, {file = "propcache-0.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ecef2343af4cc68e05131e45024ba34f6095821988a9d0a02aa7c73fcc448aa9"}, {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3d233076ccf9e450c8b3bc6720af226b898ef5d051a2d145f7d765e6e9f9bcff"}, {file = "propcache-0.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:357f5bb5c377a82e105e44bd3d52ba22b616f7b9773714bff93573988ef0a5fb"}, {file = "propcache-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cbc3b6dfc728105b2a57c06791eb07a94229202ea75c59db644d7d496b698cac"}, {file = "propcache-0.4.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:182b51b421f0501952d938dc0b0eb45246a5b5153c50d42b495ad5fb7517c888"}, {file = "propcache-0.4.1-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4b536b39c5199b96fc6245eb5fb796c497381d3942f169e44e8e392b29c9ebcc"}, {file = "propcache-0.4.1-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:db65d2af507bbfbdcedb254a11149f894169d90488dd3e7190f7cdcb2d6cd57a"}, {file = "propcache-0.4.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fd2dbc472da1f772a4dae4fa24be938a6c544671a912e30529984dd80400cd88"}, {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:daede9cd44e0f8bdd9e6cc9a607fc81feb80fae7a5fc6cecaff0e0bb32e42d00"}, {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:71b749281b816793678ae7f3d0d84bd36e694953822eaad408d682efc5ca18e0"}, {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:0002004213ee1f36cfb3f9a42b5066100c44276b9b72b4e1504cddd3d692e86e"}, {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:fe49d0a85038f36ba9e3ffafa1103e61170b28e95b16622e11be0a0ea07c6781"}, {file = "propcache-0.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:99d43339c83aaf4d32bda60928231848eee470c6bda8d02599cc4cebe872d183"}, {file = "propcache-0.4.1-cp39-cp39-win32.whl", hash = "sha256:a129e76735bc792794d5177069691c3217898b9f5cee2b2661471e52ffe13f19"}, {file = "propcache-0.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:948dab269721ae9a87fd16c514a0a2c2a1bdb23a9a61b969b0f9d9ee2968546f"}, {file = "propcache-0.4.1-cp39-cp39-win_arm64.whl", hash = "sha256:5fd37c406dd6dc85aa743e214cef35dc54bbdd1419baac4f6ae5e5b1a2976938"}, {file = "propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237"}, {file = "propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d"}, ] [[package]] name = "pygments" version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pytest" version = "9.0.2" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b"}, {file = "pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11"}, ] [package.dependencies] colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} iniconfig = ">=1.0.1" packaging = ">=22" pluggy = ">=1.5,<2" pygments = ">=2.7.2" [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "1.3.0" description = "Pytest support for asyncio" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5"}, {file = "pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5"}, ] [package.dependencies] pytest = ">=8.2,<10" typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""} [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" version = "7.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ {file = "pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861"}, {file = "pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1"}, ] [package.dependencies] coverage = {version = ">=7.10.6", extras = ["toml"]} pluggy = ">=1.2" pytest = ">=7" [package.extras] testing = ["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.3" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3"}, {file = "PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6"}, {file = "PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369"}, {file = "PyYAML-6.0.3-cp38-cp38-win32.whl", hash = "sha256:3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295"}, {file = "PyYAML-6.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b"}, {file = "pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b"}, {file = "pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956"}, {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8"}, {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198"}, {file = "pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b"}, {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0"}, {file = "pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69"}, {file = "pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e"}, {file = "pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c"}, {file = "pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e"}, {file = "pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824"}, {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c"}, {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00"}, {file = "pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d"}, {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a"}, {file = "pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4"}, {file = "pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b"}, {file = "pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf"}, {file = "pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196"}, {file = "pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0"}, {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28"}, {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c"}, {file = "pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc"}, {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e"}, {file = "pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea"}, {file = "pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5"}, {file = "pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b"}, {file = "pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd"}, {file = "pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8"}, {file = "pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1"}, {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c"}, {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5"}, {file = "pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6"}, {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6"}, {file = "pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be"}, {file = "pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26"}, {file = "pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c"}, {file = "pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb"}, {file = "pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac"}, {file = "pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310"}, {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7"}, {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788"}, {file = "pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5"}, {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764"}, {file = "pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35"}, {file = "pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac"}, {file = "pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3"}, {file = "pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3"}, {file = "pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba"}, {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c"}, {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702"}, {file = "pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c"}, {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065"}, {file = "pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65"}, {file = "pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9"}, {file = "pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b"}, {file = "pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da"}, {file = "pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917"}, {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9"}, {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5"}, {file = "pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a"}, {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926"}, {file = "pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7"}, {file = "pyyaml-6.0.3-cp39-cp39-win32.whl", hash = "sha256:1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0"}, {file = "pyyaml-6.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007"}, {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] [[package]] name = "ruamel-yaml" version = "0.19.1" 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.9" groups = ["dev"] files = [ {file = "ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93"}, {file = "ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993"}, ] [package.extras] docs = ["mercurial (>5.7)", "ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] libyaml = ["ruamel.yaml.clibz (>=0.3.7) ; platform_python_implementation == \"CPython\""] oldlibyaml = ["ruamel.yaml.clib ; platform_python_implementation == \"CPython\""] [[package]] name = "ruff" version = "0.15.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ {file = "ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d"}, {file = "ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e"}, {file = "ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea"}, {file = "ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a"}, {file = "ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956"}, {file = "ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4"}, {file = "ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de"}, {file = "ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c"}, {file = "ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8"}, {file = "ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f"}, {file = "ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5"}, {file = "ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e"}, {file = "ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342"}, ] [[package]] name = "six" version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["dev"] files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] name = "syrupy" version = "5.1.0" description = "Pytest Snapshot Test Utility" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "syrupy-5.1.0-py3-none-any.whl", hash = "sha256:95162d2b05e61ed3e13f117b88dfab7c58bd6f90e66ebbf918e8a77114ad51c5"}, {file = "syrupy-5.1.0.tar.gz", hash = "sha256:df543c7aa50d3cf1246e83d58fe490afe5f7dab7b41e74ecc0d8d23ae19bd4b8"}, ] [package.dependencies] pytest = ">=8.0.0" [[package]] name = "ty" version = "0.0.18" description = "An extremely fast Python type checker, written in Rust." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ {file = "ty-0.0.18-py3-none-linux_armv6l.whl", hash = "sha256:4e5e91b0a79857316ef893c5068afc4b9872f9d257627d9bc8ac4d2715750d88"}, {file = "ty-0.0.18-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ee0e578b3f8416e2d5416da9553b78fd33857868aa1384cb7fefeceee5ff102d"}, {file = "ty-0.0.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3f7a0487d36b939546a91d141f7fc3dbea32fab4982f618d5b04dc9d5b6da21e"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5e2fa8d45f57ca487a470e4bf66319c09b561150e98ae2a6b1a97ef04c1a4eb"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d75652e9e937f7044b1aca16091193e7ef11dac1c7ec952b7fb8292b7ba1f5f2"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:563c868edceb8f6ddd5e91113c17d3676b028f0ed380bdb3829b06d9beb90e58"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:502e2a1f948bec563a0454fc25b074bf5cf041744adba8794d024277e151d3b0"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc881dea97021a3aa29134a476937fd8054775c4177d01b94db27fcfb7aab65b"}, {file = "ty-0.0.18-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:421fcc3bc64cab56f48edb863c7c1c43649ec4d78ff71a1acb5366ad723b6021"}, {file = "ty-0.0.18-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0fe5038a7136a0e638a2fb1ad06e3d3c4045314c6ba165c9c303b9aeb4623d6c"}, {file = "ty-0.0.18-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d123600a52372677613a719bbb780adeb9b68f47fb5f25acb09171de390e0035"}, {file = "ty-0.0.18-py3-none-musllinux_1_2_i686.whl", hash = "sha256:bb4bc11d32a1bf96a829bf6b9696545a30a196ac77bbc07cc8d3dfee35e03723"}, {file = "ty-0.0.18-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dda2efbf374ba4cd704053d04e32f2f784e85c2ddc2400006b0f96f5f7e4b667"}, {file = "ty-0.0.18-py3-none-win32.whl", hash = "sha256:c5768607c94977dacddc2f459ace6a11a408a0f57888dd59abb62d28d4fee4f7"}, {file = "ty-0.0.18-py3-none-win_amd64.whl", hash = "sha256:b78d0fa1103d36fc2fce92f2092adace52a74654ab7884d54cdaec8eb5016a4d"}, {file = "ty-0.0.18-py3-none-win_arm64.whl", hash = "sha256:01770c3c82137c6b216aa3251478f0b197e181054ee92243772de553d3586398"}, {file = "ty-0.0.18.tar.gz", hash = "sha256:04ab7c3db5dcbcdac6ce62e48940d3a0124f377c05499d3f3e004e264ae94b83"}, ] [[package]] name = "typing-extensions" version = "4.15.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["main", "dev"] markers = "python_version == \"3.12\"" files = [ {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, ] [[package]] name = "yamllint" version = "1.38.0" description = "A linter for YAML files." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ {file = "yamllint-1.38.0-py3-none-any.whl", hash = "sha256:fc394a5b3be980a4062607b8fdddc0843f4fa394152b6da21722f5d59013c220"}, {file = "yamllint-1.38.0.tar.gz", hash = "sha256:09e5f29531daab93366bb061e76019d5e91691ef0a40328f04c927387d1d364d"}, ] [package.dependencies] pathspec = ">=1.0.0" pyyaml = "*" [package.extras] dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "ruff", "sphinx"] [[package]] name = "yarl" version = "1.22.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e"}, {file = "yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f"}, {file = "yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf"}, {file = "yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a"}, {file = "yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c"}, {file = "yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147"}, {file = "yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb"}, {file = "yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6"}, {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0"}, {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda"}, {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc"}, {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737"}, {file = "yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467"}, {file = "yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea"}, {file = "yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca"}, {file = "yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b"}, {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1ab72135b1f2db3fed3997d7e7dc1b80573c67138023852b6efb336a5eae6511"}, {file = "yarl-1.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:669930400e375570189492dc8d8341301578e8493aec04aebc20d4717f899dd6"}, {file = "yarl-1.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:792a2af6d58177ef7c19cbf0097aba92ca1b9cb3ffdd9c7470e156c8f9b5e028"}, {file = "yarl-1.22.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ea66b1c11c9150f1372f69afb6b8116f2dd7286f38e14ea71a44eee9ec51b9d"}, {file = "yarl-1.22.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3e2daa88dc91870215961e96a039ec73e4937da13cf77ce17f9cad0c18df3503"}, {file = "yarl-1.22.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba440ae430c00eee41509353628600212112cd5018d5def7e9b05ea7ac34eb65"}, {file = "yarl-1.22.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e6438cc8f23a9c1478633d216b16104a586b9761db62bfacb6425bac0a36679e"}, {file = "yarl-1.22.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c52a6e78aef5cf47a98ef8e934755abf53953379b7d53e68b15ff4420e6683d"}, {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3b06bcadaac49c70f4c88af4ffcfbe3dc155aab3163e75777818092478bcbbe7"}, {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6944b2dc72c4d7f7052683487e3677456050ff77fcf5e6204e98caf785ad1967"}, {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5372ca1df0f91a86b047d1277c2aaf1edb32d78bbcefffc81b40ffd18f027ed"}, {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:51af598701f5299012b8416486b40fceef8c26fc87dc6d7d1f6fc30609ea0aa6"}, {file = "yarl-1.22.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b266bd01fedeffeeac01a79ae181719ff848a5a13ce10075adbefc8f1daee70e"}, {file = "yarl-1.22.0-cp311-cp311-win32.whl", hash = "sha256:a9b1ba5610a4e20f655258d5a1fdc7ebe3d837bb0e45b581398b99eb98b1f5ca"}, {file = "yarl-1.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:078278b9b0b11568937d9509b589ee83ef98ed6d561dfe2020e24a9fd08eaa2b"}, {file = "yarl-1.22.0-cp311-cp311-win_arm64.whl", hash = "sha256:b6a6f620cfe13ccec221fa312139135166e47ae169f8253f72a0abc0dae94376"}, {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f"}, {file = "yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2"}, {file = "yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74"}, {file = "yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df"}, {file = "yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb"}, {file = "yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2"}, {file = "yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82"}, {file = "yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a"}, {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124"}, {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa"}, {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7"}, {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d"}, {file = "yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520"}, {file = "yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8"}, {file = "yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c"}, {file = "yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74"}, {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8dee9c25c74997f6a750cd317b8ca63545169c098faee42c84aa5e506c819b53"}, {file = "yarl-1.22.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:01e73b85a5434f89fc4fe27dcda2aff08ddf35e4d47bbbea3bdcd25321af538a"}, {file = "yarl-1.22.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:22965c2af250d20c873cdbee8ff958fb809940aeb2e74ba5f20aaf6b7ac8c70c"}, {file = "yarl-1.22.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4f15793aa49793ec8d1c708ab7f9eded1aa72edc5174cae703651555ed1b601"}, {file = "yarl-1.22.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5542339dcf2747135c5c85f68680353d5cb9ffd741c0f2e8d832d054d41f35a"}, {file = "yarl-1.22.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5c401e05ad47a75869c3ab3e35137f8468b846770587e70d71e11de797d113df"}, {file = "yarl-1.22.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:243dda95d901c733f5b59214d28b0120893d91777cb8aa043e6ef059d3cddfe2"}, {file = "yarl-1.22.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bec03d0d388060058f5d291a813f21c011041938a441c593374da6077fe21b1b"}, {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b0748275abb8c1e1e09301ee3cf90c8a99678a4e92e4373705f2a2570d581273"}, {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:47fdb18187e2a4e18fda2c25c05d8251a9e4a521edaed757fef033e7d8498d9a"}, {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c7044802eec4524fde550afc28edda0dd5784c4c45f0be151a2d3ba017daca7d"}, {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:139718f35149ff544caba20fce6e8a2f71f1e39b92c700d8438a0b1d2a631a02"}, {file = "yarl-1.22.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e1b51bebd221006d3d2f95fbe124b22b247136647ae5dcc8c7acafba66e5ee67"}, {file = "yarl-1.22.0-cp313-cp313-win32.whl", hash = "sha256:d3e32536234a95f513bd374e93d717cf6b2231a791758de6c509e3653f234c95"}, {file = "yarl-1.22.0-cp313-cp313-win_amd64.whl", hash = "sha256:47743b82b76d89a1d20b83e60d5c20314cbd5ba2befc9cda8f28300c4a08ed4d"}, {file = "yarl-1.22.0-cp313-cp313-win_arm64.whl", hash = "sha256:5d0fcda9608875f7d052eff120c7a5da474a6796fe4d83e152e0e4d42f6d1a9b"}, {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:719ae08b6972befcba4310e49edb1161a88cdd331e3a694b84466bd938a6ab10"}, {file = "yarl-1.22.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:47d8a5c446df1c4db9d21b49619ffdba90e77c89ec6e283f453856c74b50b9e3"}, {file = "yarl-1.22.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:cfebc0ac8333520d2d0423cbbe43ae43c8838862ddb898f5ca68565e395516e9"}, {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4398557cbf484207df000309235979c79c4356518fd5c99158c7d38203c4da4f"}, {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2ca6fd72a8cd803be290d42f2dec5cdcd5299eeb93c2d929bf060ad9efaf5de0"}, {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca1f59c4e1ab6e72f0a23c13fca5430f889634166be85dbf1013683e49e3278e"}, {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c5010a52015e7c70f86eb967db0f37f3c8bd503a695a49f8d45700144667708"}, {file = "yarl-1.22.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d7672ecf7557476642c88497c2f8d8542f8e36596e928e9bcba0e42e1e7d71f"}, {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3b7c88eeef021579d600e50363e0b6ee4f7f6f728cd3486b9d0f3ee7b946398d"}, {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f4afb5c34f2c6fecdcc182dfcfc6af6cccf1aa923eed4d6a12e9d96904e1a0d8"}, {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:59c189e3e99a59cf8d83cbb31d4db02d66cda5a1a4374e8a012b51255341abf5"}, {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:5a3bf7f62a289fa90f1990422dc8dff5a458469ea71d1624585ec3a4c8d6960f"}, {file = "yarl-1.22.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:de6b9a04c606978fdfe72666fa216ffcf2d1a9f6a381058d4378f8d7b1e5de62"}, {file = "yarl-1.22.0-cp313-cp313t-win32.whl", hash = "sha256:1834bb90991cc2999f10f97f5f01317f99b143284766d197e43cd5b45eb18d03"}, {file = "yarl-1.22.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff86011bd159a9d2dfc89c34cfd8aff12875980e3bd6a39ff097887520e60249"}, {file = "yarl-1.22.0-cp313-cp313t-win_arm64.whl", hash = "sha256:7861058d0582b847bc4e3a4a4c46828a410bca738673f35a29ba3ca5db0b473b"}, {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:34b36c2c57124530884d89d50ed2c1478697ad7473efd59cfd479945c95650e4"}, {file = "yarl-1.22.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:0dd9a702591ca2e543631c2a017e4a547e38a5c0f29eece37d9097e04a7ac683"}, {file = "yarl-1.22.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:594fcab1032e2d2cc3321bb2e51271e7cd2b516c7d9aee780ece81b07ff8244b"}, {file = "yarl-1.22.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3d7a87a78d46a2e3d5b72587ac14b4c16952dd0887dbb051451eceac774411e"}, {file = "yarl-1.22.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:852863707010316c973162e703bddabec35e8757e67fcb8ad58829de1ebc8590"}, {file = "yarl-1.22.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:131a085a53bfe839a477c0845acf21efc77457ba2bcf5899618136d64f3303a2"}, {file = "yarl-1.22.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:078a8aefd263f4d4f923a9677b942b445a2be970ca24548a8102689a3a8ab8da"}, {file = "yarl-1.22.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bca03b91c323036913993ff5c738d0842fc9c60c4648e5c8d98331526df89784"}, {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:68986a61557d37bb90d3051a45b91fa3d5c516d177dfc6dd6f2f436a07ff2b6b"}, {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:4792b262d585ff0dff6bcb787f8492e40698443ec982a3568c2096433660c694"}, {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ebd4549b108d732dba1d4ace67614b9545b21ece30937a63a65dd34efa19732d"}, {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:f87ac53513d22240c7d59203f25cc3beac1e574c6cd681bbfd321987b69f95fd"}, {file = "yarl-1.22.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:22b029f2881599e2f1b06f8f1db2ee63bd309e2293ba2d566e008ba12778b8da"}, {file = "yarl-1.22.0-cp314-cp314-win32.whl", hash = "sha256:6a635ea45ba4ea8238463b4f7d0e721bad669f80878b7bfd1f89266e2ae63da2"}, {file = "yarl-1.22.0-cp314-cp314-win_amd64.whl", hash = "sha256:0d6e6885777af0f110b0e5d7e5dda8b704efed3894da26220b7f3d887b839a79"}, {file = "yarl-1.22.0-cp314-cp314-win_arm64.whl", hash = "sha256:8218f4e98d3c10d683584cb40f0424f4b9fd6e95610232dd75e13743b070ee33"}, {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:45c2842ff0e0d1b35a6bf1cd6c690939dacb617a70827f715232b2e0494d55d1"}, {file = "yarl-1.22.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d947071e6ebcf2e2bee8fce76e10faca8f7a14808ca36a910263acaacef08eca"}, {file = "yarl-1.22.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:334b8721303e61b00019474cc103bdac3d7b1f65e91f0bfedeec2d56dfe74b53"}, {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e7ce67c34138a058fd092f67d07a72b8e31ff0c9236e751957465a24b28910c"}, {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d77e1b2c6d04711478cb1c4ab90db07f1609ccf06a287d5607fcd90dc9863acf"}, {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4647674b6150d2cae088fc07de2738a84b8bcedebef29802cf0b0a82ab6face"}, {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:efb07073be061c8f79d03d04139a80ba33cbd390ca8f0297aae9cce6411e4c6b"}, {file = "yarl-1.22.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e51ac5435758ba97ad69617e13233da53908beccc6cfcd6c34bbed8dcbede486"}, {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:33e32a0dd0c8205efa8e83d04fc9f19313772b78522d1bdc7d9aed706bfd6138"}, {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:bf4a21e58b9cde0e401e683ebd00f6ed30a06d14e93f7c8fd059f8b6e8f87b6a"}, {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e4b582bab49ac33c8deb97e058cd67c2c50dac0dd134874106d9c774fd272529"}, {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0b5bcc1a9c4839e7e30b7b30dd47fe5e7e44fb7054ec29b5bb8d526aa1041093"}, {file = "yarl-1.22.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c0232bce2170103ec23c454e54a57008a9a72b5d1c3105dc2496750da8cfa47c"}, {file = "yarl-1.22.0-cp314-cp314t-win32.whl", hash = "sha256:8009b3173bcd637be650922ac455946197d858b3630b6d8787aa9e5c4564533e"}, {file = "yarl-1.22.0-cp314-cp314t-win_amd64.whl", hash = "sha256:9fb17ea16e972c63d25d4a97f016d235c78dd2344820eb35bc034bc32012ee27"}, {file = "yarl-1.22.0-cp314-cp314t-win_arm64.whl", hash = "sha256:9f6d73c1436b934e3f01df1e1b21ff765cd1d28c77dfb9ace207f746d4610ee1"}, {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:3aa27acb6de7a23785d81557577491f6c38a5209a254d1191519d07d8fe51748"}, {file = "yarl-1.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:af74f05666a5e531289cb1cc9c883d1de2088b8e5b4de48004e5ca8a830ac859"}, {file = "yarl-1.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62441e55958977b8167b2709c164c91a6363e25da322d87ae6dd9c6019ceecf9"}, {file = "yarl-1.22.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b580e71cac3f8113d3135888770903eaf2f507e9421e5697d6ee6d8cd1c7f054"}, {file = "yarl-1.22.0-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e81fda2fb4a07eda1a2252b216aa0df23ebcd4d584894e9612e80999a78fd95b"}, {file = "yarl-1.22.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:99b6fc1d55782461b78221e95fc357b47ad98b041e8e20f47c1411d0aacddc60"}, {file = "yarl-1.22.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:088e4e08f033db4be2ccd1f34cf29fe994772fb54cfe004bbf54db320af56890"}, {file = "yarl-1.22.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4e1f6f0b4da23e61188676e3ed027ef0baa833a2e633c29ff8530800edccba"}, {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:84fc3ec96fce86ce5aa305eb4aa9358279d1aa644b71fab7b8ed33fe3ba1a7ca"}, {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5dbeefd6ca588b33576a01b0ad58aa934bc1b41ef89dee505bf2932b22ddffba"}, {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14291620375b1060613f4aab9ebf21850058b6b1b438f386cc814813d901c60b"}, {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:a4fcfc8eb2c34148c118dfa02e6427ca278bfd0f3df7c5f99e33d2c0e81eae3e"}, {file = "yarl-1.22.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:029866bde8d7b0878b9c160e72305bbf0a7342bcd20b9999381704ae03308dc8"}, {file = "yarl-1.22.0-cp39-cp39-win32.whl", hash = "sha256:4dcc74149ccc8bba31ce1944acee24813e93cfdee2acda3c172df844948ddf7b"}, {file = "yarl-1.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:10619d9fdee46d20edc49d3479e2f8269d0779f1b031e6f7c2aa1c76be04b7ed"}, {file = "yarl-1.22.0-cp39-cp39-win_arm64.whl", hash = "sha256:dd7afd3f8b0bfb4e0d9fc3c31bfe8a4ec7debe124cfd90619305def3c8ca8cd2"}, {file = "yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff"}, {file = "yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" propcache = ">=0.2.1" [metadata] lock-version = "2.1" python-versions = "^3.12" content-hash = "9055ab14525728b8cf46d9215139c0b26088c1754c049c60fc53b3a75ade19f8" forecast_solar-5.0.0/pyproject.toml000066400000000000000000000052771514642402100174500ustar00rootroot00000000000000[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.12" 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.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "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" python = "^3.12" 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" pre-commit-hooks = "6.0.0" prek = "0.3.3" pytest = "9.0.2" pytest-asyncio = "1.3.0" pytest-cov = "7.0.0" pytest-freezer = "0.4.9" ruff = "0.15.2" syrupy = "5.1.0" ty = "0.0.18" yamllint = "1.38.0" [tool.coverage.run] plugins = ["covdefaults"] source = ["forecast_solar"] [tool.coverage.report] fail_under = 90 show_missing = true [tool.pytest.ini_options] addopts = "--cov" asyncio_mode = "auto" [tool.ruff] target-version = "py312" lint.select = ["ALL"] lint.ignore = [ "ANN401", # Opinionated 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 literals "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-5.0.0/src/000077500000000000000000000000001514642402100153105ustar00rootroot00000000000000forecast_solar-5.0.0/src/forecast_solar/000077500000000000000000000000001514642402100203165ustar00rootroot00000000000000forecast_solar-5.0.0/src/forecast_solar/__init__.py000066400000000000000000000012551514642402100224320ustar00rootroot00000000000000"""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, Plane, Ratelimit __all__ = [ "AccountType", "Estimate", "ForecastSolar", "ForecastSolarAuthenticationError", "ForecastSolarConfigError", "ForecastSolarConnectionError", "ForecastSolarError", "ForecastSolarRatelimitError", "ForecastSolarRequestError", "Plane", "Ratelimit", ] forecast_solar-5.0.0/src/forecast_solar/exceptions.py000066400000000000000000000033261514642402100230550ustar00rootroot00000000000000"""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-5.0.0/src/forecast_solar/forecast_solar.py000066400000000000000000000163301514642402100237010ustar00rootroot00000000000000"""Asynchronous Python client for the Forecast.Solar API.""" from __future__ import annotations from dataclasses import dataclass from typing import Any, Self from aiohttp import ClientSession from yarl import URL from .exceptions import ( ForecastSolarAuthenticationError, ForecastSolarConfigError, ForecastSolarConnectionError, ForecastSolarError, ForecastSolarRatelimitError, ForecastSolarRequestError, ) from .models import Estimate, Plane, 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 planes: list[Plane] | None = None session: ClientSession | None = None ratelimit: Ratelimit | None = None inverter: float | None = None _close_session: bool = False _base_url = URL("https://api.forecast.solar") def _build_plane_path(self) -> str: """Build the plane path segment for API URLs. Returns ------- A string containing the plane parameters for all planes. Additional planes are only included if an API key is provided. """ path = f"{self.declination}/{self.azimuth}/{self.kwp}" # Only include additional planes if an API key is provided if self.planes and self.api_key is not None: for plane in self.planes: path += f"/{plane.declination}/{plane.azimuth}/{plane.kwp}" return path 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. """ # Add API key if one is provided if authenticate and self.api_key is not None: url = self._base_url.with_path(f"{self.api_key}/") else: url = self._base_url 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, 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 response.status == 404: data = await response.json() raise ForecastSolarRequestError(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}/{self._build_plane_path()}", 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}/{self._build_plane_path()}", 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-5.0.0/src/forecast_solar/models.py000066400000000000000000000164621514642402100221640ustar00rootroot00000000000000"""Data models for the Forecast.Solar API.""" from __future__ import annotations from dataclasses import dataclass from datetime import date, datetime, timedelta from enum import StrEnum 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(StrEnum): """Enumeration representing the Forecast.Solar account type.""" PUBLIC = "public" PERSONAL = "personal" PROFESSIONAL = "professional" @dataclass class Plane: """Represents a solar plane configuration. Attributes ---------- declination: The tilt of the solar panels (0-90 degrees). azimuth: The direction the solar panels are facing (-180 to 180 degrees). kwp: The size of the solar panels in kWp. """ declination: float azimuth: float kwp: float @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-5.0.0/src/forecast_solar/py.typed000066400000000000000000000000001514642402100220030ustar00rootroot00000000000000forecast_solar-5.0.0/tests/000077500000000000000000000000001514642402100156635ustar00rootroot00000000000000forecast_solar-5.0.0/tests/__init__.py000066400000000000000000000003611514642402100177740ustar00rootroot00000000000000"""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-5.0.0/tests/__snapshots__/000077500000000000000000000000001514642402100205015ustar00rootroot00000000000000forecast_solar-5.0.0/tests/__snapshots__/test_models.ambr000066400000000000000000002436021514642402100236750ustar00rootroot00000000000000# 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_multi_plane 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 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-5.0.0/tests/conftest.py000066400000000000000000000036171514642402100200710ustar00rootroot00000000000000"""Fixtures for the Forecast.Solar tests.""" from collections.abc import AsyncGenerator import pytest from aiohttp import ClientSession from forecast_solar import ForecastSolar, Plane @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 @pytest.fixture(name="forecast_multi_plane_client") async def client_multi_plane() -> AsyncGenerator[ForecastSolar, None]: """Return a Forecast.Solar client with multiple planes.""" async with ( ClientSession() as session, ForecastSolar( api_key="myapikey", latitude=52.16, longitude=4.47, declination=20, azimuth=10, kwp=2.160, planes=[ Plane(declination=30, azimuth=-90, kwp=1.5), ], session=session, ) as forecast_multi_plane_client, ): yield forecast_multi_plane_client forecast_solar-5.0.0/tests/fixtures/000077500000000000000000000000001514642402100175345ustar00rootroot00000000000000forecast_solar-5.0.0/tests/fixtures/forecast.json000066400000000000000000000110721514642402100222360ustar00rootroot00000000000000{ "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-5.0.0/tests/fixtures/forecast_personal.json000066400000000000000000000373421514642402100241510ustar00rootroot00000000000000{ "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-5.0.0/tests/fixtures/ratelimit.json000066400000000000000000000005071514642402100224230ustar00rootroot00000000000000{ "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-5.0.0/tests/fixtures/validate_key.json000066400000000000000000000007261514642402100230750ustar00rootroot00000000000000{ "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-5.0.0/tests/fixtures/validate_plane.json000066400000000000000000000013071514642402100234000ustar00rootroot00000000000000{ "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-5.0.0/tests/ruff.toml000066400000000000000000000005431514642402100175240ustar00rootroot00000000000000# 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-5.0.0/tests/test_exceptions.py000066400000000000000000000100121514642402100214470ustar00rootroot00000000000000"""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") async def test_status_404( aresponses: ResponsesMockServer, forecast_client: ForecastSolar, ) -> None: """Test response status 404.""" aresponses.add( "api.forecast.solar", "/test", "GET", aresponses.Response( status=404, headers={ "Content-Type": "application/json", }, text='{"message": {"code": 404, "text": "Not Found"}}', ), ) with pytest.raises(ForecastSolarRequestError): assert await forecast_client._request("test") forecast_solar-5.0.0/tests/test_forecast.py000066400000000000000000000042751514642402100211120ustar00rootroot00000000000000"""Tests for Forecast.Solar.""" # pylint: disable=protected-access import pytest from aresponses import ResponsesMockServer from forecast_solar import ( ForecastSolar, 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") forecast_solar-5.0.0/tests/test_models.py000066400000000000000000000205531514642402100205640ustar00rootroot00000000000000"""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, Plane 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 @pytest.mark.freeze_time("2024-04-26T12:00:00+02:00") async def test_estimated_forecast_multi_plane( aresponses: ResponsesMockServer, snapshot: SnapshotAssertion, forecast_multi_plane_client: ForecastSolar, ) -> None: """Test estimated forecast with multiple planes.""" aresponses.add( "api.forecast.solar", "/myapikey/estimate/52.16/4.47/20/10/2.16/30/-90/1.5", "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_multi_plane_client.estimate() assert forecast == snapshot assert forecast.timezone == "Europe/Amsterdam" assert forecast.account_type == AccountType.PERSONAL async def test_multi_plane_validation( aresponses: ResponsesMockServer, forecast_multi_plane_client: ForecastSolar, ) -> None: """Test plane validation with multiple planes.""" aresponses.add( "api.forecast.solar", "/check/52.16/4.47/20/10/2.16/30/-90/1.5", "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_multi_plane_client.validate_plane() is True async def test_planes_ignored_without_api_key( aresponses: ResponsesMockServer, ) -> None: """Test that planes are silently ignored when no API key is provided.""" # When no API key is provided, planes should be ignored # and only the primary plane used aresponses.add( "api.forecast.solar", "/estimate/52.16/4.47/20/10/2.16", # Only primary plane, no additional planes "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, planes=[ Plane(declination=30, azimuth=-90, kwp=1.5), ], ) as forecast: estimate = await forecast.estimate() assert estimate is not None