pax_global_header00006660000000000000000000000064144573301130014513gustar00rootroot0000000000000052 comment=68529d1ffb36c6e760f2dab20920e1c4e6c85af0 joostlek-python-youtube-68529d1/000077500000000000000000000000001445733011300166425ustar00rootroot00000000000000joostlek-python-youtube-68529d1/.editorconfig000066400000000000000000000003211445733011300213130ustar00rootroot00000000000000root = true [*] charset = utf-8 end_of_line = lf indent_style = space insert_final_newline = true trim_trailing_whitespace = true indent_size = 4 max_line_length = 88 [*.md] trim_trailing_whitespace = false joostlek-python-youtube-68529d1/.gitattributes000066400000000000000000000000511445733011300215310ustar00rootroot00000000000000* text eol=lf *.py whitespace=error joostlek-python-youtube-68529d1/.github/000077500000000000000000000000001445733011300202025ustar00rootroot00000000000000joostlek-python-youtube-68529d1/.github/CODEOWNERS000066400000000000000000000000241445733011300215710ustar00rootroot00000000000000.github/* @joostlek joostlek-python-youtube-68529d1/.github/CODE_OF_CONDUCT.md000066400000000000000000000062141445733011300230040ustar00rootroot00000000000000# Code of conduct ## Our pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project lead at frenck@addons.community. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project lead is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ joostlek-python-youtube-68529d1/.github/CONTRIBUTING.md000066400000000000000000000022171445733011300224350ustar00rootroot00000000000000# 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. 2. 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/joostlek/python-youtube/issues [prs]: https://github.com/joostlek/python-youtube/pulls joostlek-python-youtube-68529d1/.github/ISSUE_TEMPLATE.md000066400000000000000000000005141445733011300227070ustar00rootroot00000000000000# Problem/Motivation > (Why the issue was filed) ## Expected behavior > (What you expected to happen) ## Actual behavior > (What actually happened) ## Steps to reproduce > (How can someone else make/see it happen) ## Proposed changes > (If you have a proposed change, workaround or fix, > describe the rationale behind it) joostlek-python-youtube-68529d1/.github/LICENSE.md000066400000000000000000000020651445733011300216110ustar00rootroot00000000000000# MIT License Copyright (c) 2023 Joost Lekkerkerker 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. joostlek-python-youtube-68529d1/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000003761445733011300240110ustar00rootroot00000000000000# Proposed Changes > (Describe the changes and rationale behind them) ## Related Issues > ([Github link][autolink-references] to related issues or pull requests) [autolink-references]: https://help.github.com/articles/autolinked-references-and-urls/ joostlek-python-youtube-68529d1/.github/labels.yml000066400000000000000000000054331445733011300221740ustar00rootroot00000000000000--- - name: "breaking-change" color: ee0701 description: "A breaking change for existing users." - name: "bugfix" color: ee0701 description: "Inconsistencies or issues which will cause a problem for users or implementors." - 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 options." - 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: "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: "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." joostlek-python-youtube-68529d1/.github/release-drafter.yml000066400000000000000000000020471445733011300237750ustar00rootroot00000000000000--- name-template: "v$RESOLVED_VERSION" tag-template: "v$RESOLVED_VERSION" change-template: "- $TITLE @$AUTHOR (#$NUMBER)" 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" 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 joostlek-python-youtube-68529d1/.github/renovate.json000066400000000000000000000021611445733011300227200ustar00rootroot00000000000000{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "schedule": ["before 2am"], "rebaseWhen": "behind-base-branch", "dependencyDashboard": true, "labels": ["dependencies", "no-stale"], "lockFileMaintenance": { "enabled": true, "automerge": true }, "commitMessagePrefix": "⬆️", "packageRules": [ { "matchManagers": ["poetry"], "addLabels": ["python"] }, { "matchManagers": ["poetry"], "matchDepTypes": ["dev"], "rangeStrategy": "pin" }, { "matchManagers": ["poetry"], "matchUpdateTypes": ["minor", "patch"], "automerge": true }, { "matchManagers": ["npm", "nvm"], "addLabels": ["javascript"], "rangeStrategy": "pin" }, { "matchManagers": ["npm", "nvm"], "matchUpdateTypes": ["minor", "patch"], "automerge": true }, { "matchManagers": ["github-actions"], "addLabels": ["github_actions"], "rangeStrategy": "pin" }, { "matchManagers": ["github-actions"], "matchUpdateTypes": ["minor", "patch"], "automerge": true } ] } joostlek-python-youtube-68529d1/.github/workflows/000077500000000000000000000000001445733011300222375ustar00rootroot00000000000000joostlek-python-youtube-68529d1/.github/workflows/labels.yaml000066400000000000000000000007361445733011300243730ustar00rootroot00000000000000--- name: Sync labels # yamllint disable-line rule:truthy on: push: branches: - main paths: - .github/labels.yml workflow_dispatch: jobs: labels: name: ♻️ Sync labels runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🚀 Run Label Syncer uses: micnncim/action-label-syncer@v1.3.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} joostlek-python-youtube-68529d1/.github/workflows/linting.yaml000066400000000000000000000157771445733011300246100ustar00rootroot00000000000000--- name: Linting # yamllint disable-line rule:truthy on: push: branches: - main pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.10" jobs: codespell: name: codespell runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 code for common misspellings run: poetry run pre-commit run codespell --all-files ruff: name: Ruff runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 run: poetry run ruff . black: name: black runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 black on docs run: poetry run blacken-docs pre-commit-hooks: name: pre-commit-hooks runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: 🏗 Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: 🏗 Install Python dependencies run: poetry install --no-interaction - name: 🚀 Check Python AST run: poetry run pre-commit run check-ast --all-files - name: 🚀 Check for case conflicts run: poetry run pre-commit run check-case-conflict --all-files - name: 🚀 Check docstring is first run: poetry run pre-commit run check-docstring-first --all-files - name: 🚀 Check that executables have shebangs run: poetry run pre-commit run check-executables-have-shebangs --all-files - name: 🚀 Check JSON files run: poetry run pre-commit run check-json --all-files - name: 🚀 Check for merge conflicts run: poetry run pre-commit run check-merge-conflict --all-files - name: 🚀 Check for broken symlinks run: poetry run pre-commit run check-symlinks --all-files - name: 🚀 Check TOML files run: poetry run pre-commit run check-toml --all-files - name: 🚀 Check XML files run: poetry run pre-commit run check-xml --all-files - name: 🚀 Check YAML files run: poetry run pre-commit run check-yaml --all-files - name: 🚀 Detect Private Keys run: poetry run pre-commit run detect-private-key --all-files - name: 🚀 Check End of Files run: poetry run pre-commit run end-of-file-fixer --all-files - name: 🚀 Trim Trailing Whitespace run: poetry run pre-commit run trailing-whitespace --all-files pylint: name: pylint runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 pylint run: poetry run pre-commit run pylint --all-files yamllint: name: yamllint runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 . prettier: name: Prettier runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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: 🏗 Set up Node.js uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3 with: node-version-file: ".nvmrc" cache: "npm" - name: 🏗 Install NPM dependencies run: npm install - name: 🚀 Run prettier run: poetry run pre-commit run prettier --all-files joostlek-python-youtube-68529d1/.github/workflows/lock.yaml000066400000000000000000000006651445733011300240620ustar00rootroot00000000000000--- name: Lock # yamllint disable-line rule:truthy on: schedule: - cron: "0 9 * * *" workflow_dispatch: jobs: lock: name: 🔒 Lock closed issues and PRs runs-on: ubuntu-latest steps: - uses: dessant/lock-threads@v4.0.1 with: github-token: ${{ github.token }} issue-inactive-days: "30" issue-lock-reason: "" pr-inactive-days: "1" pr-lock-reason: "" joostlek-python-youtube-68529d1/.github/workflows/pr-labels.yaml000066400000000000000000000013021445733011300250000ustar00rootroot00000000000000--- 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 joostlek-python-youtube-68529d1/.github/workflows/release-drafter.yaml000066400000000000000000000005751445733011300261770ustar00rootroot00000000000000--- name: Release Drafter # yamllint disable-line rule:truthy on: push: branches: - main workflow_dispatch: jobs: update_release_draft: name: ✏️ Draft release runs-on: ubuntu-latest steps: - name: 🚀 Run Release Drafter uses: release-drafter/release-drafter@v5.24.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} joostlek-python-youtube-68529d1/.github/workflows/release.yaml000066400000000000000000000025001445733011300245400ustar00rootroot00000000000000--- name: Release # yamllint disable-line rule:truthy on: release: types: - published env: DEFAULT_PYTHON: "3.10" jobs: release: name: Releasing to PyPi runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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 to PyPi env: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} run: | poetry config pypi-token.pypi "${PYPI_TOKEN}" poetry publish --no-interaction joostlek-python-youtube-68529d1/.github/workflows/stale.yaml000066400000000000000000000025601445733011300242360ustar00rootroot00000000000000--- name: Stale # yamllint disable-line rule:truthy on: schedule: - cron: "0 8 * * *" workflow_dispatch: jobs: stale: name: 🧹 Clean up stale issues and PRs runs-on: ubuntu-latest steps: - name: 🚀 Run stale uses: actions/stale@v8.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 days-before-close: 7 remove-stale-when-updated: true stale-issue-label: "stale" exempt-issue-labels: "no-stale,help-wanted" stale-issue-message: > There hasn't been any activity on this issue recently, so we clean up some of the older and inactive issues. Please make sure to update to the latest version and check if that solves the issue. Let us know if that works for you by leaving a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thanks! stale-pr-label: "stale" exempt-pr-labels: "no-stale" stale-pr-message: > There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days. Thank you for your contributions. joostlek-python-youtube-68529d1/.github/workflows/tests.yaml000066400000000000000000000046751445733011300243010ustar00rootroot00000000000000--- name: Testing # yamllint disable-line rule:truthy on: push: branches: - main pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.10" jobs: pytest: name: Python ${{ matrix.python }} runs-on: ubuntu-latest strategy: matrix: python: ["3.10", "3.11"] steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ matrix.python }} id: python uses: actions/setup-python@v4.7.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 --cov vehicle tests - name: ⬆️ Upload coverage artifact uses: actions/upload-artifact@v3.1.2 with: name: coverage-${{ matrix.python }} path: .coverage coverage: runs-on: ubuntu-latest needs: pytest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 with: fetch-depth: 0 - name: ⬇️ Download coverage data uses: actions/download-artifact@v3.0.2 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.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: 🚀 Process coverage results run: | poetry run coverage combine coverage*/.coverage* poetry run coverage xml -i - name: 🚀 Upload coverage report uses: codecov/codecov-action@v3.1.4 - name: SonarCloud Scan if: github.event.pull_request.head.repo.fork == false uses: SonarSource/sonarcloud-github-action@v1.9 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} joostlek-python-youtube-68529d1/.github/workflows/typing.yaml000066400000000000000000000016151445733011300244400ustar00rootroot00000000000000--- name: Typing # yamllint disable-line rule:truthy on: push: branches: - main pull_request: workflow_dispatch: env: DEFAULT_PYTHON: "3.10" jobs: mypy: name: mypy runs-on: ubuntu-latest steps: - name: ⤵️ Check out code from GitHub uses: actions/checkout@v3.5.3 - name: 🏗 Set up Poetry run: pipx install poetry - name: 🏗 Set up Python ${{ env.DEFAULT_PYTHON }} id: python uses: actions/setup-python@v4.7.0 with: python-version: ${{ env.DEFAULT_PYTHON }} cache: "poetry" - name: 🏗 Install workflow dependencies run: | poetry config virtualenvs.create true poetry config virtualenvs.in-project true - name: 🏗 Install dependencies run: poetry install --no-interaction - name: 🚀 Run mypy run: poetry run mypy src tests joostlek-python-youtube-68529d1/.gitignore000066400000000000000000000027011445733011300206320ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # OSX useful to ignore *.DS_Store .AppleDouble .LSOverride # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # C extensions *.so # Distribution / packaging .Python env/ build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # 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/ .coverage .coverage.* .cache nosetests.xml coverage.xml *,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log # Sphinx documentation docs/_build/ # pyenv .python-version # virtualenv .venv venv/ ENV/ # mypy .mypy_cache/ # ruff .ruff_cache # Visual Studio Code .vscode # IntelliJ Idea family of suites .idea *.iml ## File-based project format: *.ipr *.iws ## mpeltonen/sbt-idea plugin .idea_modules/ # PyBuilder target/ # Cookiecutter output/ python_boilerplate/ # Node node_modules/ # Deepcode AI .dccache joostlek-python-youtube-68529d1/.nvmrc000066400000000000000000000000101445733011300177570ustar00rootroot0000000000000018.17.0 joostlek-python-youtube-68529d1/.pre-commit-config.yaml000066400000000000000000000103331445733011300231230ustar00rootroot00000000000000--- repos: - repo: local hooks: - id: ruff name: 🐶 Ruff language: system types: [python] entry: poetry run ruff --fix require_serial: true stages: [commit, push, manual] - id: black name: ☕️ Format using black language: system types: [python] entry: poetry run black require_serial: true - id: blacken-docs name: ☕️ Format documentation examples using black language: system files: '\.(rst|md|markdown|py|tex)$' entry: poetry run blacken-docs require_serial: true - 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: check-xml language: system types: [xml] - id: check-yaml name: ✅ Check YAML files language: system types: [yaml] entry: poetry run check-yaml - id: codespell name: ✅ Check code for common misspellings language: system types: [text] exclude: ^poetry\.lock$ entry: poetry run codespell --skip="./.*,*.csv,*.json" - 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: mypy name: 🆎 Static type checking using mypy language: system types: [python] entry: poetry run mypy require_serial: true - 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=main - id: poetry name: 📜 Check pyproject with Poetry language: system entry: poetry check pass_filenames: false always_run: true - id: prettier name: 💄 Ensuring files are prettier language: system types: [yaml, json, markdown] entry: npm run prettier pass_filenames: false - id: pylint name: 🌟 Starring code with pylint language: system types: [python] entry: poetry run pylint - 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 joostlek-python-youtube-68529d1/.prettierignore000066400000000000000000000000131445733011300216770ustar00rootroot00000000000000.gitignore joostlek-python-youtube-68529d1/.yamllint000066400000000000000000000024001445733011300204700ustar00rootroot00000000000000--- ignore: - .venv 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 joostlek-python-youtube-68529d1/LICENSE.md000066400000000000000000000020651445733011300202510ustar00rootroot00000000000000# MIT License Copyright (c) 2023 Joost Lekkerkerker 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. joostlek-python-youtube-68529d1/README.md000066400000000000000000000114001445733011300201150ustar00rootroot00000000000000# Python: YouTube [![GitHub Release][releases-shield]][releases] [![Python Versions][python-versions-shield]][pypi] ![Project Stage][project-stage-shield] ![Project Maintenance][maintenance-shield] [![License][license-shield]](LICENSE.md) [![Build Status][build-shield]][build] [![Code Coverage][codecov-shield]][codecov] [![Code Smells][code-smells]][sonarcloud] Asynchronous Python client for the YouTube V3 API. ## About This package allows you to interact with the YouTube V3 API. ## Installation ```bash pip install youtubeaio ``` ## Changelog & Releases This repository keeps a change log using [GitHub's releases][releases] functionality. The format of the log is based on [Keep a Changelog][keepchangelog]. Releases are based on [Semantic Versioning][semver], and use the format of ``MAJOR.MINOR.PATCH``. In a nutshell, the version will be incremented based on the following: - ``MAJOR``: Incompatible or major changes. - ``MINOR``: Backwards-compatible new features and enhancements. - ``PATCH``: Backwards-compatible bugfixes and package updates. ## Contributing This is an active open-source project. We are always open to people who want to use the code or contribute to it. We've set up a separate document for our [contribution guidelines](.github/CONTRIBUTING.md). Thank you for being involved! :heart_eyes: ## Setting up development environment This Python project is fully managed using the [Poetry][poetry] dependency manager. But also relies on the use of NodeJS for certain checks during development. You need at least: - Python 3.10+ - [Poetry][poetry-install] - NodeJS 12+ (including NPM) To install all packages, including all development requirements: ```bash npm install poetry install ``` As this repository uses the [pre-commit][pre-commit] framework, all changes are linted and tested with each commit. You can run all checks and tests manually, using the following command: ```bash poetry run pre-commit run --all-files ``` To run just the Python tests: ```bash poetry run pytest ``` ## Authors & contributors The original setup of this repository is by [Joost Lekkerkerker][joostlek] For a full list of all authors and contributors, check [the contributor's page][contributors]. ## License MIT License Copyright (c) 2023 Joost Lekkerkerker 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. [build-shield]: https://github.com/joostlek/python-youtube/actions/workflows/tests.yaml/badge.svg [build]: https://github.com/joostlek/python-youtube/actions [code-smells]: https://sonarcloud.io/api/project_badges/measure?project=joostlek_python-youtube&metric=code_smells [codecov-shield]: https://codecov.io/gh/joostlek/python-youtube/branch/master/graph/badge.svg [codecov]: https://codecov.io/gh/joostlek/python-youtube [commits-shield]: https://img.shields.io/github/commit-activity/y/joostlek/python-youtube.svg [commits]: https://github.com/joostlek/python-youtube/commits/master [contributors]: https://github.com/joostlek/python-youtube/graphs/contributors [joostlek]: https://github.com/joostlek [keepchangelog]: http://keepachangelog.com/en/1.0.0/ [license-shield]: https://img.shields.io/github/license/joostlek/python-youtube.svg [maintenance-shield]: https://img.shields.io/maintenance/yes/2023.svg [poetry-install]: https://python-poetry.org/docs/#installation [poetry]: https://python-poetry.org [pre-commit]: https://pre-commit.com/ [project-stage-shield]: https://img.shields.io/badge/project%20stage-experimental-yellow.svg [python-versions-shield]: https://img.shields.io/pypi/pyversions/youtubeaio [releases-shield]: https://img.shields.io/github/release/joostlek/python-youtube.svg [releases]: https://github.com/joostlek/python-youtube/releases [semver]: http://semver.org/spec/v2.0.0.html [sonarcloud]: https://sonarcloud.io/summary/new_code?id=joostlek_python-youtube [pypi]: https://pypi.org/project/youtubeaio/ joostlek-python-youtube-68529d1/package-lock.json000066400000000000000000000013731445733011300220620ustar00rootroot00000000000000{ "name": "python_youtube", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "python_youtube", "version": "0.0.0", "license": "MIT", "devDependencies": { "prettier": "3.0.0" } }, "node_modules/prettier": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } } } } joostlek-python-youtube-68529d1/package.json000066400000000000000000000005411445733011300211300ustar00rootroot00000000000000{ "name": "python_youtube", "version": "0.0.0", "private": true, "description": "Asynchronous Python client for the YouTube V3 API", "scripts": { "prettier": "prettier --write **/*.{json,js,md,yml,yaml}" }, "author": "Joost Lekkerkerker ", "license": "MIT", "devDependencies": { "prettier": "3.0.0" } } joostlek-python-youtube-68529d1/poetry.lock000066400000000000000000004770011445733011300210470ustar00rootroot00000000000000# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "aiohttp" version = "3.8.5" description = "Async http client/server framework (asyncio)" optional = false python-versions = ">=3.6" files = [ {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a94159871304770da4dd371f4291b20cac04e8c94f11bdea1c3478e557fbe0d8"}, {file = "aiohttp-3.8.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:13bf85afc99ce6f9ee3567b04501f18f9f8dbbb2ea11ed1a2e079670403a7c84"}, {file = "aiohttp-3.8.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ce2ac5708501afc4847221a521f7e4b245abf5178cf5ddae9d5b3856ddb2f3a"}, {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96943e5dcc37a6529d18766597c491798b7eb7a61d48878611298afc1fca946c"}, {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ad5c3c4590bb3cc28b4382f031f3783f25ec223557124c68754a2231d989e2b"}, {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c413c633d0512df4dc7fd2373ec06cc6a815b7b6d6c2f208ada7e9e93a5061d"}, {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df72ac063b97837a80d80dec8d54c241af059cc9bb42c4de68bd5b61ceb37caa"}, {file = "aiohttp-3.8.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c48c5c0271149cfe467c0ff8eb941279fd6e3f65c9a388c984e0e6cf57538e14"}, {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:368a42363c4d70ab52c2c6420a57f190ed3dfaca6a1b19afda8165ee16416a82"}, {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7607ec3ce4993464368505888af5beb446845a014bc676d349efec0e05085905"}, {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0d21c684808288a98914e5aaf2a7c6a3179d4df11d249799c32d1808e79503b5"}, {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:312fcfbacc7880a8da0ae8b6abc6cc7d752e9caa0051a53d217a650b25e9a691"}, {file = "aiohttp-3.8.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad093e823df03bb3fd37e7dec9d4670c34f9e24aeace76808fc20a507cace825"}, {file = "aiohttp-3.8.5-cp310-cp310-win32.whl", hash = "sha256:33279701c04351a2914e1100b62b2a7fdb9a25995c4a104259f9a5ead7ed4802"}, {file = "aiohttp-3.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:6e4a280e4b975a2e7745573e3fc9c9ba0d1194a3738ce1cbaa80626cc9b4f4df"}, {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae871a964e1987a943d83d6709d20ec6103ca1eaf52f7e0d36ee1b5bebb8b9b9"}, {file = "aiohttp-3.8.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:461908b2578955045efde733719d62f2b649c404189a09a632d245b445c9c975"}, {file = "aiohttp-3.8.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:72a860c215e26192379f57cae5ab12b168b75db8271f111019509a1196dfc780"}, {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14be025665dba6202b6a71cfcdb53210cc498e50068bc088076624471f8bb9"}, {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8af740fc2711ad85f1a5c034a435782fbd5b5f8314c9a3ef071424a8158d7f6b"}, {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:841cd8233cbd2111a0ef0a522ce016357c5e3aff8a8ce92bcfa14cef890d698f"}, {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed1c46fb119f1b59304b5ec89f834f07124cd23ae5b74288e364477641060ff"}, {file = "aiohttp-3.8.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84f8ae3e09a34f35c18fa57f015cc394bd1389bce02503fb30c394d04ee6b938"}, {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62360cb771707cb70a6fd114b9871d20d7dd2163a0feafe43fd115cfe4fe845e"}, {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:23fb25a9f0a1ca1f24c0a371523546366bb642397c94ab45ad3aedf2941cec6a"}, {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0ba0d15164eae3d878260d4c4df859bbdc6466e9e6689c344a13334f988bb53"}, {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5d20003b635fc6ae3f96d7260281dfaf1894fc3aa24d1888a9b2628e97c241e5"}, {file = "aiohttp-3.8.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0175d745d9e85c40dcc51c8f88c74bfbaef9e7afeeeb9d03c37977270303064c"}, {file = "aiohttp-3.8.5-cp311-cp311-win32.whl", hash = "sha256:2e1b1e51b0774408f091d268648e3d57f7260c1682e7d3a63cb00d22d71bb945"}, {file = "aiohttp-3.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:043d2299f6dfdc92f0ac5e995dfc56668e1587cea7f9aa9d8a78a1b6554e5755"}, {file = "aiohttp-3.8.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cae533195e8122584ec87531d6df000ad07737eaa3c81209e85c928854d2195c"}, {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f21e83f355643c345177a5d1d8079f9f28b5133bcd154193b799d380331d5d3"}, {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a75ef35f2df54ad55dbf4b73fe1da96f370e51b10c91f08b19603c64004acc"}, {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e2e9839e14dd5308ee773c97115f1e0a1cb1d75cbeeee9f33824fa5144c7634"}, {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44e65da1de4403d0576473e2344828ef9c4c6244d65cf4b75549bb46d40b8dd"}, {file = "aiohttp-3.8.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78d847e4cde6ecc19125ccbc9bfac4a7ab37c234dd88fbb3c5c524e8e14da543"}, {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:c7a815258e5895d8900aec4454f38dca9aed71085f227537208057853f9d13f2"}, {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:8b929b9bd7cd7c3939f8bcfffa92fae7480bd1aa425279d51a89327d600c704d"}, {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5db3a5b833764280ed7618393832e0853e40f3d3e9aa128ac0ba0f8278d08649"}, {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:a0215ce6041d501f3155dc219712bc41252d0ab76474615b9700d63d4d9292af"}, {file = "aiohttp-3.8.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fd1ed388ea7fbed22c4968dd64bab0198de60750a25fe8c0c9d4bef5abe13824"}, {file = "aiohttp-3.8.5-cp36-cp36m-win32.whl", hash = "sha256:6e6783bcc45f397fdebc118d772103d751b54cddf5b60fbcc958382d7dd64f3e"}, {file = "aiohttp-3.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:b5411d82cddd212644cf9360879eb5080f0d5f7d809d03262c50dad02f01421a"}, {file = "aiohttp-3.8.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:01d4c0c874aa4ddfb8098e85d10b5e875a70adc63db91f1ae65a4b04d3344cda"}, {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5980a746d547a6ba173fd5ee85ce9077e72d118758db05d229044b469d9029a"}, {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a482e6da906d5e6e653be079b29bc173a48e381600161c9932d89dfae5942ef"}, {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80bd372b8d0715c66c974cf57fe363621a02f359f1ec81cba97366948c7fc873"}, {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1161b345c0a444ebcf46bf0a740ba5dcf50612fd3d0528883fdc0eff578006a"}, {file = "aiohttp-3.8.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd56db019015b6acfaaf92e1ac40eb8434847d9bf88b4be4efe5bfd260aee692"}, {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:153c2549f6c004d2754cc60603d4668899c9895b8a89397444a9c4efa282aaf4"}, {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4a01951fabc4ce26ab791da5f3f24dca6d9a6f24121746eb19756416ff2d881b"}, {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bfb9162dcf01f615462b995a516ba03e769de0789de1cadc0f916265c257e5d8"}, {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:7dde0009408969a43b04c16cbbe252c4f5ef4574ac226bc8815cd7342d2028b6"}, {file = "aiohttp-3.8.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4149d34c32f9638f38f544b3977a4c24052042affa895352d3636fa8bffd030a"}, {file = "aiohttp-3.8.5-cp37-cp37m-win32.whl", hash = "sha256:68c5a82c8779bdfc6367c967a4a1b2aa52cd3595388bf5961a62158ee8a59e22"}, {file = "aiohttp-3.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:2cf57fb50be5f52bda004b8893e63b48530ed9f0d6c96c84620dc92fe3cd9b9d"}, {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:eca4bf3734c541dc4f374ad6010a68ff6c6748f00451707f39857f429ca36ced"}, {file = "aiohttp-3.8.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1274477e4c71ce8cfe6c1ec2f806d57c015ebf84d83373676036e256bc55d690"}, {file = "aiohttp-3.8.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:28c543e54710d6158fc6f439296c7865b29e0b616629767e685a7185fab4a6b9"}, {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:910bec0c49637d213f5d9877105d26e0c4a4de2f8b1b29405ff37e9fc0ad52b8"}, {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5443910d662db951b2e58eb70b0fbe6b6e2ae613477129a5805d0b66c54b6cb7"}, {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e460be6978fc24e3df83193dc0cc4de46c9909ed92dd47d349a452ef49325b7"}, {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb1558def481d84f03b45888473fc5a1f35747b5f334ef4e7a571bc0dfcb11f8"}, {file = "aiohttp-3.8.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34dd0c107799dcbbf7d48b53be761a013c0adf5571bf50c4ecad5643fe9cfcd0"}, {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aa1990247f02a54185dc0dff92a6904521172a22664c863a03ff64c42f9b5410"}, {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0e584a10f204a617d71d359fe383406305a4b595b333721fa50b867b4a0a1548"}, {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a3cf433f127efa43fee6b90ea4c6edf6c4a17109d1d037d1a52abec84d8f2e42"}, {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:c11f5b099adafb18e65c2c997d57108b5bbeaa9eeee64a84302c0978b1ec948b"}, {file = "aiohttp-3.8.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:84de26ddf621d7ac4c975dbea4c945860e08cccde492269db4e1538a6a6f3c35"}, {file = "aiohttp-3.8.5-cp38-cp38-win32.whl", hash = "sha256:ab88bafedc57dd0aab55fa728ea10c1911f7e4d8b43e1d838a1739f33712921c"}, {file = "aiohttp-3.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:5798a9aad1879f626589f3df0f8b79b3608a92e9beab10e5fda02c8a2c60db2e"}, {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a6ce61195c6a19c785df04e71a4537e29eaa2c50fe745b732aa937c0c77169f3"}, {file = "aiohttp-3.8.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:773dd01706d4db536335fcfae6ea2440a70ceb03dd3e7378f3e815b03c97ab51"}, {file = "aiohttp-3.8.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f83a552443a526ea38d064588613aca983d0ee0038801bc93c0c916428310c28"}, {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f7372f7341fcc16f57b2caded43e81ddd18df53320b6f9f042acad41f8e049a"}, {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea353162f249c8097ea63c2169dd1aa55de1e8fecbe63412a9bc50816e87b761"}, {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d47ae48db0b2dcf70bc8a3bc72b3de86e2a590fc299fdbbb15af320d2659de"}, {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d827176898a2b0b09694fbd1088c7a31836d1a505c243811c87ae53a3f6273c1"}, {file = "aiohttp-3.8.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3562b06567c06439d8b447037bb655ef69786c590b1de86c7ab81efe1c9c15d8"}, {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4e874cbf8caf8959d2adf572a78bba17cb0e9d7e51bb83d86a3697b686a0ab4d"}, {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6809a00deaf3810e38c628e9a33271892f815b853605a936e2e9e5129762356c"}, {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:33776e945d89b29251b33a7e7d006ce86447b2cfd66db5e5ded4e5cd0340585c"}, {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eaeed7abfb5d64c539e2db173f63631455f1196c37d9d8d873fc316470dfbacd"}, {file = "aiohttp-3.8.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e91d635961bec2d8f19dfeb41a539eb94bd073f075ca6dae6c8dc0ee89ad6f91"}, {file = "aiohttp-3.8.5-cp39-cp39-win32.whl", hash = "sha256:00ad4b6f185ec67f3e6562e8a1d2b69660be43070bd0ef6fcec5211154c7df67"}, {file = "aiohttp-3.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:c0a9034379a37ae42dea7ac1e048352d96286626251862e448933c0f59cbd79c"}, {file = "aiohttp-3.8.5.tar.gz", hash = "sha256:b9552ec52cc147dbf1944ac7ac98af7602e51ea2dcd076ed194ca3c0d1c7d0bc"}, ] [package.dependencies] aiosignal = ">=1.1.2" async-timeout = ">=4.0.0a3,<5.0" attrs = ">=17.3.0" charset-normalizer = ">=2.0,<4.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" [package.extras] speedups = ["Brotli", "aiodns", "cchardet"] [[package]] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" optional = false python-versions = ">=3.7" files = [ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"}, {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"}, ] [package.dependencies] frozenlist = ">=1.1.0" [[package]] name = "annotated-types" version = "0.5.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.7" files = [ {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, ] [[package]] name = "aresponses" version = "2.1.6" description = "Asyncio response mocking. Similar to the responses library used for 'requests'" optional = false python-versions = ">=3.6" files = [ {file = "aresponses-2.1.6-py3-none-any.whl", hash = "sha256:06525f6911063f0f8d370cbc96bd273e6cddc89c7b5163ddf91e0c8abf148a32"}, {file = "aresponses-2.1.6.tar.gz", hash = "sha256:231dfa0756e39ca9f1e82212038f98e773d1ed9c0993caf2667e25ba535697ca"}, ] [package.dependencies] aiohttp = ">=3.1.0,<4.dev0" pytest-asyncio = "*" [[package]] name = "astroid" version = "2.15.6" description = "An abstract syntax tree for Python with inference support." optional = false python-versions = ">=3.7.2" files = [ {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"}, {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"}, ] [package.dependencies] lazy-object-proxy = ">=1.4.0" typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} wrapt = [ {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, ] [[package]] name = "async-timeout" version = "4.0.2" description = "Timeout context manager for asyncio programs" optional = false python-versions = ">=3.6" files = [ {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, ] [[package]] name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] dev = ["attrs[docs,tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] [[package]] name = "black" version = "23.7.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "blacken-docs" version = "1.15.0" description = "Run Black on Python code blocks in documentation files." optional = false python-versions = ">=3.8" files = [ {file = "blacken_docs-1.15.0-py3-none-any.whl", hash = "sha256:020657fd480f9f0a4dc82b9278390891ebd5216992b026e652c5b31d0e9c405d"}, {file = "blacken_docs-1.15.0.tar.gz", hash = "sha256:2915242add4e584738027b5bebafd4120c174a6c7645e1d8ce1c2f3265edc48a"}, ] [package.dependencies] black = ">=22.1.0" [[package]] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] [[package]] name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." optional = false python-versions = ">=3.6.1" files = [ {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, ] [[package]] name = "charset-normalizer" version = "3.2.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, ] [[package]] name = "click" version = "8.1.6" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "codespell" version = "2.2.5" description = "Codespell" optional = false python-versions = ">=3.7" files = [ {file = "codespell-2.2.5-py3-none-any.whl", hash = "sha256:efa037f54b73c84f7bd14ce8e853d5f822cdd6386ef0ff32e957a3919435b9ec"}, {file = "codespell-2.2.5.tar.gz", hash = "sha256:6d9faddf6eedb692bf80c9a94ec13ab4f5fb585aabae5f3750727148d7b5be56"}, ] [package.extras] dev = ["Pygments", "build", "chardet", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli"] hard-encoding-detection = ["chardet"] toml = ["tomli"] types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] [[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" 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" 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.2.7" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.7" files = [ {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, ] [package.dependencies] tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli"] [[package]] name = "dill" version = "0.3.6" description = "serialize all of python" optional = false python-versions = ">=3.7" files = [ {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"}, {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"}, ] [package.extras] graph = ["objgraph (>=1.7.2)"] [[package]] name = "distlib" version = "0.3.7" description = "Distribution utilities" optional = false python-versions = "*" files = [ {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, ] [[package]] name = "dparse" version = "0.6.3" description = "A parser for Python dependency files" optional = false python-versions = ">=3.6" files = [ {file = "dparse-0.6.3-py3-none-any.whl", hash = "sha256:0d8fe18714056ca632d98b24fbfc4e9791d4e47065285ab486182288813a5318"}, {file = "dparse-0.6.3.tar.gz", hash = "sha256:27bb8b4bcaefec3997697ba3f6e06b2447200ba273c0b085c3d012a04571b528"}, ] [package.dependencies] packaging = "*" tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] conda = ["pyyaml"] pipenv = ["pipenv (<=2022.12.19)"] [[package]] name = "exceptiongroup" version = "1.1.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"}, {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"}, ] [package.extras] test = ["pytest (>=6)"] [[package]] name = "filelock" version = "3.12.2" description = "A platform independent file lock." optional = false python-versions = ">=3.7" files = [ {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "frozenlist" version = "1.4.0" description = "A list-like structure which implements collections.abc.MutableSequence" optional = false python-versions = ">=3.8" files = [ {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab"}, {file = "frozenlist-1.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559"}, {file = "frozenlist-1.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c"}, {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b"}, {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea"}, {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326"}, {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963"}, {file = "frozenlist-1.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300"}, {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b"}, {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8"}, {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb"}, {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9"}, {file = "frozenlist-1.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62"}, {file = "frozenlist-1.4.0-cp310-cp310-win32.whl", hash = "sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0"}, {file = "frozenlist-1.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956"}, {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95"}, {file = "frozenlist-1.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3"}, {file = "frozenlist-1.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc"}, {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839"}, {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c"}, {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f"}, {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b"}, {file = "frozenlist-1.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b"}, {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472"}, {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01"}, {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f"}, {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467"}, {file = "frozenlist-1.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb"}, {file = "frozenlist-1.4.0-cp311-cp311-win32.whl", hash = "sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431"}, {file = "frozenlist-1.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1"}, {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f0ed05f5079c708fe74bf9027e95125334b6978bf07fd5ab923e9e55e5fbb9d3"}, {file = "frozenlist-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ca265542ca427bf97aed183c1676e2a9c66942e822b14dc6e5f42e038f92a503"}, {file = "frozenlist-1.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:491e014f5c43656da08958808588cc6c016847b4360e327a62cb308c791bd2d9"}, {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17ae5cd0f333f94f2e03aaf140bb762c64783935cc764ff9c82dff626089bebf"}, {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e78fb68cf9c1a6aa4a9a12e960a5c9dfbdb89b3695197aa7064705662515de2"}, {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5655a942f5f5d2c9ed93d72148226d75369b4f6952680211972a33e59b1dfdc"}, {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11b0746f5d946fecf750428a95f3e9ebe792c1ee3b1e96eeba145dc631a9672"}, {file = "frozenlist-1.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e66d2a64d44d50d2543405fb183a21f76b3b5fd16f130f5c99187c3fb4e64919"}, {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:88f7bc0fcca81f985f78dd0fa68d2c75abf8272b1f5c323ea4a01a4d7a614efc"}, {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:5833593c25ac59ede40ed4de6d67eb42928cca97f26feea219f21d0ed0959b79"}, {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:fec520865f42e5c7f050c2a79038897b1c7d1595e907a9e08e3353293ffc948e"}, {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:b826d97e4276750beca7c8f0f1a4938892697a6bcd8ec8217b3312dad6982781"}, {file = "frozenlist-1.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ceb6ec0a10c65540421e20ebd29083c50e6d1143278746a4ef6bcf6153171eb8"}, {file = "frozenlist-1.4.0-cp38-cp38-win32.whl", hash = "sha256:2b8bcf994563466db019fab287ff390fffbfdb4f905fc77bc1c1d604b1c689cc"}, {file = "frozenlist-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:a6c8097e01886188e5be3e6b14e94ab365f384736aa1fca6a0b9e35bd4a30bc7"}, {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6c38721585f285203e4b4132a352eb3daa19121a035f3182e08e437cface44bf"}, {file = "frozenlist-1.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a0c6da9aee33ff0b1a451e867da0c1f47408112b3391dd43133838339e410963"}, {file = "frozenlist-1.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:93ea75c050c5bb3d98016b4ba2497851eadf0ac154d88a67d7a6816206f6fa7f"}, {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f61e2dc5ad442c52b4887f1fdc112f97caeff4d9e6ebe78879364ac59f1663e1"}, {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa384489fefeb62321b238e64c07ef48398fe80f9e1e6afeff22e140e0850eef"}, {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10ff5faaa22786315ef57097a279b833ecab1a0bfb07d604c9cbb1c4cdc2ed87"}, {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:007df07a6e3eb3e33e9a1fe6a9db7af152bbd8a185f9aaa6ece10a3529e3e1c6"}, {file = "frozenlist-1.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4f399d28478d1f604c2ff9119907af9726aed73680e5ed1ca634d377abb087"}, {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5374b80521d3d3f2ec5572e05adc94601985cc526fb276d0c8574a6d749f1b3"}, {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ce31ae3e19f3c902de379cf1323d90c649425b86de7bbdf82871b8a2a0615f3d"}, {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7211ef110a9194b6042449431e08c4d80c0481e5891e58d429df5899690511c2"}, {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:556de4430ce324c836789fa4560ca62d1591d2538b8ceb0b4f68fb7b2384a27a"}, {file = "frozenlist-1.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7645a8e814a3ee34a89c4a372011dcd817964ce8cb273c8ed6119d706e9613e3"}, {file = "frozenlist-1.4.0-cp39-cp39-win32.whl", hash = "sha256:19488c57c12d4e8095a922f328df3f179c820c212940a498623ed39160bc3c2f"}, {file = "frozenlist-1.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:6221d84d463fb110bdd7619b69cb43878a11d51cbb9394ae3105d082d5199167"}, {file = "frozenlist-1.4.0.tar.gz", hash = "sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251"}, ] [[package]] name = "identify" version = "2.5.25" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ {file = "identify-2.5.25-py2.py3-none-any.whl", hash = "sha256:9df2489842707d431b38ce3410ef8df40da5b10a3e28a3fcac1a42523e956409"}, {file = "identify-2.5.25.tar.gz", hash = "sha256:db4de0e758c0db8f81996816cd2f3f2f8c5c8d49a7fd02f3b4109aac6fd80e29"}, ] [package.extras] license = ["ukkonen"] [[package]] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, ] [package.extras] colors = ["colorama (>=0.4.3)"] pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, ] [package.dependencies] MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] [[package]] name = "lazy-object-proxy" version = "1.9.0" description = "A fast and thorough lazy object proxy." optional = false python-versions = ">=3.7" files = [ {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] [[package]] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.7" files = [ {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] [[package]] name = "marshmallow" version = "3.20.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." optional = false python-versions = ">=3.8" files = [ {file = "marshmallow-3.20.1-py3-none-any.whl", hash = "sha256:684939db93e80ad3561392f47be0230743131560a41c5110684c16e21ade0a5c"}, {file = "marshmallow-3.20.1.tar.gz", hash = "sha256:5d2371bbe42000f2b3fb5eaa065224df7d8f8597bc19a1bbfa5bfe7fba8da889"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] dev = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] docs = ["alabaster (==0.7.13)", "autodocsumm (==0.2.11)", "sphinx (==7.0.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] lint = ["flake8 (==6.0.0)", "flake8-bugbear (==23.7.10)", "mypy (==1.4.1)", "pre-commit (>=2.4,<4.0)"] tests = ["pytest", "pytz", "simplejson"] [[package]] name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] [[package]] name = "multidict" version = "6.0.4" description = "multidict implementation" optional = false python-versions = ">=3.7" files = [ {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8"}, {file = "multidict-6.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171"}, {file = "multidict-6.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7"}, {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b"}, {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547"}, {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569"}, {file = "multidict-6.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93"}, {file = "multidict-6.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98"}, {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0"}, {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988"}, {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc"}, {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0"}, {file = "multidict-6.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5"}, {file = "multidict-6.0.4-cp310-cp310-win32.whl", hash = "sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8"}, {file = "multidict-6.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc"}, {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03"}, {file = "multidict-6.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3"}, {file = "multidict-6.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba"}, {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9"}, {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982"}, {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe"}, {file = "multidict-6.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710"}, {file = "multidict-6.0.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c"}, {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4"}, {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a"}, {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c"}, {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed"}, {file = "multidict-6.0.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461"}, {file = "multidict-6.0.4-cp311-cp311-win32.whl", hash = "sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636"}, {file = "multidict-6.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0"}, {file = "multidict-6.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78"}, {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f"}, {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603"}, {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac"}, {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9"}, {file = "multidict-6.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2"}, {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde"}, {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe"}, {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067"}, {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87"}, {file = "multidict-6.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d"}, {file = "multidict-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775"}, {file = "multidict-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e"}, {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c"}, {file = "multidict-6.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161"}, {file = "multidict-6.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11"}, {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e"}, {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d"}, {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2"}, {file = "multidict-6.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258"}, {file = "multidict-6.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52"}, {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660"}, {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951"}, {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60"}, {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d"}, {file = "multidict-6.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1"}, {file = "multidict-6.0.4-cp38-cp38-win32.whl", hash = "sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779"}, {file = "multidict-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480"}, {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664"}, {file = "multidict-6.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35"}, {file = "multidict-6.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60"}, {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706"}, {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d"}, {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca"}, {file = "multidict-6.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1"}, {file = "multidict-6.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449"}, {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf"}, {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063"}, {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a"}, {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176"}, {file = "multidict-6.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95"}, {file = "multidict-6.0.4-cp39-cp39-win32.whl", hash = "sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313"}, {file = "multidict-6.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2"}, {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] [[package]] name = "mypy" version = "1.4.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.7" files = [ {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typing-extensions = ">=4.1.0" [package.extras] dmypy = ["psutil (>=4.0)"] install-types = ["pip"] python2 = ["typed-ast (>=1.4.0,<2)"] reports = ["lxml"] [[package]] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false python-versions = ">=3.5" files = [ {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] [[package]] name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] setuptools = "*" [[package]] name = "packaging" version = "23.0" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] [[package]] name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false python-versions = ">=3.7" files = [ {file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"}, {file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"}, ] [[package]] name = "platformdirs" version = "3.9.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ {file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, {file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, ] [package.extras] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" version = "1.2.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.7" files = [ {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" version = "3.3.3" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" files = [ {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, ] [package.dependencies] cfgv = ">=2.0.0" identify = ">=1.0.0" nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" [[package]] name = "pre-commit-hooks" version = "4.4.0" description = "Some out-of-the-box hooks for pre-commit." optional = false python-versions = ">=3.7" files = [ {file = "pre_commit_hooks-4.4.0-py2.py3-none-any.whl", hash = "sha256:fc8837335476221ccccda3d176ed6ae29fe58753ce7e8b7863f5d0f987328fc6"}, {file = "pre_commit_hooks-4.4.0.tar.gz", hash = "sha256:7011eed8e1a25cde94693da009cba76392194cecc2f3f06c51a44ea6ad6c2af9"}, ] [package.dependencies] "ruamel.yaml" = ">=0.15" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [[package]] name = "pydantic" version = "2.0.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ {file = "pydantic-2.0.3-py3-none-any.whl", hash = "sha256:614eb3321eb600c81899a88fa9858b008e3c79e0d4f1b49ab1f516b4b0c27cfb"}, {file = "pydantic-2.0.3.tar.gz", hash = "sha256:94f13e0dcf139a5125e88283fc999788d894e14ed90cf478bcc2ee50bd4fc630"}, ] [package.dependencies] annotated-types = ">=0.4.0" pydantic-core = "2.3.0" typing-extensions = ">=4.6.1" [package.extras] email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" version = "2.3.0" description = "" optional = false python-versions = ">=3.7" files = [ {file = "pydantic_core-2.3.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4542c98b8364b976593703a2dda97377433b102f380b61bc3a2cbc2fbdae1d1f"}, {file = "pydantic_core-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9342de50824b40f55d2600f66c6f9a91a3a24851eca39145a749a3dc804ee599"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:539432f911686cb80284c30b33eaf9f4fd9a11e1111fe0dc98fdbdce69b49821"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38a0e7ee65c8999394d92d9c724434cb629279d19844f2b69d9bbc46dc8b8b61"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:e3ed6834cc005798187a56c248a2240207cb8ffdda1c89e9afda4c3d526c2ea0"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:e72ac299a6bf732a60852d052acf3999d234686755a02ba111e85e7ebf8155b1"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:616b3451b05ca63b8f433c627f68046b39543faeaa4e50d8c6699a2a1e4b85a5"}, {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:adcb9c8848e15c613e483e0b99767ae325af27fe0dbd866df01fe5849d06e6e1"}, {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:464bf799b422be662e5e562e62beeffc9eaa907d381a9d63a2556615bbda286d"}, {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4638ebc17de08c2f3acba557efeb6f195c88b7299d8c55c0bb4e20638bbd4d03"}, {file = "pydantic_core-2.3.0-cp310-none-win32.whl", hash = "sha256:9ff322c7e1030543d35d83bb521b69114d3d150750528d7757544f639def9ad6"}, {file = "pydantic_core-2.3.0-cp310-none-win_amd64.whl", hash = "sha256:4824eb018f0a4680b1e434697a9bf3f41c7799b80076d06530cbbd212e040ccc"}, {file = "pydantic_core-2.3.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:0aa429578e23885b3984c49d687cd05ab06f0b908ea1711a8bf7e503b7f97160"}, {file = "pydantic_core-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20d710c1f79af930b8891bcebd84096798e4387ab64023ef41521d58f21277d3"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f45d4d7481d6f09cb9e35c72caa0e50add4a30bb08c04c5fe5956a0158633"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bcfb7be905aa849bd882262e1df3f75b564e2f708b4b4c7ad2d3deaf5410562"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:85cd9c0af34e371390e3cb2f3a470b0b40cc07568c1e966c638c49062be6352d"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:37c5028cebdf731298724070838fb3a71ef1fbd201d193d311ac2cbdbca25a23"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:e4208f23f12d0ad206a07a489ef4cb15722c10b62774c4460ee4123250be938e"}, {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c24465dd11b65c8510f251b095fc788c7c91481c81840112fe3f76c30793a455"}, {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3cd7ee8bbfab277ab56e272221886fd33a1b5943fbf45ae9195aa6a48715a8a0"}, {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0fc7e0b056b66cc536e97ef60f48b3b289f6b3b62ac225afd4b22a42434617bf"}, {file = "pydantic_core-2.3.0-cp311-none-win32.whl", hash = "sha256:4788135db4bd83a5edc3522b11544b013be7d25b74b155e08dd3b20cd6663bbb"}, {file = "pydantic_core-2.3.0-cp311-none-win_amd64.whl", hash = "sha256:f93c867e5e85584a28c6a6feb6f2086d717266eb5d1210d096dd717b7f4dec04"}, {file = "pydantic_core-2.3.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:73f62bb7fd862d9bcd886e10612bade6fe042eda8b47e8c129892bcfb7b45e84"}, {file = "pydantic_core-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d889d498fce64bfcd8adf1a78579a7f626f825cbeb2956a24a29b35f9a1df32"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d55e38a89ec2ae17b2fa7ffeda6b70f63afab1888bd0d57aaa7b7879760acb4"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1aefebb506bc1fe355d91d25f12bcdea7f4d7c2d9f0f6716dd025543777c99a5"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:6441a29f42585f085db0c04cd0557d4cbbb46fa68a0972409b1cfe9f430280c1"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:47e8f034be31390a8f525431eb5e803a78ce7e2e11b32abf5361a972e14e6b61"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:ad814864aba263be9c83ada44a95f72d10caabbf91589321f95c29c902bdcff0"}, {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9eff3837d447fccf2ac38c259b14ab9cbde700df355a45a1f3ff244d5e78f8b6"}, {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:534f3f63c000f08050c6f7f4378bf2b52d7ba9214e9d35e3f60f7ad24a4d6425"}, {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ef6a222d54f742c24f6b143aab088702db3a827b224e75b9dd28b38597c595fe"}, {file = "pydantic_core-2.3.0-cp312-none-win32.whl", hash = "sha256:4e26944e64ecc1d7b19db954c0f7b471f3b141ec8e1a9f57cfe27671525cd248"}, {file = "pydantic_core-2.3.0-cp312-none-win_amd64.whl", hash = "sha256:019c5c41941438570dfc7d3f0ae389b2425add1775a357ce1e83ed1434f943d6"}, {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:27c1bbfb9d84a75cf33b7f19b53c29eb7ead99b235fce52aced5507174ab8f98"}, {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:7cb496e934b71f1ade844ab91d6ccac78a3520e5df02fdb2357f85a71e541e69"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af2d43b1978958d91351afbcc9b4d0cfe144c46c61740e82aaac8bb39ab1a4d"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3097c39d7d4e8dba2ef86de171dcccad876c36d8379415ba18a5a4d0533510"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:dd3b023f3317dbbbc775e43651ce1a31a9cea46216ad0b5be37afc18a2007699"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:27babb9879bf2c45ed655d02639f4c30e2b9ef1b71ce59c2305bbf7287910a18"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:2183a9e18cdc0de53bdaa1675f237259162abeb62d6ac9e527c359c1074dc55d"}, {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c089d8e7f1b4db08b2f8e4107304eec338df046275dad432635a9be9531e2fc8"}, {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f10aa5452b865818dd0137f568d443f5e93b60a27080a01aa4b7512c7ba13a3"}, {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f642313d559f9d9a00c4de6820124059cc3342a0d0127b18301de2c680d5ea40"}, {file = "pydantic_core-2.3.0-cp37-none-win32.whl", hash = "sha256:45327fc57afbe3f2c3d7f54a335d5cecee8a9fdb3906a2fbed8af4092f4926df"}, {file = "pydantic_core-2.3.0-cp37-none-win_amd64.whl", hash = "sha256:e427b66596a6441a5607dfc0085b47d36073f88da7ac48afd284263b9b99e6ce"}, {file = "pydantic_core-2.3.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:0b3d781c71b8bfb621ef23b9c874933e2cd33237c1a65cc20eeb37437f8e7e18"}, {file = "pydantic_core-2.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad46027dbd5c1db87dc0b49becbe23093b143a20302028d387dae37ee5ef95f5"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39aa09ed7ce2a648c904f79032d16dda29e6913112af8465a7bf710eef23c7ca"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05b4bf8c58409586a7a04c858a86ab10f28c6c1a7c33da65e0326c59d5b0ab16"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:ba2b807d2b62c446120906b8580cddae1d76d3de4efbb95ccc87f5e35c75b4b2"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:ea955e4ed21f4bbb9b83fea09fc6af0bed82e69ecf6b35ec89237a0a49633033"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:06884c07956526ac9ebfef40fe21a11605569b8fc0e2054a375fb39c978bf48f"}, {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f868e731a18b403b88aa434d960489ceeed0ddeb44ebc02389540731a67705e0"}, {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cb08fab0fc1db15c277b72e33ac74ad9c0c789413da8984a3eacb22a94b42ef4"}, {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6ca34c29fbd6592de5fd39e80c1993634d704c4e7e14ba54c87b2c7c53da68fe"}, {file = "pydantic_core-2.3.0-cp38-none-win32.whl", hash = "sha256:cd782807d35c8a41aaa7d30b5107784420eefd9fdc1c760d86007d43ae00b15d"}, {file = "pydantic_core-2.3.0-cp38-none-win_amd64.whl", hash = "sha256:01f56d5ee70b1d39c0fd08372cc5142274070ab7181d17c86035f130eebc05b8"}, {file = "pydantic_core-2.3.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:78b1ac0151271ce62bc2b33755f1043eda6a310373143a2f27e2bcd3d5fc8633"}, {file = "pydantic_core-2.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64bfd2c35a2c350f73ac52dc134d8775f93359c4c969280a6fe5301b5b6e7431"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:937c0fe9538f1212b62df6a68f8d78df3572fe3682d9a0dd8851eac8a4e46063"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d965c7c4b40d1cedec9188782e98bd576f9a04868835604200c3a6e817b824f"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:ad442b8585ed4a3c2d22e4bf7b465d9b7d281e055b09719a8aeb5b576422dc9b"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:4bf20c9722821fce766e685718e739deeccc60d6bc7be5029281db41f999ee0c"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:f3dd5333049b5b3faa739e0f40b77cc8b7a1aded2f2da0e28794c81586d7b08a"}, {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dc5f516b24d24bc9e8dd9305460899f38302b3c4f9752663b396ef9848557bf"}, {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:055f7ea6b1fbb37880d66d70eefd22dd319b09c79d2cb99b1dbfeb34b653b0b2"}, {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:af693a89db6d6ac97dd84dd7769b3f2bd9007b578127d0e7dda03053f4d3b34b"}, {file = "pydantic_core-2.3.0-cp39-none-win32.whl", hash = "sha256:f60e31e3e15e8c294bf70c60f8ae4d0c3caf3af8f26466e9aa8ea4c01302749b"}, {file = "pydantic_core-2.3.0-cp39-none-win_amd64.whl", hash = "sha256:2b79f3681481f4424d7845cc7a261d5a4baa810d656b631fa844dc9967b36a7b"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a666134b41712e30a71afaa26deeb4da374179f769fa49784cdf0e7698880fab"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c119e9227487ad3d7c3c737d896afe548a6be554091f9745da1f4b489c40561"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73929a2fb600a2333fce2efd92596cff5e6bf8946e20e93c067b220760064862"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:41bbc2678a5b6a19371b2cb51f30ccea71f0c14b26477d2d884fed761cea42c7"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dcbff997f47d45bf028bda4c3036bb3101e89a3df271281d392b6175f71c71d1"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:afa8808159169368b66e4fbeafac6c6fd8f26246dc4d0dcc2caf94bd9cf1b828"}, {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:12be3b5f54f8111ca38e6b7277f26c23ba5cb3344fae06f879a0a93dfc8b479e"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ed5babdcd3d052ba5cf8832561f18df20778c7ccf12587b2d82f7bf3bf259a0e"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d642e5c029e2acfacf6aa0a7a3e822086b3b777c70d364742561f9ca64c1ffc"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ba3073eb38a1294e8c7902989fb80a7a147a69db2396818722bd078476586a0"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5146a6749b1905e04e62e0ad4622f079e5582f8b3abef5fb64516c623127908"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:deeb64335f489c3c11949cbd1d1668b3f1fb2d1c6a5bf40e126ef7bf95f9fa40"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:31acc37288b8e69e4849f618c3d5cf13b58077c1a1ff9ade0b3065ba974cd385"}, {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e09d9f6d722de9d4c1c5f122ea9bc6b25a05f975457805af4dcab7b0128aacbf"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ba6a8cf089222a171b8f84e6ec2d10f7a9d14f26be3a347b14775a8741810676"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1fd1b24e9bcddcb168437686677104e205c8e25b066e73ffdf331d3bb8792b"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eda1a89c4526826c0a87d33596a4cd15b8f58e9250f503e39af1699ba9c878e8"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3e9a18401a28db4358da2e191508702dbf065f2664c710708cdf9552b9fa50c"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a439fd0d45d51245bbde799726adda5bd18aed3fa2b01ab2e6a64d6d13776fa3"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:bf6a1d2c920cc9528e884850a4b2ee7629e3d362d5c44c66526d4097bbb07a1a"}, {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e33fcbea3b63a339dd94de0fc442fefacfe681cc7027ce63f67af9f7ceec7422"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:bf3ed993bdf4754909f175ff348cf8f78d4451215b8aa338633f149ca3b1f37a"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7584171eb3115acd4aba699bc836634783f5bd5aab131e88d8eeb8a3328a4a72"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1624baa76d1740711b2048f302ae9a6d73d277c55a8c3e88b53b773ebf73a971"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:06f33f695527f5a86e090f208978f9fd252c9cfc7e869d3b679bd71f7cb2c1fa"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7ecf0a67b212900e92f328181fed02840d74ed39553cdb38d27314e2b9c89dfa"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45fa1e8ad6f4367ad73674ca560da8e827cc890eaf371f3ee063d6d7366a207b"}, {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8d0dbcc57839831ae79fd24b1b83d42bc9448d79feaf3ed3fb5cbf94ffbf3eb7"}, {file = "pydantic_core-2.3.0.tar.gz", hash = "sha256:5cfb5ac4e82c47d5dc25b209dd4c3989e284b80109f9e08b33c895080c424b4f"}, ] [package.dependencies] typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pylint" version = "2.17.4" description = "python code static checker" optional = false python-versions = ">=3.7.2" files = [ {file = "pylint-2.17.4-py3-none-any.whl", hash = "sha256:7a1145fb08c251bdb5cca11739722ce64a63db479283d10ce718b2460e54123c"}, {file = "pylint-2.17.4.tar.gz", hash = "sha256:5dcf1d9e19f41f38e4e85d10f511e5b9c35e1aa74251bf95cdd8cb23584e2db1"}, ] [package.dependencies] astroid = ">=2.15.4,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, ] isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" [package.extras] spelling = ["pyenchant (>=3.2,<4.0)"] testutils = ["gitpython (>3)"] [[package]] name = "pytest" version = "7.4.0" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" version = "0.21.1" description = "Pytest support for asyncio" optional = false python-versions = ">=3.7" files = [ {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] pytest = ">=7.0.0" [package.extras] docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.7" files = [ {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, ] [package.dependencies] coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" optional = false python-versions = ">=3.6" files = [ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] name = "requests" version = "2.31.0" description = "Python HTTP for Humans." optional = false python-versions = ">=3.7" files = [ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruamel-yaml" version = "0.17.32" 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" files = [ {file = "ruamel.yaml-0.17.32-py3-none-any.whl", hash = "sha256:23cd2ed620231677564646b0c6a89d138b6822a0d78656df7abda5879ec4f447"}, {file = "ruamel.yaml-0.17.32.tar.gz", hash = "sha256:ec939063761914e14542972a5cba6d33c23b0859ab6342f61cf070cfc600efc2"}, ] [package.dependencies] "ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.12\""} [package.extras] docs = ["ryd"] jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] [[package]] name = "ruamel-yaml-clib" version = "0.2.7" description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" optional = false python-versions = ">=3.5" files = [ {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"}, {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"}, {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"}, {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"}, {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"}, {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"}, {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"}, {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"}, ] [[package]] name = "ruff" version = "0.0.280" description = "An extremely fast Python linter, written in Rust." optional = false python-versions = ">=3.7" files = [ {file = "ruff-0.0.280-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:48ed5aca381050a4e2f6d232db912d2e4e98e61648b513c350990c351125aaec"}, {file = "ruff-0.0.280-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:ef6ee3e429fd29d6a5ceed295809e376e6ece5b0f13c7e703efaf3d3bcb30b96"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d878370f7e9463ac40c253724229314ff6ebe4508cdb96cb536e1af4d5a9cd4f"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83e8f372fa5627eeda5b83b5a9632d2f9c88fc6d78cead7e2a1f6fb05728d137"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7008fc6ca1df18b21fa98bdcfc711dad5f94d0fc3c11791f65e460c48ef27c82"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fe7118c1eae3fda17ceb409629c7f3b5a22dffa7caf1f6796776936dca1fe653"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:37359cd67d2af8e09110a546507c302cbea11c66a52d2a9b6d841d465f9962d4"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd58af46b0221efb95966f1f0f7576df711cb53e50d2fdb0e83c2f33360116a4"}, {file = "ruff-0.0.280-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e7c15828d09f90e97bea8feefcd2907e8c8ce3a1f959c99f9b4b3469679f33c"}, {file = "ruff-0.0.280-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:2dae8f2d9c44c5c49af01733c2f7956f808db682a4193180dedb29dd718d7bbe"}, {file = "ruff-0.0.280-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5f972567163a20fb8c2d6afc60c2ea5ef8b68d69505760a8bd0377de8984b4f6"}, {file = "ruff-0.0.280-py3-none-musllinux_1_2_i686.whl", hash = "sha256:8ffa7347ad11643f29de100977c055e47c988cd6d9f5f5ff83027600b11b9189"}, {file = "ruff-0.0.280-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a37dab70114671d273f203268f6c3366c035fe0c8056614069e90a65e614bfc"}, {file = "ruff-0.0.280-py3-none-win32.whl", hash = "sha256:7784e3606352fcfb193f3cd22b2e2117c444cb879ef6609ec69deabd662b0763"}, {file = "ruff-0.0.280-py3-none-win_amd64.whl", hash = "sha256:4a7d52457b5dfcd3ab24b0b38eefaead8e2dca62b4fbf10de4cd0938cf20ce30"}, {file = "ruff-0.0.280-py3-none-win_arm64.whl", hash = "sha256:b7de5b8689575918e130e4384ed9f539ce91d067c0a332aedef6ca7188adac2d"}, {file = "ruff-0.0.280.tar.gz", hash = "sha256:581c43e4ac5e5a7117ad7da2120d960a4a99e68ec4021ec3cd47fe1cf78f8380"}, ] [[package]] name = "safety" version = "2.4.0b1" description = "Checks installed dependencies for known vulnerabilities and licenses." optional = false python-versions = "*" files = [ {file = "safety-2.4.0b1-py3-none-any.whl", hash = "sha256:95570bfdb0ca17bb2acdf34963966ce8f8b26bffeb76722d98251cee2f81b215"}, {file = "safety-2.4.0b1.tar.gz", hash = "sha256:26b3000eec09f64fdd323db29c44c0446607b0c9b4ce65c3f8f9570e2c640958"}, ] [package.dependencies] Click = ">=8.0.2" dparse = ">=0.6.2" jinja2 = {version = ">=3.1.0", markers = "python_version >= \"3.7\""} marshmallow = {version = ">=3.15.0", markers = "python_version >= \"3.7\""} packaging = ">=21.0,<=23.0" requests = "*" "ruamel.yaml" = ">=0.17.21" setuptools = {version = ">=65.5.1", markers = "python_version >= \"3.7\""} urllib3 = ">=1.26.5" [package.extras] github = ["pygithub (>=1.43.3)"] gitlab = ["python-gitlab (>=1.3.0)"] [[package]] name = "setuptools" version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.7" files = [ {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.7" files = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] [[package]] name = "tomlkit" version = "0.11.8" description = "Style preserving TOML library" optional = false python-versions = ">=3.7" files = [ {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ] [[package]] name = "typing-extensions" version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" optional = false python-versions = ">=3.7" files = [ {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "urllib3" version = "2.0.4" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.7" files = [ {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" version = "20.24.1" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ {file = "virtualenv-20.24.1-py3-none-any.whl", hash = "sha256:01aacf8decd346cf9a865ae85c0cdc7f64c8caa07ff0d8b1dfc1733d10677442"}, {file = "virtualenv-20.24.1.tar.gz", hash = "sha256:2ef6a237c31629da6442b0bcaa3999748108c7166318d1f55cc9f8d7294e97bd"}, ] [package.dependencies] distlib = ">=0.3.6,<1" filelock = ">=3.12,<4" platformdirs = ">=3.5.1,<4" [package.extras] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] [[package]] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, ] [[package]] name = "yamllint" version = "1.32.0" description = "A linter for YAML files." optional = false python-versions = ">=3.7" files = [ {file = "yamllint-1.32.0-py3-none-any.whl", hash = "sha256:d97a66e48da820829d96077d76b8dfbe6c6140f106e558dae87e81ac4e6b30b7"}, {file = "yamllint-1.32.0.tar.gz", hash = "sha256:d01dde008c65de5b235188ab3110bebc59d18e5c65fc8a58267cd211cd9df34a"}, ] [package.dependencies] pathspec = ">=0.5.3" pyyaml = "*" [package.extras] dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [[package]] name = "yarl" version = "1.9.2" description = "Yet another URL library" optional = false python-versions = ">=3.7" files = [ {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82"}, {file = "yarl-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8"}, {file = "yarl-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9"}, {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560"}, {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac"}, {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea"}, {file = "yarl-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608"}, {file = "yarl-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5"}, {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0"}, {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4"}, {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095"}, {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3"}, {file = "yarl-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528"}, {file = "yarl-1.9.2-cp310-cp310-win32.whl", hash = "sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3"}, {file = "yarl-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde"}, {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6"}, {file = "yarl-1.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb"}, {file = "yarl-1.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0"}, {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2"}, {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191"}, {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d"}, {file = "yarl-1.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7"}, {file = "yarl-1.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6"}, {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8"}, {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9"}, {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be"}, {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7"}, {file = "yarl-1.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a"}, {file = "yarl-1.9.2-cp311-cp311-win32.whl", hash = "sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8"}, {file = "yarl-1.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051"}, {file = "yarl-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38a3928ae37558bc1b559f67410df446d1fbfa87318b124bf5032c31e3447b74"}, {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac9bb4c5ce3975aeac288cfcb5061ce60e0d14d92209e780c93954076c7c4367"}, {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3da8a678ca8b96c8606bbb8bfacd99a12ad5dd288bc6f7979baddd62f71c63ef"}, {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13414591ff516e04fcdee8dc051c13fd3db13b673c7a4cb1350e6b2ad9639ad3"}, {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf74d08542c3a9ea97bb8f343d4fcbd4d8f91bba5ec9d5d7f792dbe727f88938"}, {file = "yarl-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e7221580dc1db478464cfeef9b03b95c5852cc22894e418562997df0d074ccc"}, {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:494053246b119b041960ddcd20fd76224149cfea8ed8777b687358727911dd33"}, {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:52a25809fcbecfc63ac9ba0c0fb586f90837f5425edfd1ec9f3372b119585e45"}, {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:e65610c5792870d45d7b68c677681376fcf9cc1c289f23e8e8b39c1485384185"}, {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:1b1bba902cba32cdec51fca038fd53f8beee88b77efc373968d1ed021024cc04"}, {file = "yarl-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:662e6016409828ee910f5d9602a2729a8a57d74b163c89a837de3fea050c7582"}, {file = "yarl-1.9.2-cp37-cp37m-win32.whl", hash = "sha256:f364d3480bffd3aa566e886587eaca7c8c04d74f6e8933f3f2c996b7f09bee1b"}, {file = "yarl-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6a5883464143ab3ae9ba68daae8e7c5c95b969462bbe42e2464d60e7e2698368"}, {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5610f80cf43b6202e2c33ba3ec2ee0a2884f8f423c8f4f62906731d876ef4fac"}, {file = "yarl-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9a4e67ad7b646cd6f0938c7ebfd60e481b7410f574c560e455e938d2da8e0f4"}, {file = "yarl-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:83fcc480d7549ccebe9415d96d9263e2d4226798c37ebd18c930fce43dfb9574"}, {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fcd436ea16fee7d4207c045b1e340020e58a2597301cfbcfdbe5abd2356c2fb"}, {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84e0b1599334b1e1478db01b756e55937d4614f8654311eb26012091be109d59"}, {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3458a24e4ea3fd8930e934c129b676c27452e4ebda80fbe47b56d8c6c7a63a9e"}, {file = "yarl-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:838162460b3a08987546e881a2bfa573960bb559dfa739e7800ceeec92e64417"}, {file = "yarl-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4e2d08f07a3d7d3e12549052eb5ad3eab1c349c53ac51c209a0e5991bbada78"}, {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de119f56f3c5f0e2fb4dee508531a32b069a5f2c6e827b272d1e0ff5ac040333"}, {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:149ddea5abf329752ea5051b61bd6c1d979e13fbf122d3a1f9f0c8be6cb6f63c"}, {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:674ca19cbee4a82c9f54e0d1eee28116e63bc6fd1e96c43031d11cbab8b2afd5"}, {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:9b3152f2f5677b997ae6c804b73da05a39daa6a9e85a512e0e6823d81cdad7cc"}, {file = "yarl-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415d5a4b080dc9612b1b63cba008db84e908b95848369aa1da3686ae27b6d2b"}, {file = "yarl-1.9.2-cp38-cp38-win32.whl", hash = "sha256:f7a3d8146575e08c29ed1cd287068e6d02f1c7bdff8970db96683b9591b86ee7"}, {file = "yarl-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:63c48f6cef34e6319a74c727376e95626f84ea091f92c0250a98e53e62c77c72"}, {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75df5ef94c3fdc393c6b19d80e6ef1ecc9ae2f4263c09cacb178d871c02a5ba9"}, {file = "yarl-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c027a6e96ef77d401d8d5a5c8d6bc478e8042f1e448272e8d9752cb0aff8b5c8"}, {file = "yarl-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3b078dbe227f79be488ffcfc7a9edb3409d018e0952cf13f15fd6512847f3f7"}, {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59723a029760079b7d991a401386390c4be5bfec1e7dd83e25a6a0881859e716"}, {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b03917871bf859a81ccb180c9a2e6c1e04d2f6a51d953e6a5cdd70c93d4e5a2a"}, {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1012fa63eb6c032f3ce5d2171c267992ae0c00b9e164efe4d73db818465fac3"}, {file = "yarl-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a74dcbfe780e62f4b5a062714576f16c2f3493a0394e555ab141bf0d746bb955"}, {file = "yarl-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c56986609b057b4839968ba901944af91b8e92f1725d1a2d77cbac6972b9ed1"}, {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c315df3293cd521033533d242d15eab26583360b58f7ee5d9565f15fee1bef4"}, {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:b7232f8dfbd225d57340e441d8caf8652a6acd06b389ea2d3222b8bc89cbfca6"}, {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:53338749febd28935d55b41bf0bcc79d634881195a39f6b2f767870b72514caf"}, {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:066c163aec9d3d073dc9ffe5dd3ad05069bcb03fcaab8d221290ba99f9f69ee3"}, {file = "yarl-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8288d7cd28f8119b07dd49b7230d6b4562f9b61ee9a4ab02221060d21136be80"}, {file = "yarl-1.9.2-cp39-cp39-win32.whl", hash = "sha256:b124e2a6d223b65ba8768d5706d103280914d61f5cae3afbc50fc3dfcc016623"}, {file = "yarl-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:61016e7d582bc46a5378ffdd02cd0314fb8ba52f40f9cf4d9a5e7dbef88dee18"}, {file = "yarl-1.9.2.tar.gz", hash = "sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.10" content-hash = "f72accb9d5f9f850bebdb916ac933d61c1719fd4beed9a6933d17591e3227472" joostlek-python-youtube-68529d1/pyproject.toml000066400000000000000000000074411445733011300215640ustar00rootroot00000000000000[tool.poetry] name = "youtubeaio" version = "1.1.4" description = "Asynchronous Python client for YouTube V3 API." authors = ["Joost Lekkerkerker "] maintainers = ["Joost Lekkerkerker "] license = "MIT" readme = "README.md" homepage = "https://github.com/joostlek/python-youtube" repository = "https://github.com/joostlek/python-youtube" documentation = "https://github.com/joostlek/python-youtube" keywords = ["youtube", "api", "async", "client"] classifiers = [ "Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "Natural Language :: English", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries :: Python Modules", ] packages = [ { include = "youtubeaio", from = "src" }, ] [tool.poetry.dependencies] python = "^3.10" aiohttp = ">=3.0.0" yarl = ">=1.6.0" pydantic = ">=1.10.8" [tool.poetry.group.dev.dependencies] aresponses = "2.1.6" black = "23.7.0" blacken-docs = "1.15.0" codespell = "2.2.5" covdefaults = "2.3.0" coverage = {version = "7.2.7", extras = ["toml"]} mypy = "1.4.1" pre-commit = "3.3.3" pre-commit-hooks = "4.4.0" pylint = "2.17.4" pytest = "7.4.0" pytest-asyncio = "0.21.1" pytest-cov = "4.1.0" ruff = "0.0.280" safety = "2.4.0b1" yamllint = "1.32.0" [tool.poetry.urls] "Bug Tracker" = "https://github.com/joostlek/python-youtube/issues" Changelog = "https://github.com/joostlek/python-youtube/releases" [tool.coverage.report] show_missing = true [tool.coverage.run] plugins = ["covdefaults"] source = ["youtubeaio"] [tool.mypy] # Specify the target platform details in config, so your developers are # free to run mypy on Windows, Linux, or macOS and get consistent # results. platform = "linux" python_version = "3.10" # show error messages from unrelated files follow_imports = "normal" # suppress errors about unsatisfied imports ignore_missing_imports = true # be strict check_untyped_defs = true disallow_any_generics = true disallow_incomplete_defs = true disallow_subclassing_any = true disallow_untyped_calls = true disallow_untyped_decorators = true disallow_untyped_defs = true no_implicit_optional = true no_implicit_reexport = true strict_optional = true warn_incomplete_stub = true warn_no_return = true warn_redundant_casts = true warn_return_any = true warn_unused_configs = true warn_unused_ignores = true [tool.pylint.MASTER] extension-pkg-whitelist = [ "pydantic", ] ignore = [ "tests", ] [tool.pylint.BASIC] good-names = [ "_", "ex", "fp", "i", "id", "j", "k", "on", "Run", "T", ] [tool.pylint.DESIGN] max-attributes = 8 [tool.pylint."MESSAGES CONTROL"] disable = [ "duplicate-code", "format", "unsubscriptable-object", "unnecessary-dunder-call", "too-many-instance-attributes", "too-many-arguments", "too-many-locals", ] [tool.pylint.SIMILARITIES] ignore-imports = true [tool.pylint.FORMAT] max-line-length = 88 [tool.pytest.ini_options] addopts = "--cov" asyncio_mode = "auto" [tool.ruff] ignore = [ "ANN101", # Self... explanatory "ANN102", # cls... just as useless "ANN401", # Opinioated warning on disallowing dynamically typed expressions "D203", # Conflicts with other rules "D213", # Conflicts with other rules "D417", # False positives in some occasions "PLR2004", # Just annoying, not really useful "TCH001", "TRY301", "FBT001", # Boolean positional arg "FBT002", # Boolean default arg "PLR0913", # A lot of arguments ] select = ["ALL"] [tool.ruff.flake8-pytest-style] fixture-parentheses = false mark-parentheses = false [tool.ruff.isort] known-first-party = ["youtubeaio"] [tool.ruff.mccabe] max-complexity = 25 [build-system] build-backend = "poetry.core.masonry.api" requires = ["poetry-core>=1.0.0"] joostlek-python-youtube-68529d1/sonar-project.properties000066400000000000000000000011271445733011300235470ustar00rootroot00000000000000sonar.projectKey=joostlek_python-youtube sonar.organization=joostlek-github sonar.projectName=Asynchronous Python client for the YouTube V3 API sonar.projectVersion=1.0 sonar.links.homepage=https://github.com/joostlek/python-youtube sonar.links.ci=https://github.com/joostlek/python-youtube/actions sonar.links.issue=https://github.com/joostlek/python-youtube/issues sonar.links.scm=https://github.com/joostlek/python-youtube/tree/main sonar.language=py sonar.sourceEncoding=UTF-8 sonar.sources=src sonar.tests=tests sonar.python.version=3.10, 3.11 sonar.python.coverage.reportPaths=coverage.xml joostlek-python-youtube-68529d1/src/000077500000000000000000000000001445733011300174315ustar00rootroot00000000000000joostlek-python-youtube-68529d1/src/youtubeaio/000077500000000000000000000000001445733011300216165ustar00rootroot00000000000000joostlek-python-youtube-68529d1/src/youtubeaio/__init__.py000066400000000000000000000000711445733011300237250ustar00rootroot00000000000000"""Asynchronous Python client for the YouTube V3 API.""" joostlek-python-youtube-68529d1/src/youtubeaio/const.py000066400000000000000000000014771445733011300233270ustar00rootroot00000000000000"""Models for YouTube API.""" from enum import Enum class HttpStatusCode(int, Enum): """Enum holding http status codes.""" NOT_FOUND = 404 class VideoPart(str, Enum): """Enum holding the part parameters for video requests.""" CONTENT_DETAILS = "contentDetails" FILE_DETAILS = "fileDetails" ID = "id" LIVE_STREAMING_DETAILS = "liveStreamingDetails" LOCALIZATIONS = "localizations" PLAYER = "player" PROCESSING_DETAILS = "processingDetails" RECORDING_DETAILS = "recordingDetails" SNIPPET = "snippet" STATISTICS = "statistics" STATUS = "status" SUGGESTIONS = "suggestions" TOPIC_DETAILS = "topicDetails" class LiveBroadcastContent(str, Enum): """Enum holding the liveBroadcastContent values.""" NONE = "none" LIVE = "live" UPCOMING = "upcoming" joostlek-python-youtube-68529d1/src/youtubeaio/helper.py000066400000000000000000000061151445733011300234520ustar00rootroot00000000000000"""Helper functions for the YouTube API.""" import urllib.parse from collections.abc import AsyncGenerator, Generator from enum import Enum from typing import Any, TypeVar from youtubeaio.types import AuthScope __all__ = [ "YOUTUBE_AUTH_BASE_URL", "YOUTUBE_AUTH_TOKEN_URL", "build_scope", "build_url", "first", "chunk", "limit", ] T = TypeVar("T") YOUTUBE_AUTH_BASE_URL: str = "https://oauth2.googleapis.com" YOUTUBE_AUTH_TOKEN_URL: str = f"{YOUTUBE_AUTH_BASE_URL}/token" def build_scope(scopes: list[AuthScope]) -> str: """Build a valid scope string from list. :param scopes: list of :class:`~youtubeaio.types.AuthScope` :returns: the valid auth scope string """ return " ".join([s.value for s in scopes]) def build_url( url: str, params: dict[str, Any], remove_none: bool = False, split_lists: bool = False, enum_value: bool = True, ) -> str: """Build a valid url string. :param url: base URL :param params: dictionary of URL parameter :param remove_none: if set all params that have a None value get removed |default| :code:`False` :param split_lists: if set all params that are a list will be split over multiple url parameter with the same name |default| :code:`False` :param enum_value: if true, automatically get value string from Enum values |default| :code:`True` :return: URL """ def get_value(input_value: Any) -> str: if not enum_value: return str(input_value) if isinstance(input_value, Enum): return str(input_value.value) return str(input_value) def add_param(res: str, query_key: str, query_value: Any) -> str: if len(res) > 0: res += "&" res += query_key if query_value is not None: res += "=" + urllib.parse.quote(get_value(query_value)) return res result = "" for key, value in params.items(): if value is None and remove_none: continue if split_lists and isinstance(value, list): for val in value: result = add_param(result, key, val) else: result = add_param(result, key, value) return url + (("?" + result) if len(result) > 0 else "") async def first(generator: AsyncGenerator[T, None]) -> T | None: """Return the first value or None from the given AsyncGenerator.""" try: return await generator.__anext__() except StopAsyncIteration: return None def chunk(source: list[T], chunk_size: int) -> Generator[list[T], None, None]: """Divide the source list in chunks of given size.""" for i in range(0, len(source), chunk_size): yield source[i : i + chunk_size] async def limit( generator: AsyncGenerator[T, None], total: int, ) -> AsyncGenerator[T, None]: """Limit the number of entries returned from the AsyncGenerator.""" if total < 1: msg = "Limit has to be an int > 1" raise ValueError(msg) count = 0 async for item in generator: count += 1 if count > total: break yield item joostlek-python-youtube-68529d1/src/youtubeaio/models.py000066400000000000000000000164051445733011300234610ustar00rootroot00000000000000"""Models for YouTube API.""" from datetime import datetime from typing import TypeVar from pydantic import BaseModel, Field from youtubeaio.const import LiveBroadcastContent __all__ = [ "YouTubeThumbnail", "YouTubeVideoThumbnails", "YouTubeVideoSnippet", "YouTubeVideo", "YouTubeChannelThumbnails", "YouTubeChannelRelatedPlaylists", "YouTubeChannelContentDetails", "YouTubeChannelSnippet", "YouTubeChannel", ] from youtubeaio.types import PartMissingError T = TypeVar("T") class YouTubeThumbnail(BaseModel): """Model representing a video thumbnail.""" url: str = Field(...) width: int = Field(...) height: int = Field(...) class YouTubeVideoThumbnails(BaseModel): """Model representing video thumbnails.""" default: YouTubeThumbnail = Field(...) medium: YouTubeThumbnail | None = Field(None) high: YouTubeThumbnail | None = Field(None) standard: YouTubeThumbnail | None = Field(None) maxres: YouTubeThumbnail | None = Field(None) def get_highest_quality(self) -> YouTubeThumbnail: """Return the highest quality thumbnail.""" for size in (self.maxres, self.standard, self.high, self.medium): if size is not None: return size return self.default class YouTubeVideoSnippet(BaseModel): """Model representing video snippet.""" published_at: datetime = Field(..., alias="publishedAt") channel_id: str = Field(..., alias="channelId") title: str = Field(...) description: str = Field(...) thumbnails: YouTubeVideoThumbnails = Field(...) channel_title: str = Field(..., alias="channelTitle") tags: list[str] = Field([]) live_broadcast_content: LiveBroadcastContent = Field( ..., alias="liveBroadcastContent", ) default_language: str | None = Field(None, alias="defaultLanguage") default_audio_language: str | None = Field(None, alias="defaultAudioLanguage") class YouTubeVideo(BaseModel): """Model representing a video.""" video_id: str = Field(..., alias="id") nullable_snippet: YouTubeVideoSnippet | None = Field(None, alias="snippet") @property def snippet(self) -> YouTubeVideoSnippet: """Return snippet.""" if self.nullable_snippet is None: raise PartMissingError return self.nullable_snippet class YouTubeChannelThumbnails(BaseModel): """Model representing channel thumbnails.""" default: YouTubeThumbnail = Field(...) medium: YouTubeThumbnail | None = Field(None) high: YouTubeThumbnail | None = Field(None) def get_highest_quality(self) -> YouTubeThumbnail: """Return the highest quality thumbnail.""" for size in (self.high, self.medium): if size is not None: return size return self.default class YouTubeChannelRelatedPlaylists(BaseModel): """Model representing related playlists of a channel.""" likes: str = Field(...) uploads: str = Field(...) class YouTubeChannelContentDetails(BaseModel): """Model representing content details of a channel.""" related_playlists: YouTubeChannelRelatedPlaylists = Field( ..., alias="relatedPlaylists", ) class YouTubeChannelStatistics(BaseModel): """Model representing statistics of a channel.""" view_count: int = Field(..., alias="viewCount") subscriber_count: int = Field(..., alias="subscriberCount") subscriber_count_hidden: bool = Field(..., alias="hiddenSubscriberCount") video_count: int = Field(..., alias="videoCount") class YouTubeChannelSnippet(BaseModel): """Model representing channel snippet.""" title: str = Field(...) description: str = Field(...) published_at: datetime = Field(..., alias="publishedAt") thumbnails: YouTubeChannelThumbnails = Field(...) default_language: str | None = Field(None, alias="defaultLanguage") class YouTubeChannel(BaseModel): """Model representing a YouTube channel.""" channel_id: str = Field(..., alias="id") nullable_snippet: YouTubeChannelSnippet | None = Field(None, alias="snippet") nullable_content_details: YouTubeChannelContentDetails | None = Field( None, alias="contentDetails", ) nullable_statistics: YouTubeChannelStatistics | None = Field( None, alias="statistics", ) @property def upload_playlist_id(self) -> str: """Return playlist id with uploads from channel.""" return str(self.channel_id).replace("UC", "UU", 1) @property def snippet(self) -> YouTubeChannelSnippet: """Return snippet.""" if self.nullable_snippet is None: raise PartMissingError return self.nullable_snippet @property def content_details(self) -> YouTubeChannelContentDetails: """Return content details.""" if self.nullable_content_details is None: raise PartMissingError return self.nullable_content_details @property def statistics(self) -> YouTubeChannelStatistics: """Return statistics.""" if self.nullable_statistics is None: raise PartMissingError return self.nullable_statistics class YouTubeSubscriptionSnippet(BaseModel): """Model representing a YouTube subscription snippet.""" title: str = Field(...) description: str = Field(...) subscribed_at: datetime = Field(..., alias="publishedAt") channel_info: dict[str, str] = Field(..., alias="resourceId") @property def channel_id(self) -> str: """Return channel id.""" return self.channel_info["channelId"] class YouTubeSubscription(BaseModel): """Model representing a YouTube subscription.""" subscription_id: str = Field(..., alias="id") nullable_snippet: YouTubeSubscriptionSnippet | None = Field(None, alias="snippet") @property def snippet(self) -> YouTubeSubscriptionSnippet: """Return snippet.""" if self.nullable_snippet is None: raise PartMissingError return self.nullable_snippet class YouTubePlaylistItemSnippet(BaseModel): """Model representing a YouTube playlist item snippet.""" added_at: datetime = Field(..., alias="publishedAt") title: str = Field(...) description: str = Field(...) thumbnails: YouTubeVideoThumbnails = Field(...) playlist_id: str = Field(..., alias="playlistId") class YouTubePlaylistItemContentDetails(BaseModel): """Model representing a YouTube playlist item content details.""" video_id: str = Field(..., alias="videoId") class YouTubePlaylistItem(BaseModel): """Model representing a YouTube playlist item.""" playlist_item_id: str = Field(..., alias="id") nullable_snippet: YouTubePlaylistItemSnippet | None = Field(None, alias="snippet") nullable_content_details: YouTubePlaylistItemContentDetails | None = Field( None, alias="contentDetails", ) @property def snippet(self) -> YouTubePlaylistItemSnippet: """Return snippet.""" if self.nullable_snippet is None: raise PartMissingError return self.nullable_snippet @property def content_details(self) -> YouTubePlaylistItemContentDetails: """Return content details.""" if self.nullable_content_details is None: raise PartMissingError return self.nullable_content_details joostlek-python-youtube-68529d1/src/youtubeaio/oauth.py000066400000000000000000000033541445733011300233150ustar00rootroot00000000000000"""Oauth helpers for YouTube.""" import aiohttp from youtubeaio.helper import YOUTUBE_AUTH_TOKEN_URL, build_url from youtubeaio.types import InvalidRefreshTokenError, UnauthorizedError __all__ = ["refresh_access_token"] async def refresh_access_token( refresh_token: str, app_id: str, app_secret: str, session: aiohttp.ClientSession | None = None, ) -> tuple[str, str]: """Refresh a user access token. :param str refresh_token: the current refresh_token :param str app_id: the id of your app :param str app_secret: the secret key of your app :param ~aiohttp.ClientSession session: optionally a active client session to be used for the web request to avoid having to open a new one :return: access_token, refresh_token :raises ~youtubeaio.types.InvalidRefreshTokenException: if refresh token is invalid :raises ~youtubeaio.types.UnauthorizedException: if both refresh and access token are invalid (e.g. if the user changes their password of the app gets disconnected) :rtype: (str, str) """ param = { "refresh_token": refresh_token, "client_id": app_id, "grant_type": "refresh_token", "client_secret": app_secret, "access_type": "offline", "prompt": "consent", } url = build_url(YOUTUBE_AUTH_TOKEN_URL, {}) ses = session if session is not None else aiohttp.ClientSession() async with ses.post(url, data=param) as result: data = await result.json() if session is None: await ses.close() if result.status == 400: raise InvalidRefreshTokenError(data.get("error", "")) if result.status == 401: raise UnauthorizedError(data.get("error", "")) return data["access_token"], refresh_token joostlek-python-youtube-68529d1/src/youtubeaio/py.typed000066400000000000000000000000001445733011300233030ustar00rootroot00000000000000joostlek-python-youtube-68529d1/src/youtubeaio/types.py000066400000000000000000000041331445733011300233350ustar00rootroot00000000000000"""Type definitions.""" from enum import Enum __all__ = [ "AuthScope", "YouTubeAPIError", "YouTubeAuthorizationError", "InvalidRefreshTokenError", "InvalidTokenError", "UnauthorizedError", "MissingScopeError", "YouTubeBackendError", "MissingAppSecretError", "DeprecatedError", "YouTubeResourceNotFoundError", "ForbiddenError", ] class AuthScope(Enum): """Enum of authentication scopes.""" MANAGE = "https://www.googleapis.com/auth/youtube" MANAGE_MEMBERSHIPS = ( "https://www.googleapis.com/auth/youtube.channel-memberships.creator" ) FORCE_SSL = "https://www.googleapis.com/auth/youtube.force-ssl" READ_ONLY = "https://www.googleapis.com/auth/youtube.readonly" UPLOAD = "https://www.googleapis.com/auth/youtube.upload" PARTNER = "https://www.googleapis.com/auth/youtubepartner" PARTNER_AUDIT = "https://www.googleapis.com/auth/youtubepartner-channel-audit" class YouTubeAPIError(Exception): """Base YouTube API exception.""" class YouTubeAuthorizationError(YouTubeAPIError): """Exception in the YouTube Authorization.""" class InvalidRefreshTokenError(YouTubeAPIError): """used User Refresh Token is invalid.""" class InvalidTokenError(YouTubeAPIError): """Used if an invalid token is set for the client.""" class UnauthorizedError(YouTubeAuthorizationError): """Not authorized to use this.""" class MissingScopeError(YouTubeAuthorizationError): """authorization is missing scope.""" class YouTubeBackendError(YouTubeAPIError): """When the YouTube API itself is down.""" class PartMissingError(YouTubeAPIError): """If you request a part which is not requested.""" class MissingAppSecretError(YouTubeAPIError): """When the app secret is not set but app authorization is attempted.""" class DeprecatedError(YouTubeAPIError): """If something has been marked as deprecated by the YouTube API.""" class YouTubeResourceNotFoundError(YouTubeAPIError): """If a requested resource was not found.""" class ForbiddenError(YouTubeAPIError): """If you are not allowed to do that.""" joostlek-python-youtube-68529d1/src/youtubeaio/youtube.py000066400000000000000000000227571445733011300237010ustar00rootroot00000000000000"""The YouTube API.""" import asyncio from collections.abc import AsyncGenerator, Callable, Coroutine from dataclasses import field from logging import getLogger from typing import Any, TypeVar import async_timeout from aiohttp import ClientError, ClientResponse, ClientSession from youtubeaio.helper import ( build_url, first, ) from youtubeaio.models import ( YouTubeChannel, YouTubePlaylistItem, YouTubeSubscription, YouTubeVideo, ) from youtubeaio.types import ( AuthScope, ForbiddenError, MissingScopeError, UnauthorizedError, YouTubeAPIError, YouTubeBackendError, YouTubeResourceNotFoundError, ) __all__ = [ "YouTube", ] T = TypeVar("T") class YouTube: """YouTube API client.""" base_url: str = "https://youtube.googleapis.com/youtube/v3/" _close_session: bool = False logger = getLogger(__name__) _user_auth_token: str | None = None _user_auth_refresh_token: str | None = None _user_auth_scopes: list[AuthScope] = field(default_factory=list) _has_user_auth = False def __init__( self, app_id: str | None = None, app_secret: str | None = None, session: ClientSession | None = None, session_timeout: int = 10, auto_refresh_auth: bool | None = None, ) -> None: """Initialize YouTube object.""" self.session = session self.session_timeout = session_timeout self.app_id = app_id self.app_secret = app_secret if auto_refresh_auth is None: self.auto_refresh_auth = app_id is not None and app_secret is not None else: self.auto_refresh_auth = auto_refresh_auth self._r_lookup: dict[ str, Callable[ [ClientSession, str, dict[str, Any] | None], Coroutine[Any, Any, ClientResponse], ], ] = { "get": self._api_get_request, } async def _check_request_return(self, response: ClientResponse) -> ClientResponse: if response.status == 500: msg = "Internal Server Error" raise YouTubeBackendError(msg) if response.status == 400: msg = (await response.json()).get("message") raise YouTubeAPIError( "Bad Request" + ("" if msg is None else f" - {msg!s}"), ) if response.status == 404: raise YouTubeResourceNotFoundError if response.status == 401: raise UnauthorizedError if response.status == 403: response_json = await response.json() error_message = response_json["error"]["errors"][0]["message"] raise ForbiddenError(error_message) if 400 <= response.status < 500: try: response.raise_for_status() except ClientError as exc: raise YouTubeAPIError from exc return response async def _api_get_request( self, session: ClientSession, url: str, data: dict[str, Any] | None = None, ) -> ClientResponse: """Make GET request with authorization.""" headers = {"Authorization": f"Bearer {self._user_auth_token}"} self.logger.debug("making GET request to %s", url) response = await session.get(url, headers=headers, json=data) return await self._check_request_return(response) async def _build_generator( self, req: str, url: str, url_params: dict[str, Any], return_type: T, body_data: dict[str, Any] | None = None, split_lists: bool = False, ) -> AsyncGenerator[T, None]: method = self._r_lookup.get(req.lower(), self._api_get_request) _after = url_params.get("nextPageToken") _first = True if not self.session: self.session = ClientSession() self._close_session = True try: while _first or _after is not None: url_params["pageToken"] = _after _url = build_url( self.base_url + url, url_params, remove_none=True, split_lists=split_lists, ) async with async_timeout.timeout(self.session_timeout): response = await method(self.session, _url, body_data) if response.content_type != "application/json": msg = "Unexpected response type" raise YouTubeAPIError(msg) data = await response.json() for entry in data.get("items", []): yield return_type(**entry) # type: ignore[operator] _after = data.get("nextPageToken") _first = False except asyncio.TimeoutError as exc: msg = "Timeout occurred" raise YouTubeAPIError(msg) from exc async def set_user_authentication( self, token: str, scopes: list[AuthScope], refresh_token: str | None = None, ) -> None: """Set a user token to be used. :param token: the generated user token :param scopes: List of Authorization Scopes that the given user token has :param refresh_token: The generated refresh token, has to be provided if :attr:`auto_refresh_auth` is True |default| :code:`None` :raises ValueError: if :attr:`auto_refresh_auth` is True but refresh_token is not set :raises ~youtubeaio.types.MissingScopeException: if given token is missing one of the required scopes :raises ~youtubeaio.types.InvalidTokenException: if the given token is invalid or for a different client id """ if refresh_token is None and self.auto_refresh_auth: msg = "refresh_token has to be provided when auto_refresh_auth is True" raise ValueError(msg) if not scopes: msg = "scope was not provided" raise MissingScopeError(msg) self._user_auth_token = token self._user_auth_refresh_token = refresh_token self._user_auth_scopes = scopes self._has_user_auth = True def get_user_auth_token(self) -> str | None: """Return the current user auth token, None if no user Authentication is set. :return: current user auth token """ return self._user_auth_token async def get_videos( self, video_ids: list[str], ) -> AsyncGenerator[YouTubeVideo, None]: """Get videos by id.""" if not video_ids: msg = "at least one video id has to be set" raise ValueError(msg) param = { "part": "snippet", "id": ",".join(video_ids), } async for item in self._build_generator( "GET", "videos", param, YouTubeVideo, ): yield item # type: ignore[misc] async def get_video(self, video_id: str) -> YouTubeVideo | None: """Get a single video.""" return await first(self.get_videos([video_id])) async def _get_channels( self, param: dict[str, Any], ) -> AsyncGenerator[YouTubeChannel, None]: """Get channels.""" async for item in self._build_generator( "GET", "channels", param, YouTubeChannel, ): yield item # type: ignore[misc] async def get_user_channels(self) -> AsyncGenerator[YouTubeChannel, None]: """Return channels owned by the authenticated user.""" param = { "part": "snippet", "mine": "true", } async for item in self._get_channels(param): yield item async def get_channels( self, channel_ids: list[str], ) -> AsyncGenerator[YouTubeChannel, None]: """Return list of channels.""" param = { "part": "snippet,contentDetails,statistics", "id": ",".join(channel_ids), } async for item in self._get_channels(param): yield item async def get_user_subscriptions( self, ) -> AsyncGenerator[YouTubeSubscription, None]: """Get subscriptions for authenticated user.""" param = { "part": "snippet", "mine": "true", } async for item in self._build_generator( "GET", "subscriptions", param, YouTubeSubscription, ): yield item # type: ignore[misc] async def get_playlist_items( self, playlist_id: str, max_results: int = 50, ) -> AsyncGenerator[YouTubePlaylistItem, None]: """Get playlist by id.""" param = { "part": "snippet,contentDetails", "playlistId": playlist_id, "maxResults": max_results, } async for item in self._build_generator( "GET", "playlistItems", param, YouTubePlaylistItem, ): yield item # type: ignore[misc] async def close(self) -> None: """Close open client session.""" if self.session and self._close_session: await self.session.close() async def __aenter__(self) -> "YouTube": """Async enter. Returns ------- The YouTube object. """ return self async def __aexit__(self, *_exc_info: Any) -> None: """Async exit. Args: ---- _exc_info: Exec type. """ await self.close() joostlek-python-youtube-68529d1/tests/000077500000000000000000000000001445733011300200045ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/__init__.py000066400000000000000000000017051445733011300221200ustar00rootroot00000000000000"""Tests for the YouTube Library.""" import json from pathlib import Path from typing import Any def load_fixture(filename: str) -> str: """Load a fixture.""" path = Path(__package__) / "fixtures" / filename return path.read_text(encoding="utf-8") def construct_fixture(object_type: str, parts: list[str], object_number: int) -> Any: """Construct a fixture from different files.""" base_path = Path(__package__) / "fixtures" / object_type base_json = json.loads((base_path / "base.json").read_text(encoding="utf-8")) object_json = base_path / str(object_number) base_object_json = json.loads( (object_json / "base.json").read_text(encoding="utf-8"), ) for part in parts: part_json_path = object_json / f"{part}.json" part_json = json.loads(part_json_path.read_text(encoding="utf-8")) base_object_json[part] = part_json base_json["items"].append(base_object_json) return base_json joostlek-python-youtube-68529d1/tests/const.py000066400000000000000000000001131445733011300214770ustar00rootroot00000000000000"""Constants for YouTube tests.""" YOUTUBE_URL = "youtube.googleapis.com" joostlek-python-youtube-68529d1/tests/fixtures/000077500000000000000000000000001445733011300216555ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/channel/000077500000000000000000000000001445733011300232655ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/channel/1/000077500000000000000000000000001445733011300234255ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/channel/1/base.json000066400000000000000000000001631445733011300252320ustar00rootroot00000000000000{ "kind": "youtube#channel", "etag": "PT8fdvojgSn53JoWCx_QVmL-M1E", "id": "UC_x5XG1OV2P6uZZ5FSM9Ttw" } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/brandingSettings.json000066400000000000000000000015421445733011300276270ustar00rootroot00000000000000{ "channel": { "title": "Google for Developers", "description": "Subscribe to join a community of creative developers and learn the latest in Google technology — from AI and cloud, to mobile and web.\n\nExplore more at developers.google.com\n\n", "keywords": "\"google developers\" developers \"Google developers videos\" \"google developer tutorials\" \"developer tutorials\" \"developer news\" android firebase tensorflow chrome web flutter \"google developer experts\" \"google launchpad\" \"developer updates\" google \"google design\"", "trackingAnalyticsAccountId": "YT-9170156-1", "unsubscribedTrailer": "bC8fvcpocBU", "country": "US" }, "image": { "bannerExternalUrl": "https://yt3.googleusercontent.com/Oxa3gK3h8fgC8wNLkMJVcj2VJ_rRzZL02eAEEVOiKpts-ed5LApGEKZTJ2YrmrsRq6lrJRmZ9g" } } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/contentDetails.json000066400000000000000000000001471445733011300273020ustar00rootroot00000000000000{ "relatedPlaylists": { "likes": "", "uploads": "UU_x5XG1OV2P6uZZ5FSM9Ttw" } } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/snippet.json000066400000000000000000000024551445733011300260100ustar00rootroot00000000000000{ "title": "Google for Developers", "description": "Subscribe to join a community of creative developers and learn the latest in Google technology — from AI and cloud, to mobile and web.\n\nExplore more at developers.google.com\n\n", "customUrl": "@googledevelopers", "publishedAt": "2007-08-23T00:34:43Z", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s88-c-k-c0x00ffffff-no-rj", "width": 88, "height": 88 }, "medium": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s240-c-k-c0x00ffffff-no-rj", "width": 240, "height": 240 }, "high": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s800-c-k-c0x00ffffff-no-rj", "width": 800, "height": 800 } }, "localized": { "title": "Google for Developers", "description": "Subscribe to join a community of creative developers and learn the latest in Google technology — from AI and cloud, to mobile and web.\n\nExplore more at developers.google.com\n\n" }, "country": "US" } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/statistics.json000066400000000000000000000002011445733011300265030ustar00rootroot00000000000000{ "viewCount": "234084903", "subscriberCount": "2300000", "hiddenSubscriberCount": false, "videoCount": "5783" } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/status.json000066400000000000000000000002051445733011300256400ustar00rootroot00000000000000{ "privacyStatus": "public", "isLinked": true, "longUploadsStatus": "longUploadsUnspecified", "madeForKids": false } joostlek-python-youtube-68529d1/tests/fixtures/channel/1/topicDetails.json000066400000000000000000000004361445733011300267470ustar00rootroot00000000000000{ "topicIds": [ "/m/07c1v", "/m/019_rr", "/m/01k8wb" ], "topicCategories": [ "https://en.wikipedia.org/wiki/Technology", "https://en.wikipedia.org/wiki/Lifestyle_(sociology)", "https://en.wikipedia.org/wiki/Knowledge" ] } joostlek-python-youtube-68529d1/tests/fixtures/channel/base.json000066400000000000000000000002531445733011300250720ustar00rootroot00000000000000{ "kind": "youtube#channelListResponse", "etag": "GBw0IHK0JUk4W3ttcxY9nt39sK0", "pageInfo": { "totalResults": 1, "resultsPerPage": 5 }, "items": [ ] } joostlek-python-youtube-68529d1/tests/fixtures/channel_response_snippet.json000066400000000000000000000035211445733011300276410ustar00rootroot00000000000000{ "kind": "youtube#channelListResponse", "etag": "9sIVzjSfOfk6gN357UcUDTWRTec", "pageInfo": { "totalResults": 1, "resultsPerPage": 5 }, "items": [ { "kind": "youtube#channel", "etag": "veRvdNDE9HmhyENPqeFNq-VH6NI", "id": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "snippet": { "title": "Google for Developers", "description": "Subscribe to join a community of creative developers and learn the latest in Google technology — from AI and cloud, to mobile and web.\n\nExplore more at developers.google.com\n\n", "customUrl": "@googledevelopers", "publishedAt": "2007-08-23T00:34:43Z", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s88-c-k-c0x00ffffff-no-rj", "width": 88, "height": 88 }, "medium": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s240-c-k-c0x00ffffff-no-rj", "width": 240, "height": 240 }, "high": { "url": "https://yt3.ggpht.com/fca_HuJ99xUxflWdex0XViC3NfctBFreIl8y4i9z411asnGTWY-Ql3MeH_ybA4kNaOjY7kyA=s800-c-k-c0x00ffffff-no-rj", "width": 800, "height": 800 } }, "localized": { "title": "Google for Developers", "description": "Subscribe to join a community of creative developers and learn the latest in Google technology — from AI and cloud, to mobile and web.\n\nExplore more at developers.google.com\n\n" }, "country": "US" }, "statistics": { "viewCount": "234084903", "subscriberCount": "2300000", "hiddenSubscriberCount": false, "videoCount": "5783" } } ] } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/000077500000000000000000000000001445733011300245345ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/1/000077500000000000000000000000001445733011300246745ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/1/base.json000066400000000000000000000002201445733011300264730ustar00rootroot00000000000000{ "kind": "youtube#playlistItem", "etag": "3AcLIY9M6JE6BoVVf636kkiGdVc", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LlVaNG4xbjEzY3JJ" } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/1/contentDetails.json000066400000000000000000000001211445733011300305410ustar00rootroot00000000000000{ "videoId": "UZ4n1n13crI", "videoPublishedAt": "2023-07-21T19:00:27Z" } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/1/snippet.json000066400000000000000000000036151445733011300272560ustar00rootroot00000000000000{ "publishedAt": "2023-07-21T19:00:27Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "Unleash Your Web Development Potential with dval.dev", "description": "Website → https://dval.dev\n\nDiscover dval.dev, a resource to unlock your web development potential. Join Dan Valinotti as he shares inspiring insights, expert tips, and showcases his captivating portfolio. Dive into the world of web components, JavaScript, and more to gain the inspiration you need for your own projects.\n\n#MyDomain is a series from Google Registry where website creators share the stories behind their domain names, as well as website-building tips. Stay tuned for more episodes.\n\nGet your .app website: https://get.dev\n#MyDomain playlist → https://goo.gle/MyDomain\n\nSubscribe → https://goo.gle/developers", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 0, "resourceId": { "kind": "youtube#video", "videoId": "UZ4n1n13crI" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/1/status.json000066400000000000000000000000421445733011300271060ustar00rootroot00000000000000{ "privacyStatus": "public" } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item/base.json000066400000000000000000000002631445733011300263420ustar00rootroot00000000000000{ "kind": "youtube#playlistItemListResponse", "etag": "jKUJRscolu59oCWlCnDdKrPlTDI", "items": [ ], "pageInfo": { "totalResults": 5783, "resultsPerPage": 1 } } joostlek-python-youtube-68529d1/tests/fixtures/playlist_item_response_snippet_content_details.json000066400000000000000000000251221445733011300343500ustar00rootroot00000000000000{ "kind": "youtube#playlistItemListResponse", "etag": "ymk0VS6i1mVdlljgcX3cnxScdhU", "items": [ { "kind": "youtube#playlistItem", "etag": "H3SdsdssTDmYJkvgC4rOsXsq_nY", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LlVaNG4xbjEzY3JJ", "snippet": { "publishedAt": "2023-07-21T19:00:27Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "Unleash Your Web Development Potential with dval.dev", "description": "Website → https://dval.dev\n\nDiscover dval.dev, a resource to unlock your web development potential. Join Dan Valinotti as he shares inspiring insights, expert tips, and showcases his captivating portfolio. Dive into the world of web components, JavaScript, and more to gain the inspiration you need for your own projects.\n\n#MyDomain is a series from Google Registry where website creators share the stories behind their domain names, as well as website-building tips. Stay tuned for more episodes.\n\nGet your .app website: https://get.dev\n#MyDomain playlist → https://goo.gle/MyDomain\n\nSubscribe → https://goo.gle/developers", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/UZ4n1n13crI/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 0, "resourceId": { "kind": "youtube#video", "videoId": "UZ4n1n13crI" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" }, "contentDetails": { "videoId": "UZ4n1n13crI", "videoPublishedAt": "2023-07-21T19:00:27Z" } }, { "kind": "youtube#playlistItem", "etag": "uVfC4v2s8ojCfH8ei695bB_m8WU", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3Lmd3QTBUcVNONmxn", "snippet": { "publishedAt": "2023-07-21T19:00:15Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "Learn How to Supercharge Your Last.fm Developer Experience with Finale.app", "description": "Website →https:/finale.app \n\nDiscover Finale.app, a Last.fm client developed by Noa Rubin. Track your music listening habits and unlock detailed statistics like never before. With exclusive features such as multi-source logging and the ability to create stunning collages of your top songs, artists, and albums, Finale takes your Last.fm experience to the next level. In this #MyDomain episode, uncover the story behind the name as Finale represents its musical roots and being the ultimate Last.fm client.\n\n\n#MyDomain is a series from Google Registry where website creators share the stories behind their domain names, as well as website-building tips. Stay tuned for more episodes.\n\nGet your .app website: https://get.app\n#MyDomain playlist → https://goo.gle/MyDomain\n\nSubscribe → https://goo.gle/developers", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/gwA0TqSN6lg/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/gwA0TqSN6lg/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/gwA0TqSN6lg/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/gwA0TqSN6lg/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/gwA0TqSN6lg/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 1, "resourceId": { "kind": "youtube#video", "videoId": "gwA0TqSN6lg" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" }, "contentDetails": { "videoId": "gwA0TqSN6lg", "videoPublishedAt": "2023-07-21T19:00:15Z" } }, { "kind": "youtube#playlistItem", "etag": "BQMpEaUTP5kL9Wa_kTh9QJYcn4k", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LmJiV1V3UEhuQlRj", "snippet": { "publishedAt": "2023-07-20T21:00:30Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "What tools make it easier for devs to develop?", "description": "Watch this video for developer tips and tricks that can make your projects easier and fun!\n\nSubscribe to Google Developers → https://goo.gle/developers \n\n#streetinterviews #developers", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/bbWUwPHnBTc/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/bbWUwPHnBTc/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/bbWUwPHnBTc/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/bbWUwPHnBTc/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/bbWUwPHnBTc/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 2, "resourceId": { "kind": "youtube#video", "videoId": "bbWUwPHnBTc" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" }, "contentDetails": { "videoId": "bbWUwPHnBTc", "videoPublishedAt": "2023-07-20T21:00:30Z" } }, { "kind": "youtube#playlistItem", "etag": "YNIS7l0t5fF1qcSbThewbKZI4Ac", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LmRka0l0X3NXOGJv", "snippet": { "publishedAt": "2023-07-20T15:00:28Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "Writing IOS and Android apps simultaneously?", "description": "We’ve all been there. You write one app for one operating system only to find out you need to write it for another. Watch this short to see how you can develop for Android and IOS simultaneously with Flutter. \n\nWatch more episodes of GDE Secrets → https://goo.gle/3Di2Olg \nSubscribe to Google Developers → https://goo.gle/developers \n\n#GDESecrets", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/ddkIt_sW8bo/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/ddkIt_sW8bo/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/ddkIt_sW8bo/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/ddkIt_sW8bo/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/ddkIt_sW8bo/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 3, "resourceId": { "kind": "youtube#video", "videoId": "ddkIt_sW8bo" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" }, "contentDetails": { "videoId": "ddkIt_sW8bo", "videoPublishedAt": "2023-07-20T15:00:28Z" } }, { "kind": "youtube#playlistItem", "etag": "CQPbyZ8zzkvPaimscUGyLnI7XMA", "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LlNaLTROSFhTb0JJ", "snippet": { "publishedAt": "2023-07-18T21:00:17Z", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "title": "What tips would you give to new dev?", "description": "So, you want to be a dev, huh? When you’re first starting out, it’s nice to hear what elder developers have to say and what advice they would give to a newcomer in our community. \n\nSubscribe to Google Developers → https://goo.gle/developers \n\n#streetInterviews #developers", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/SZ-4NHXSoBI/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/SZ-4NHXSoBI/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/SZ-4NHXSoBI/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/SZ-4NHXSoBI/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/SZ-4NHXSoBI/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "Google for Developers", "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw", "position": 4, "resourceId": { "kind": "youtube#video", "videoId": "SZ-4NHXSoBI" }, "videoOwnerChannelTitle": "Google for Developers", "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw" }, "contentDetails": { "videoId": "SZ-4NHXSoBI", "videoPublishedAt": "2023-07-18T21:00:17Z" } } ], "pageInfo": { "totalResults": 5783, "resultsPerPage": 5 } } joostlek-python-youtube-68529d1/tests/fixtures/refresh_token.json000066400000000000000000000002661445733011300254120ustar00rootroot00000000000000{ "access_token": "asdasdasdasdasdasdasdadasdasdasdasdasd", "expires_in": 3599, "scope": "https://www.googleapis.com/auth/youtube.readonly", "token_type": "Bearer" } joostlek-python-youtube-68529d1/tests/fixtures/subscription/000077500000000000000000000000001445733011300244015ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/subscription/1/000077500000000000000000000000001445733011300245415ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/subscription/1/base.json000066400000000000000000000002131445733011300263420ustar00rootroot00000000000000{ "kind": "youtube#subscription", "etag": "JFUmZ2Ug0_3GK1SLrvMrkkEXVGU", "id": "l6YW-siEBx0vFwUCplQXHsY4uVZod9Xtzzo3SgEL_Hw" } joostlek-python-youtube-68529d1/tests/fixtures/subscription/1/contentDetails.json000066400000000000000000000001201445733011300304050ustar00rootroot00000000000000{ "totalItemCount": 205, "newItemCount": 1, "activityType": "all" } joostlek-python-youtube-68529d1/tests/fixtures/subscription/1/snippet.json000066400000000000000000000014561445733011300271240ustar00rootroot00000000000000{ "publishedAt": "2023-07-08T12:06:58.238253Z", "title": "Bellied Up Pod", "description": "", "resourceId": { "kind": "youtube#channel", "channelId": "UCATH-c7kenLwxiGWohX_Jgw" }, "channelId": "UCJA_MqaDMFv6Dh-E8bpszIw", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/mE9ypqGduSh34pjlJ-YXBoYYgSeNXIyv-28NSlMzV122mZx4jtD5KdgoKhxmXHnFVnSTMiVNdw=s88-c-k-c0x00ffffff-no-rj" }, "medium": { "url": "https://yt3.ggpht.com/mE9ypqGduSh34pjlJ-YXBoYYgSeNXIyv-28NSlMzV122mZx4jtD5KdgoKhxmXHnFVnSTMiVNdw=s240-c-k-c0x00ffffff-no-rj" }, "high": { "url": "https://yt3.ggpht.com/mE9ypqGduSh34pjlJ-YXBoYYgSeNXIyv-28NSlMzV122mZx4jtD5KdgoKhxmXHnFVnSTMiVNdw=s800-c-k-c0x00ffffff-no-rj" } } } joostlek-python-youtube-68529d1/tests/fixtures/subscription/1/subscriberSnippet.json000066400000000000000000000010451445733011300311420ustar00rootroot00000000000000{ "title": "Asdswdsdsd", "description": "", "channelId": "UCJA_asdasdasdasd-E8bpszIw", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/ytc/AOPolasdasdtM4ZBEPjVnYIkQ=s88-c-k-c0x00ffffff-no-rj" }, "medium": { "url": "https://yt3.ggpht.com/ytc/AOPolasdasdtM4ZBEPjVnYIkQ-StM4ZBEPjVnYIkQ=s240-c-k-c0x00ffffff-no-rj" }, "high": { "url": "https://yt3.ggpht.com/ytc/AOPolasdasdtM4ZBEPjVnYIkQ-StM4ZBEPjVnYIkQ=s800-c-k-c0x00ffffff-no-rj" } } } joostlek-python-youtube-68529d1/tests/fixtures/subscription/base.json000066400000000000000000000002621445733011300262060ustar00rootroot00000000000000{ "kind": "youtube#SubscriptionListResponse", "etag": "O2dpqDFZ9GorF8eHIzslXwXyfKU", "pageInfo": { "totalResults": 547, "resultsPerPage": 5 }, "items": [ ] } joostlek-python-youtube-68529d1/tests/fixtures/subscription_response_snippet.json000066400000000000000000000046621445733011300307640ustar00rootroot00000000000000{ "kind": "youtube#SubscriptionListResponse", "etag": "ToySCAR2vCoWXFlWF3I2pOR9odY", "pageInfo": { "totalResults": 547, "resultsPerPage": 2 }, "items": [ { "kind": "youtube#subscription", "etag": "qQ8Upr97jeB0ksUo2lFQXxXtcis", "id": "l6YW-siEBx2rtBlTJ_ip132nwdjtfEj_s_XrLrZyj3Y", "snippet": { "publishedAt": "2020-05-18T01:04:54.7417Z", "title": "DougDoug", "description": "I'm a pepper who teach how to videogame real good.\n\nI stream live on Twitch! https://www.twitch.tv/DougDoug\n\nFollow me on twitter! https://twitter.com/DougDougFood", "resourceId": { "kind": "youtube#channel", "channelId": "UClyGlKOhDUooPJFy4v_mqPg" }, "channelId": "UCJA_MqaDMFv6Dh-E8bpszIw", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/ytc/AOPolaQNqmde36_-rZt3loE_aZJ1iJKX936_5ebnJA2dVQ=s88-c-k-c0x00ffffff-no-rj" }, "medium": { "url": "https://yt3.ggpht.com/ytc/AOPolaQNqmde36_-rZt3loE_aZJ1iJKX936_5ebnJA2dVQ=s240-c-k-c0x00ffffff-no-rj" }, "high": { "url": "https://yt3.ggpht.com/ytc/AOPolaQNqmde36_-rZt3loE_aZJ1iJKX936_5ebnJA2dVQ=s800-c-k-c0x00ffffff-no-rj" } } } }, { "kind": "youtube#subscription", "etag": "3Ma9gfFVk8R7tC6js2OPirKjleg", "id": "l6YW-siEBx0PYqtFJQsPPR3JU1r9dzJpv-pjRAZJ0iU", "snippet": { "publishedAt": "2023-01-04T20:35:54.095866Z", "title": "Home Assistant", "description": "Home Assistant is an open source home automation that puts local control and privacy first. Powered by a worldwide community of tinkerers and DIY enthusiasts. Perfect to run on a Raspberry Pi or a local server.", "resourceId": { "kind": "youtube#channel", "channelId": "UCbX3YkedQunLt7EQAdVxh7w" }, "channelId": "UCJA_MqaDMFv6Dh-E8bpszIw", "thumbnails": { "default": { "url": "https://yt3.ggpht.com/ytc/AOPolaTRAmW34QPGjkXJ9QKJaSXXzbP3K_BlPY5IodnE0Q=s88-c-k-c0x00ffffff-no-rj" }, "medium": { "url": "https://yt3.ggpht.com/ytc/AOPolaTRAmW34QPGjkXJ9QKJaSXXzbP3K_BlPY5IodnE0Q=s240-c-k-c0x00ffffff-no-rj" }, "high": { "url": "https://yt3.ggpht.com/ytc/AOPolaTRAmW34QPGjkXJ9QKJaSXXzbP3K_BlPY5IodnE0Q=s800-c-k-c0x00ffffff-no-rj" } } } } ] } joostlek-python-youtube-68529d1/tests/fixtures/video/000077500000000000000000000000001445733011300227635ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/video/1/000077500000000000000000000000001445733011300231235ustar00rootroot00000000000000joostlek-python-youtube-68529d1/tests/fixtures/video/1/base.json000066400000000000000000000001441445733011300247270ustar00rootroot00000000000000{ "kind": "youtube#video", "etag": "eJfprdKoDOEG7x7dm-HJo0iVO6U", "id": "Ks-_Mh1QhMc" } joostlek-python-youtube-68529d1/tests/fixtures/video/1/contentDetails.json000066400000000000000000000002731445733011300270000ustar00rootroot00000000000000{ "duration": "PT21M3S", "dimension": "2d", "definition": "hd", "caption": "true", "licensedContent": true, "contentRating": {}, "projection": "rectangular" } joostlek-python-youtube-68529d1/tests/fixtures/video/1/localizations.json000066400000000000000000000160621445733011300266760ustar00rootroot00000000000000{ "fa": { "title": "اِمی کادی: زبان بدن شما هویت شما را شکل می\u200cدهد", "description": "زبان بدن بر دیدگاه دیگران درباره\u200cی ما تاثیر می\u200cگذارد، اما ممکن است نگاه ما بر خودمان را نیز تغییردهد. اِمی کادی، روانشناس اجتماعی، نشان می\u200cدهد که چگونه «ژست قدرت» - قرار گرفتن در حالتی از اطمینان، حتی هنگامی که ما احساس اطمینان نداریم- می\u200cتواند بر سطح تستسترون و کورتیزول در مغز تاثیر بگذارد، و حتی ممکن است تاثیراتی بر فرصت\u200cهای ما در زندگی بگذارد." }, "fr": { "title": "Amy Cuddy: votre langage corporel forge qui vous êtes", "description": "Le langage du corps affecte la façon dont les autres nous voient, mais cela peut aussi changer la façon dont nous nous voyons nous-mêmes. La psychologue sociale Amy Cuddy montre comment \"les poses de pouvoir\" -- se tenir dans des posture confiantes, même quand nous ne nous sentons pas confiants -- peuvent changer les niveaux de testostérone et le cortisol dans le cerveau, et pourraient même avoir un impact sur nos chances de succès." }, "ru": { "title": "Эми Кадди: Язык тела формирует вашу личность", "description": "Язык тела влияет на то, как другие люди видят нас, но он также может изменить наш взгляд на самих себя. Социальный психолог Эми Кадди показывает, как принятие сильных поз — например, позы уверенности даже в тех ситуациях, когда мы не чувствуем себя уверенными — влияет на уровень тестостерона и кортизола в крови и увеличивает наши шансы на успех." }, "vi": { "title": "Amy Cuddy: Ngôn ngữ cơ thể hình thành nên con người bạn", "description": "Ngôn ngữ cơ thể tác động đến cách những người khác nhìn chúng ta, nhưng nó cũng có thể thay đổi cách mà chúng ta nhìn về bản thân mình. Nhà tâm lý xã hội Amy Cuddy chỉ ra \"tư thế sức mạnh\" - tư thế của sự tự tin ngay cả khi chúng ta không hề cảm thấy tự tin như thế có thể ảnh hưởng thế nào đến độ testosterone và cortisol trong não của chúng ta, và thậm chí có thể có ảnh hưởng đến cả những cơ hội thành công của chúng ta." }, "pt-BR": { "title": "Amy Cuddy: Sua linguagem corporal molda quem você é", "description": "A linguagem corporal afeta a maneira como os outros nos vêem, mas também pode mudar a maneira como nos vemos. A psicóloga social Amy Cuddy nos mostra como “fazer poses de poder” -- ficar numa postura confiante, mesmo quando não nos sentimos confiantes -- pode afetar os níveis de testosterona e cortisol no cérebro, e pode até ter um impacto nas nossas chances de sucesso." }, "es": { "title": "Amy Cuddy: El lenguaje corporal moldea nuestra identidad", "description": "El lenguaje corporal influye en cómo nos ven los demás, pero también puede cambiar en cómo nos vemos a nosotros mismos. La psicóloga social Amy Cuddy muestra como las \"posturas de poder\" —mostrar una actitud de seguridad, aún sintiéndose inseguro— pueden alterar los niveles cerebrales de testosterona y cortisol, e incluso mejorar nuestras probabilidades de éxito." }, "en": { "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED" }, "tr": { "title": "Amy Cuddy: Vücut dilin benliğini şekillendiriyor.", "description": "Vücut dili başkalarının bizi nasıl gördüğünü etkilemekte, fakat kendimizi nasıl gördüğümüzü de değiştirebilir. Sosyal psikolog Amy Cuddy, \"güç duruşu\"nun-- insanın kendinden emin olmadığı durumlarda bile kendinden emin şekilde duruş sağlamasının--, o kişinin beynindeki testesteron ve kortizol düzeylerini etkileyebileceğini ve belki de o kişinin başarı şansını etkileyebileceğini gösteriyor." }, "ja": { "title": "エイミー・カディ 「ボディランゲージが人を作る」", "description": "私たちのするボディランゲージは、自分に対する他の人の見方に影響しますが、自分自身の見方にも影響します。社会心理学者のエイミー・カディは、自信のないときでも自信に溢れる「力のポーズ」を取ることで、脳内のテストステロンやコルチゾールのレベルが変化し、成功できる見込みも変わるのだと言います。" }, "de": { "title": "Amy Cuddy: Ihre Körpersprache beeinflusst, wer Sie sind", "description": "Unsere Körpersprache hat Einfluss darauf, wie andere uns sehen, aber sie könnte auch Einfluss darauf nehmen, wie wir uns selbst sehen. Die Sozialpsychologin Amy Cuddy zeigt, wie das Einnehmen von \"Macht-Posen\" — eine selbstbewusste Haltung einnehmen, auch wenn man sich nicht selbstbewusst fühlt — die Testosteron- und Cortisollevel in unserem Gehirn beeinflussen kann. Und vielleicht sogar Einfluss auf unsere Erfolgschancen hat." }, "zh": { "title": "Amy Cuddy: 肢体语言塑造你自己", "description": "肢体语言影响着他人对我们的看法,但同时它也影响着我们对自己的看法。社会心理学家Amy Cuddy表示“有力的姿势”--以一个自信的方式站着,即使我们不感到自信--他们也能够影响我们脑内的睾丸酮和可的松含量,甚至可以爆发性地推动我们成功的机会。" } } joostlek-python-youtube-68529d1/tests/fixtures/video/1/player.json000066400000000000000000000004261445733011300253140ustar00rootroot00000000000000{ "embedHtml": "\u003ciframe width=\"480\" height=\"270\" src=\"//www.youtube.com/embed/Ks-_Mh1QhMc\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen\u003e\u003c/iframe\u003e" } joostlek-python-youtube-68529d1/tests/fixtures/video/1/snippet.json000066400000000000000000000073001445733011300255000ustar00rootroot00000000000000{ "publishedAt": "2012-10-01T15:27:35Z", "channelId": "UCAuUUnT6oDeKwE6v1NGQxug", "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "TED", "tags": [ "Amy Cuddy", "TED", "TEDTalk", "TEDTalks", "TED Talk", "TED Talks", "TEDGlobal", "brain", "business", "psychology", "self", "success" ], "categoryId": "22", "liveBroadcastContent": "none", "defaultLanguage": "en", "localized": { "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED" }, "defaultAudioLanguage": "en" } joostlek-python-youtube-68529d1/tests/fixtures/video/1/statistics.json000066400000000000000000000001611445733011300262060ustar00rootroot00000000000000{ "viewCount": "23463386", "likeCount": "395573", "favoriteCount": "0", "commentCount": "9523" } joostlek-python-youtube-68529d1/tests/fixtures/video/1/status.json000066400000000000000000000002601445733011300253370ustar00rootroot00000000000000{ "uploadStatus": "processed", "privacyStatus": "public", "license": "youtube", "embeddable": true, "publicStatsViewable": true, "madeForKids": false } joostlek-python-youtube-68529d1/tests/fixtures/video/1/topicDetails.json000066400000000000000000000002211445733011300264350ustar00rootroot00000000000000{ "topicCategories": [ "https://en.wikipedia.org/wiki/Knowledge", "https://en.wikipedia.org/wiki/Television_program" ] } joostlek-python-youtube-68529d1/tests/fixtures/video/base.json000066400000000000000000000002461445733011300245720ustar00rootroot00000000000000{ "kind": "youtube#videoListResponse", "etag": "pEh5uVVqjHdtlXLDZ0aBXFDs1Nc", "items": [], "pageInfo": { "totalResults": 1, "resultsPerPage": 1 } } joostlek-python-youtube-68529d1/tests/fixtures/video_response_1.json000066400000000000000000000166541445733011300260300ustar00rootroot00000000000000{ "kind": "youtube#videoListResponse", "etag": "eozK4JKrCWSJuIyOHpQFRgGZq6o", "nextPageToken": "asd", "items": [ { "kind": "youtube#video", "etag": "iS4dw2lIouzQeh-sl-73b9Sanys", "id": "Ks-_Mh1QhMc", "snippet": { "publishedAt": "2012-10-01T15:27:35Z", "channelId": "UCAuUUnT6oDeKwE6v1NGQxug", "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "TED", "tags": [ "Amy Cuddy", "TED", "TEDTalk", "TEDTalks", "TED Talk", "TED Talks", "TEDGlobal", "brain", "business", "psychology", "self", "success" ], "categoryId": "22", "liveBroadcastContent": "none", "defaultLanguage": "en", "localized": { "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED" }, "defaultAudioLanguage": "en" }, "contentDetails": { "duration": "PT21M3S", "dimension": "2d", "definition": "hd", "caption": "true", "licensedContent": true, "contentRating": {}, "projection": "rectangular" }, "statistics": { "viewCount": "23278951", "likeCount": "391633", "favoriteCount": "0", "commentCount": "9518" } }, { "kind": "youtube#video", "etag": "Mab4ureXibw1M_hr_x8-cVdpGL8", "id": "GvgqDSnpRQM", "snippet": { "publishedAt": "2013-10-18T07:03:29Z", "channelId": "UCvceBgMIpKb4zK1ss-Sh90w", "title": "Andrew Willis, Skatepark Engineer", "description": "Andrew Willis built a skatepark in East London using reclaimed materials left over from the Olympic Games, creating a lasting legacy for the local community of Hackney Wick.", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/GvgqDSnpRQM/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/GvgqDSnpRQM/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/GvgqDSnpRQM/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/GvgqDSnpRQM/sddefault.jpg", "width": 640, "height": 480 } }, "channelTitle": "Google Search Stories", "tags": [ "Google", "Google Maps", "Maps", "Android", "Google search", "technology", "Google story", "Google stories", "Google ad", "Google film", "documentary", "Andrew Willis", "Andy willis", "skateboarder", "skate video", "skate park", "engineer", "Hackney Wick", "Skatepark", "Frontside Gardens", "Skateboard park", "BMX park", "London", "Olympics", "Hackney", "East London", "LLDC", "Halfpipe", "sustainability", "community", "Community interest group", "kids", "locals", "artsists", "street art", "street artsists", "graffiti", "street course", "ramp", "obstacle", "quarter pipe" ], "categoryId": "1", "liveBroadcastContent": "none", "localized": { "title": "Andrew Willis, Skatepark Engineer", "description": "Andrew Willis built a skatepark in East London using reclaimed materials left over from the Olympic Games, creating a lasting legacy for the local community of Hackney Wick." } }, "contentDetails": { "duration": "PT1M30S", "dimension": "2d", "definition": "hd", "caption": "true", "licensedContent": false, "contentRating": {}, "projection": "rectangular" }, "statistics": { "viewCount": "2653344", "likeCount": "1152", "favoriteCount": "0", "commentCount": "123" } } ], "pageInfo": { "totalResults": 2, "resultsPerPage": 2 } } joostlek-python-youtube-68529d1/tests/fixtures/video_response_2.json000066400000000000000000000046331445733011300260230ustar00rootroot00000000000000{ "kind": "youtube#videoListResponse", "etag": "eozK4JKrCWSJuIyOHpQFRgGZq6o", "items": [ { "kind": "youtube#video", "etag": "MOMqe6Fp-SLZ2GW5iZSZMIr4gRQ", "id": "V4DDt30Aat4", "snippet": { "publishedAt": "2011-11-21T19:11:41Z", "channelId": "UCvceBgMIpKb4zK1ss-Sh90w", "title": "Mark Lesek: A New/Old Prosthetic", "description": "Follow Mark on Google+: https://plus.google.com/u/0/114778778979884307299/about\r\n\r\nMark lost his arm several years ago. Now his search for a better prosthetic could improve the lives of amputees everywhere.", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/V4DDt30Aat4/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/V4DDt30Aat4/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/V4DDt30Aat4/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/V4DDt30Aat4/sddefault.jpg", "width": 640, "height": 480 } }, "channelTitle": "Google Search Stories", "tags": [ "google search stories", "search story", "prosthetics", "prosthetic arm", "google commercial", "motorcycle", "amputee" ], "categoryId": "28", "liveBroadcastContent": "none", "localized": { "title": "Mark Lesek: A New/Old Prosthetic", "description": "Follow Mark on Google+: https://plus.google.com/u/0/114778778979884307299/about\r\n\r\nMark lost his arm several years ago. Now his search for a better prosthetic could improve the lives of amputees everywhere." }, "defaultAudioLanguage": "en" }, "contentDetails": { "duration": "PT2M39S", "dimension": "2d", "definition": "hd", "caption": "true", "licensedContent": false, "contentRating": {}, "projection": "rectangular" }, "statistics": { "viewCount": "3603770", "likeCount": "1827", "favoriteCount": "0", "commentCount": "358" } } ], "pageInfo": { "totalResults": 1, "resultsPerPage": 2 } } joostlek-python-youtube-68529d1/tests/fixtures/video_response_snippet.json000066400000000000000000000101371445733011300273400ustar00rootroot00000000000000{ "kind": "youtube#videoListResponse", "etag": "pEh5uVVqjHdtlXLDZ0aBXFDs1Nc", "items": [ { "kind": "youtube#video", "etag": "eJfprdKoDOEG7x7dm-HJo0iVO6U", "id": "Ks-_Mh1QhMc", "snippet": { "publishedAt": "2012-10-01T15:27:35Z", "channelId": "UCAuUUnT6oDeKwE6v1NGQxug", "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/hqdefault.jpg", "width": 480, "height": 360 }, "standard": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/sddefault.jpg", "width": 640, "height": 480 }, "maxres": { "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/maxresdefault.jpg", "width": 1280, "height": 720 } }, "channelTitle": "TED", "tags": [ "Amy Cuddy", "TED", "TEDTalk", "TEDTalks", "TED Talk", "TED Talks", "TEDGlobal", "brain", "business", "psychology", "self", "success" ], "categoryId": "22", "liveBroadcastContent": "none", "defaultLanguage": "en", "localized": { "title": "Your body language may shape who you are | Amy Cuddy", "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED" }, "defaultAudioLanguage": "en" } } ], "pageInfo": { "totalResults": 1, "resultsPerPage": 1 } } joostlek-python-youtube-68529d1/tests/fixtures/youtube_not_activated.json000066400000000000000000000033511445733011300271520ustar00rootroot00000000000000{ "error": { "code": 403, "message": "YouTube Data API v3 has not been used in project 69696969 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=69696969 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.", "errors": [ { "message": "YouTube Data API v3 has not been used in project 69696969 before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=69696969 then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.", "domain": "usageLimits", "reason": "accessNotConfigured", "extendedHelp": "https://console.developers.google.com" } ], "status": "PERMISSION_DENIED", "details": [ { "@type": "type.googleapis.com/google.rpc.Help", "links": [ { "description": "Google developers console API activation", "url": "https://console.developers.google.com/apis/api/youtube.googleapis.com/overview?project=69696969" } ] }, { "@type": "type.googleapis.com/google.rpc.ErrorInfo", "reason": "SERVICE_DISABLED", "domain": "googleapis.com", "metadata": { "service": "youtube.googleapis.com", "consumer": "projects/69696969" } } ] } } joostlek-python-youtube-68529d1/tests/helper.py000066400000000000000000000004271445733011300216400ustar00rootroot00000000000000"""Test helpers.""" from youtubeaio.models import YouTubeThumbnail def get_thumbnail(resolution: str) -> YouTubeThumbnail: """Return mock thumbnail with resolution as url.""" return YouTubeThumbnail( url=resolution, width=100, height=100, ) joostlek-python-youtube-68529d1/tests/ruff.toml000066400000000000000000000006661445733011300216530ustar00rootroot00000000000000# This extend our general Ruff rules specifically for tests extend = "../pyproject.toml" extend-select = [ "PT", # Use @pytest.fixture without parentheses ] extend-ignore = [ "S101", # Use of assert detected. As these are tests... "S106", # Detection of passwords... "SLF001", # Tests will access private/protected members... "TCH002", # pytest doesn't like this one... "PT011", # We want to check for broad exceptions... ] joostlek-python-youtube-68529d1/tests/test_auth.py000066400000000000000000000027441445733011300223650ustar00rootroot00000000000000"""Tests for the YouTube client.""" import aiohttp import pytest from youtubeaio.types import AuthScope, MissingScopeError from youtubeaio.youtube import YouTube async def test_user_authentication() -> None: """Test setting user authentication.""" async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) await youtube.set_user_authentication("token", [AuthScope.READ_ONLY], "refresh") assert youtube.get_user_auth_token() == "token" await youtube.close() async def test_user_authentication_without_scopes() -> None: """Test setting user authentication without scopes.""" async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(MissingScopeError): await youtube.set_user_authentication("token", [], "refresh") await youtube.close() async def test_user_authentication_without_refresh_token() -> None: """Test setting user authentication without refresh token.""" async with aiohttp.ClientSession() as session: youtube = YouTube(session=session, app_id="asd", app_secret="asd") with pytest.raises(ValueError): await youtube.set_user_authentication("token", [AuthScope.READ_ONLY]) youtube = YouTube(session=session, auto_refresh_auth=False) await youtube.set_user_authentication("token", [AuthScope.READ_ONLY]) assert youtube.get_user_auth_token() == "token" await youtube.close() joostlek-python-youtube-68529d1/tests/test_channel.py000066400000000000000000000124421445733011300230300ustar00rootroot00000000000000"""Tests for the YouTube client.""" import json from datetime import datetime, timezone import aiohttp import pytest from aresponses import ResponsesMockServer from youtubeaio.models import YouTubeChannelThumbnails from youtubeaio.types import PartMissingError from youtubeaio.youtube import YouTube from . import construct_fixture, load_fixture from .const import YOUTUBE_URL from .helper import get_thumbnail async def test_fetch_channel( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a channel.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/channels", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("channel_response_snippet.json"), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) channel_generator = youtube.get_channels( channel_ids=["UC_x5XG1OV2P6uZZ5FSM9Ttw"], ) channel = await channel_generator.__anext__() assert channel assert channel.channel_id == "UC_x5XG1OV2P6uZZ5FSM9Ttw" assert channel.upload_playlist_id == "UU_x5XG1OV2P6uZZ5FSM9Ttw" assert channel.snippet assert channel.snippet.published_at == datetime( 2007, 8, 23, 0, 34, 43, tzinfo=timezone.utc, ) with pytest.raises(StopAsyncIteration): await channel_generator.__anext__() await youtube.close() async def test_fetch_own_channel( aresponses: ResponsesMockServer, ) -> None: """Test retrieving own channel.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/channels?part=snippet&mine=true", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("channel_response_snippet.json"), ), match_querystring=True, ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) channel_generator = youtube.get_user_channels() channel = await channel_generator.__anext__() assert channel assert channel.snippet assert channel.snippet.published_at == datetime( 2007, 8, 23, 0, 34, 43, tzinfo=timezone.utc, ) with pytest.raises(StopAsyncIteration): await channel_generator.__anext__() await youtube.close() @pytest.mark.parametrize( ("thumbnails", "result_url"), [ ( YouTubeChannelThumbnails( high=get_thumbnail("high"), medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "high", ), ( YouTubeChannelThumbnails( high=None, medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "medium", ), ( YouTubeChannelThumbnails( high=None, medium=None, default=get_thumbnail("default"), ), "default", ), ], ) async def test_get_hq_thumbnail( thumbnails: YouTubeChannelThumbnails, result_url: str, ) -> None: """Check if the highest quality thumbnail is returned.""" assert thumbnails.get_highest_quality().url == result_url async def test_nullable_fields( aresponses: ResponsesMockServer, ) -> None: """Check if the fields exist when they are filled.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/channels", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps( construct_fixture( "channel", ["snippet", "contentDetails", "statistics"], 1, ), ), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for subscription in youtube.get_user_channels(): assert subscription assert subscription.snippet assert subscription.content_details assert subscription.statistics async def test_nullable_fields_null( aresponses: ResponsesMockServer, ) -> None: """Check if an error is thrown if a non-requested part is accessed.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/channels", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("channel", [], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for subscription in youtube.get_user_channels(): assert subscription with pytest.raises(PartMissingError): assert subscription.snippet with pytest.raises(PartMissingError): assert subscription.content_details with pytest.raises(PartMissingError): assert subscription.statistics joostlek-python-youtube-68529d1/tests/test_helper.py000066400000000000000000000063351445733011300227030ustar00rootroot00000000000000"""Tests for the helper module.""" from collections.abc import AsyncGenerator from typing import Any import pytest from youtubeaio.helper import build_scope, build_url, chunk, first, limit from youtubeaio.types import AuthScope async def _generator(amount: int) -> AsyncGenerator[int, None]: for i in range(0, amount): yield i async def test_first() -> None: """Test if the first method works.""" first_variable = await first(_generator(1)) assert first_variable == 0 async def test_first_unavailable() -> None: """Test if the first method works.""" second_variable = await first(_generator(0)) assert second_variable is None def test_chunk() -> None: """Test if the chunk method works.""" source = list(range(0, 10)) result = list(chunk(source, 3)) assert result == [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] async def test_limit() -> None: """Test if the limit method works.""" async for i in limit(_generator(10), 3): assert i < 3 async for i in limit(_generator(2), 3): assert i < 3 async def test_limit_invalid_value() -> None: """Test if the limit method works.""" with pytest.raises(ValueError): await limit(_generator(10), 0).__anext__() async def test_build_scope() -> None: """Test build scope.""" assert ( build_scope([AuthScope.READ_ONLY, AuthScope.MANAGE]) == "https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube" ) @pytest.mark.parametrize( ("params", "remove_none", "split_lists", "enum_value", "result"), [ ( { "hello": None, }, True, True, True, "asd.com", ), ( { "hello": None, }, False, True, True, "asd.com?hello", ), ( { "hello": [ "yes", "no", ], }, False, True, True, "asd.com?hello=yes&hello=no", ), ( { "hello": [ "yes", "no", ], }, False, False, True, "asd.com?hello=%5B%27yes%27%2C%20%27no%27%5D", ), ( { "hello": AuthScope.MANAGE, }, False, True, True, "asd.com?hello=https%3A//www.googleapis.com/auth/youtube", ), ( { "hello": AuthScope.MANAGE, }, False, False, False, "asd.com?hello=AuthScope.MANAGE", ), ], ids=[ "None value removed", "None value", "Split list", "Non split list", "Enum value", "Non enum value", ], ) async def test_build_url( params: dict[str, Any], remove_none: bool, split_lists: bool, enum_value: bool, result: str, ) -> None: """Test build url.""" assert build_url("asd.com", params, remove_none, split_lists, enum_value) == result joostlek-python-youtube-68529d1/tests/test_oauth.py000066400000000000000000000053421445733011300225410ustar00rootroot00000000000000"""Tests for the YouTube client.""" import aiohttp import pytest from aiohttp.web_request import BaseRequest from aresponses import Response, ResponsesMockServer from youtubeaio.oauth import refresh_access_token from youtubeaio.types import InvalidRefreshTokenError, UnauthorizedError from . import load_fixture async def test_refresh_access_token( aresponses: ResponsesMockServer, ) -> None: """Test setting user authentication.""" async def response_handler(request: BaseRequest) -> Response: """Response handler for this test.""" assert ( await request.text() == "refresh_token=asdasd&client_id=app_id&grant_type=refresh_token&" "client_secret=app_secret&access_type=offline&prompt=consent" ) return aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("refresh_token.json"), ) aresponses.add( "oauth2.googleapis.com", "/token", "POST", response_handler, ) async with aiohttp.ClientSession() as session: await refresh_access_token("asdasd", "app_id", "app_secret", session) async def test_refresh_access_token_new_session( aresponses: ResponsesMockServer, ) -> None: """Test setting user authentication with new session.""" aresponses.add( "oauth2.googleapis.com", "/token", "POST", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("refresh_token.json"), ), ) await refresh_access_token("asdasd", "app_id", "app_secret") async def test_refresh_access_token_invalid_token( aresponses: ResponsesMockServer, ) -> None: """Test setting user authentication with invalid refresh token.""" aresponses.add( "oauth2.googleapis.com", "/token", "POST", aresponses.Response( status=400, headers={"Content-Type": "application/json"}, text='{"error": "Invalid token"}', ), ) with pytest.raises(InvalidRefreshTokenError): await refresh_access_token("asdasd", "app_id", "app_secret") async def test_refresh_access_token_unauthorized( aresponses: ResponsesMockServer, ) -> None: """Test setting user authentication while unauthorized.""" aresponses.add( "oauth2.googleapis.com", "/token", "POST", aresponses.Response( status=401, headers={"Content-Type": "application/json"}, text='{"error": "Unauthorized"}', ), ) with pytest.raises(UnauthorizedError): await refresh_access_token("asdasd", "app_id", "app_secret") joostlek-python-youtube-68529d1/tests/test_playlist_item.py000066400000000000000000000054611445733011300243020ustar00rootroot00000000000000"""Tests for the YouTube client.""" import json import aiohttp import pytest from aresponses import ResponsesMockServer from youtubeaio.types import PartMissingError from youtubeaio.youtube import YouTube from . import construct_fixture, load_fixture from .const import YOUTUBE_URL async def test_fetch_playlist_items( aresponses: ResponsesMockServer, ) -> None: """Test retrieving playlist items.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/playlistItems", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("playlist_item_response_snippet_content_details.json"), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) count = 0 async for playlist_item in youtube.get_playlist_items( "UU_x5XG1OV2P6uZZ5FSM9Ttw", ): count += 1 assert playlist_item assert playlist_item.snippet assert playlist_item.content_details assert count == 5 await youtube.close() async def test_nullable_fields( aresponses: ResponsesMockServer, ) -> None: """Check if the fields exist when they are filled.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/playlistItems", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps( construct_fixture("playlist_item", ["snippet", "contentDetails"], 1), ), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for playlist_item in youtube.get_playlist_items( "UU_x5XG1OV2P6uZZ5FSM9Ttw", ): assert playlist_item assert playlist_item.snippet assert playlist_item.content_details async def test_nullable_fields_null( aresponses: ResponsesMockServer, ) -> None: """Check if an error is thrown if a non-requested part is accessed.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/playlistItems", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("playlist_item", [], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for playlist_item in youtube.get_playlist_items( "UU_x5XG1OV2P6uZZ5FSM9Ttw", ): assert playlist_item with pytest.raises(PartMissingError): assert playlist_item.snippet with pytest.raises(PartMissingError): assert playlist_item.content_details joostlek-python-youtube-68529d1/tests/test_subscription.py000066400000000000000000000050061445733011300241420ustar00rootroot00000000000000"""Tests for the YouTube client.""" import json import aiohttp import pytest from aresponses import ResponsesMockServer from youtubeaio.types import PartMissingError from youtubeaio.youtube import YouTube from . import construct_fixture, load_fixture from .const import YOUTUBE_URL async def test_fetch_user_subscriptions( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a video.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/subscriptions?part=snippet&mine=true", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("subscription_response_snippet.json"), ), match_querystring=True, ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) count = 0 async for subscription in youtube.get_user_subscriptions(): count += 1 assert subscription assert subscription.snippet assert subscription.snippet.channel_id assert count == 2 await youtube.close() async def test_nullable_fields( aresponses: ResponsesMockServer, ) -> None: """Check if the fields exist when they are filled.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/subscriptions", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("subscription", ["snippet"], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for subscription in youtube.get_user_subscriptions(): assert subscription assert subscription.snippet async def test_nullable_fields_null( aresponses: ResponsesMockServer, ) -> None: """Check if an error is thrown if a non-requested part is accessed.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/subscriptions", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("subscription", [], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) async for subscription in youtube.get_user_subscriptions(): assert subscription with pytest.raises(PartMissingError): assert subscription.snippet.channel_id joostlek-python-youtube-68529d1/tests/test_video.py000066400000000000000000000232771445733011300225360ustar00rootroot00000000000000"""Tests for the YouTube client.""" import json from datetime import datetime, timezone import aiohttp import pytest from aiohttp.web_request import BaseRequest from aresponses import Response, ResponsesMockServer from youtubeaio.helper import first from youtubeaio.models import YouTubeVideoThumbnails from youtubeaio.types import PartMissingError from youtubeaio.youtube import YouTube from . import construct_fixture, load_fixture from .const import YOUTUBE_URL from .helper import get_thumbnail async def test_fetch_video( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a video.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("video_response_snippet.json"), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) video = await youtube.get_video(video_id="Ks-_Mh1QhMc") assert video assert video.snippet assert video.snippet.published_at == datetime( 2012, 10, 1, 15, 27, 35, tzinfo=timezone.utc, ) assert video.snippet.channel_id == "UCAuUUnT6oDeKwE6v1NGQxug" assert ( video.snippet.title == "Your body language may shape who you are | Amy Cuddy" ) assert ( video.snippet.description == "Body language affects how others see us, but it may also change how " 'we see ourselves. Social psychologist Amy Cuddy argues that "power ' "posing\" -- standing in a posture of confidence, even when we don't " "feel confident -- can boost feelings of confidence, and might have an " "impact on our chances for success. (Note: Some of the findings " "presented in this talk have been referenced in an ongoing debate " "among social scientists about robustness and reproducibility. Read " "Amy Cuddy's response here: " "http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with" "-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at " "https://www.ted.com/signup.\n\nThe TED Talks channel features the " "best talks and performances from the TED Conference, where the " "world's leading thinkers and doers give the talk of their lives in 18 " "minutes (or less). Look for talks on Technology, Entertainment and " "Design -- plus science, business, global issues, the arts and " "more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike " "TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our " "channel: https://www.youtube.com/TED" ) assert video.snippet.thumbnails assert ( video.snippet.thumbnails.default.url == "https://i.ytimg.com/vi/Ks-_Mh1QhMc/default.jpg" ) assert video.snippet.thumbnails.default.width == 120 assert video.snippet.thumbnails.default.height == 90 assert video.snippet.thumbnails.medium assert ( video.snippet.thumbnails.medium.url == "https://i.ytimg.com/vi/Ks-_Mh1QhMc/mqdefault.jpg" ) assert video.snippet.thumbnails.medium.width == 320 assert video.snippet.thumbnails.medium.height == 180 assert video.snippet.thumbnails.high assert ( video.snippet.thumbnails.high.url == "https://i.ytimg.com/vi/Ks-_Mh1QhMc/hqdefault.jpg" ) assert video.snippet.thumbnails.high.width == 480 assert video.snippet.thumbnails.high.height == 360 assert video.snippet.thumbnails.standard assert ( video.snippet.thumbnails.standard.url == "https://i.ytimg.com/vi/Ks-_Mh1QhMc/sddefault.jpg" ) assert video.snippet.thumbnails.standard.width == 640 assert video.snippet.thumbnails.standard.height == 480 assert video.snippet.thumbnails.maxres assert ( video.snippet.thumbnails.maxres.url == "https://i.ytimg.com/vi/Ks-_Mh1QhMc/maxresdefault.jpg" ) assert video.snippet.thumbnails.maxres.width == 1280 assert video.snippet.thumbnails.maxres.height == 720 await youtube.close() async def test_fetch_videos( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a list of videos.""" async def response_handler(req: BaseRequest) -> Response: """Response handler for this test.""" if "pageToken" in req.query: fixture = "video_response_2.json" else: fixture = "video_response_1.json" return aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture(fixture), ) aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", response_handler, repeat=2, ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) videos = youtube.get_videos( video_ids=["Ks-_Mh1QhMc", "GvgqDSnpRQM", "V4DDt30Aat4"], ) video1 = await videos.__anext__() assert video1 assert video1.video_id == "Ks-_Mh1QhMc" video2 = await videos.__anext__() assert video2 assert video2.video_id == "GvgqDSnpRQM" video3 = await videos.__anext__() assert video3 assert video3.video_id == "V4DDt30Aat4" async def test_fetch_single_page_video( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a page of videos.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("video_response_2.json"), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) videos = youtube.get_videos( video_ids=["V4DDt30Aat4"], ) video3 = await videos.__anext__() assert video3 assert video3.video_id == "V4DDt30Aat4" with pytest.raises(StopAsyncIteration): await videos.__anext__() async def test_fetch_no_videos() -> None: """Test retrieving no videos.""" youtube = YouTube() with pytest.raises(ValueError): await first(youtube.get_videos(video_ids=[])) @pytest.mark.parametrize( ("thumbnails", "result_url"), [ ( YouTubeVideoThumbnails( maxres=get_thumbnail("maxres"), standard=get_thumbnail("standard"), high=get_thumbnail("high"), medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "maxres", ), ( YouTubeVideoThumbnails( maxres=None, standard=get_thumbnail("standard"), high=get_thumbnail("high"), medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "standard", ), ( YouTubeVideoThumbnails( maxres=None, standard=None, high=get_thumbnail("high"), medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "high", ), ( YouTubeVideoThumbnails( maxres=None, standard=None, high=None, medium=get_thumbnail("medium"), default=get_thumbnail("default"), ), "medium", ), ( YouTubeVideoThumbnails( maxres=None, standard=None, high=None, medium=None, default=get_thumbnail("default"), ), "default", ), ], ) async def test_get_hq_thumbnail( thumbnails: YouTubeVideoThumbnails, result_url: str, ) -> None: """Check if the highest quality thumbnail is returned.""" assert thumbnails.get_highest_quality().url == result_url async def test_nullable_fields( aresponses: ResponsesMockServer, ) -> None: """Check if the fields exist when they are filled.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("video", ["snippet"], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) video = await youtube.get_video(video_id="V4DDt30Aat4") assert video assert video.snippet.channel_id == "UCAuUUnT6oDeKwE6v1NGQxug" async def test_nullable_fields_null( aresponses: ResponsesMockServer, ) -> None: """Check if an error is thrown if a non-requested part is accessed.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=json.dumps(construct_fixture("video", [], 1)), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) video = await youtube.get_video(video_id="V4DDt30Aat4") assert video with pytest.raises(PartMissingError): assert video.snippet.thumbnails joostlek-python-youtube-68529d1/tests/test_youtube.py000066400000000000000000000133201445733011300231100ustar00rootroot00000000000000"""Tests for the YouTube client.""" import asyncio import aiohttp import pytest from aiohttp.web_request import BaseRequest from aresponses import Response, ResponsesMockServer from youtubeaio.types import ( ForbiddenError, UnauthorizedError, YouTubeAPIError, YouTubeBackendError, YouTubeResourceNotFoundError, ) from youtubeaio.youtube import YouTube from . import load_fixture from .const import YOUTUBE_URL async def test_new_session( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a video.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "application/json"}, text=load_fixture("video_response_snippet.json"), ), ) async with YouTube() as youtube: assert not youtube.session await youtube.get_video(video_id="Ks-_Mh1QhMc") assert youtube.session async def test_timeout(aresponses: ResponsesMockServer) -> None: """Test request timeout.""" # Faking a timeout by sleeping async def response_handler(_: BaseRequest) -> Response: """Response handler for this test.""" await asyncio.sleep(2) return aresponses.Response(body="Goodmorning!") aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", response_handler, ) youtube = YouTube(session_timeout=1) with pytest.raises(YouTubeAPIError): assert await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_fetch_video_not_found( aresponses: ResponsesMockServer, ) -> None: """Test retrieving a non-existent video.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=404, headers={"Content-Type": "application/json"}, ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(YouTubeResourceNotFoundError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_general_error_handling( aresponses: ResponsesMockServer, ) -> None: """Test throwing unexpected error.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=418, headers={"Content-Type": "application/json"}, ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(YouTubeAPIError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_unexpected_server_response( aresponses: ResponsesMockServer, ) -> None: """Test handling a server error.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=200, headers={"Content-Type": "plain/text"}, text="Yes", ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(YouTubeAPIError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_internal_server_error( aresponses: ResponsesMockServer, ) -> None: """Test handling an internal server error.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=500, headers={"Content-Type": "plain/text"}, text="Yes", ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(YouTubeBackendError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_bad_request( aresponses: ResponsesMockServer, ) -> None: """Test handling a bad request.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=400, headers={"Content-Type": "application/json"}, text='{"message":"Something went wrong"}', ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(YouTubeAPIError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_unauthorized( aresponses: ResponsesMockServer, ) -> None: """Test handling being unauthorized.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=401, headers={"Content-Type": "application/json"}, text='{"message":"Something went wrong"}', ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(UnauthorizedError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close() async def test_not_activated( aresponses: ResponsesMockServer, ) -> None: """Test handling YouTube api not activated.""" aresponses.add( YOUTUBE_URL, "/youtube/v3/videos", "GET", aresponses.Response( status=403, headers={"Content-Type": "application/json"}, text=load_fixture("youtube_not_activated.json"), ), ) async with aiohttp.ClientSession() as session: youtube = YouTube(session=session) with pytest.raises(ForbiddenError): await youtube.get_video(video_id="Ks-_Mh1QhMc") await youtube.close()