├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── build-docs.yml │ ├── codeql-analysis.yml │ ├── lib-test.yml │ └── upload-to-pypi.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── docs ├── API │ └── CryptoPayAPI │ │ ├── errors.en.md │ │ ├── errors.ru.md │ │ ├── index.en.md │ │ ├── index.ru.md │ │ ├── schemas.en.md │ │ └── schemas.ru.md ├── _images │ ├── en │ │ ├── dark │ │ │ ├── app.png │ │ │ ├── cryptopay.png │ │ │ ├── main_bot_info.png │ │ │ ├── start.png │ │ │ ├── test_bot_info.png │ │ │ └── token.png │ │ └── light │ │ │ ├── app.png │ │ │ ├── cryptopay.png │ │ │ ├── main_bot_info.png │ │ │ ├── start.png │ │ │ ├── test_bot_info.png │ │ │ └── token.png │ └── ru │ │ ├── dark │ │ ├── app.png │ │ ├── cryptopay.png │ │ ├── main_bot_info.png │ │ ├── start.png │ │ ├── test_bot_info.png │ │ └── token.png │ │ └── light │ │ ├── app.png │ │ ├── cryptopay.png │ │ ├── main_bot_info.png │ │ ├── start.png │ │ ├── test_bot_info.png │ │ └── token.png ├── examples │ ├── get_me.en.md │ ├── get_me.ru.md │ ├── testnet_usage.en.md │ ├── testnet_usage.ru.md │ ├── transfer_usage.en.md │ ├── transfer_usage.ru.md │ ├── webhook_example.en.md │ └── webhook_example.ru.md ├── get_token.en.md ├── get_token.ru.md ├── index.en.md ├── index.ru.md ├── install.en.md └── install.ru.md ├── examples ├── constants-usage.py ├── get_me.py ├── testnet-usage.py ├── transfer-usage.py └── webhook-example.py ├── mkdocs.yml ├── poetry.lock ├── pyproject.toml ├── src └── CryptoPayAPI │ ├── __init__.py │ ├── api.py │ ├── errors.py │ ├── schemas.py │ └── types.py └── tests └── test_main.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: t.me/CryptoBot?start=IVyIR8vICYVK 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. 16 | 2. 17 | 3. 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Desktop (please complete the following information):** 26 | - OS: [e.g. iOS] 27 | - pyCryptoPayAPI Version [e.g. 0.1] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/build-docs.yml: -------------------------------------------------------------------------------- 1 | name: Build Documentation 2 | on: 3 | release: 4 | types: [published] 5 | push: 6 | branches: [ master ] 7 | 8 | permissions: 9 | contents: write 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 18 | - name: Set up Python 3.11 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: 3.11 22 | - name: Install poetry 23 | run: | 24 | python -m pip install poetry 25 | - name: Install dependencies 26 | run: poetry install 27 | - name: Build and publish documentation 28 | run: poetry run mkdocs gh-deploy --force 29 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '29 0 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'python' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/lib-test.yml: -------------------------------------------------------------------------------- 1 | name: Library test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: [ master ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-20.04 14 | strategy: 15 | matrix: 16 | python-version: ["3.8.1", "3.9", "3.10", "3.11"] 17 | 18 | environment: development 19 | env: 20 | API_TOKEN: ${{ secrets.API_TOKEN }} 21 | APP_NAME: ${{ secrets.APP_NAME }} 22 | APP_ID: ${{ secrets.APP_ID }} 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | - name: Set up Python ${{ matrix.python-version }} 27 | uses: actions/setup-python@v4 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | - name: Install poetry 31 | run: | 32 | python -m pip install poetry 33 | - name: Install dependencies 34 | run: poetry install 35 | - name: Lint with flake8 36 | run: | 37 | # stop the build if there are Python syntax errors or undefined names 38 | poetry run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 39 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 40 | poetry run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 41 | - name: Test with pytest 42 | run: | 43 | poetry run pytest tests/ 44 | -------------------------------------------------------------------------------- /.github/workflows/upload-to-pypi.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | 21 | runs-on: ubuntu-latest 22 | environment: publish 23 | 24 | steps: 25 | - uses: actions/checkout@v3 26 | - name: Set up Python v3.10 27 | uses: actions/setup-python@v3 28 | with: 29 | python-version: '3.10' 30 | - name: Install dependencies 31 | run: | 32 | python -m pip install --upgrade pip 33 | pip install build 34 | - name: Build package 35 | run: python -m build 36 | - name: Publish package 37 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 38 | with: 39 | user: __token__ 40 | password: ${{ secrets.PYPI_API_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/Windows,VisualStudioCode,Python,venv 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=Windows,VisualStudioCode,Python,venv 4 | 5 | ### Python ### 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | cover/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | .pybuilder/ 81 | target/ 82 | 83 | # Jupyter Notebook 84 | .ipynb_checkpoints 85 | 86 | # IPython 87 | profile_default/ 88 | ipython_config.py 89 | 90 | # pyenv 91 | # For a library or package, you might want to ignore these files since the code is 92 | # intended to run in multiple environments; otherwise, check them in: 93 | # .python-version 94 | 95 | # pipenv 96 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 97 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 98 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 99 | # install all needed dependencies. 100 | #Pipfile.lock 101 | 102 | # poetry 103 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 104 | # This is especially recommended for binary packages to ensure reproducibility, and is more 105 | # commonly ignored for libraries. 106 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 107 | #poetry.lock 108 | 109 | # pdm 110 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 111 | #pdm.lock 112 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 113 | # in version control. 114 | # https://pdm.fming.dev/#use-with-ide 115 | .pdm.toml 116 | 117 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 118 | __pypackages__/ 119 | 120 | # Celery stuff 121 | celerybeat-schedule 122 | celerybeat.pid 123 | 124 | # SageMath parsed files 125 | *.sage.py 126 | 127 | # Environments 128 | .env 129 | .venv 130 | env/ 131 | venv/ 132 | ENV/ 133 | env.bak/ 134 | venv.bak/ 135 | 136 | # Spyder project settings 137 | .spyderproject 138 | .spyproject 139 | 140 | # Rope project settings 141 | .ropeproject 142 | 143 | # mkdocs documentation 144 | /site 145 | 146 | # mypy 147 | .mypy_cache/ 148 | .dmypy.json 149 | dmypy.json 150 | 151 | # Pyre type checker 152 | .pyre/ 153 | 154 | # pytype static type analyzer 155 | .pytype/ 156 | 157 | # Cython debug symbols 158 | cython_debug/ 159 | 160 | # PyCharm 161 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 162 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 163 | # and can be added to the global gitignore or merged into this file. For a more nuclear 164 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 165 | #.idea/ 166 | 167 | ### venv ### 168 | # Virtualenv 169 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 170 | [Bb]in 171 | [Ii]nclude 172 | [Ll]ib 173 | [Ll]ib64 174 | [Ll]ocal 175 | [Ss]cripts 176 | pyvenv.cfg 177 | pip-selfcheck.json 178 | 179 | ### VisualStudioCode ### 180 | .vscode/* 181 | 182 | # Local History for Visual Studio Code 183 | .history/ 184 | 185 | # Built Visual Studio Code Extensions 186 | *.vsix 187 | 188 | ### VisualStudioCode Patch ### 189 | # Ignore all local history of files 190 | .history 191 | .ionide 192 | 193 | # Support for Project snippet scope 194 | .vscode/*.code-snippets 195 | 196 | # Ignore code-workspaces 197 | *.code-workspace 198 | 199 | ### Windows ### 200 | # Windows thumbnail cache files 201 | Thumbs.db 202 | Thumbs.db:encryptable 203 | ehthumbs.db 204 | ehthumbs_vista.db 205 | 206 | # Dump file 207 | *.stackdump 208 | 209 | # Folder config file 210 | [Dd]esktop.ini 211 | 212 | # Recycle Bin used on file shares 213 | $RECYCLE.BIN/ 214 | 215 | # Windows Installer files 216 | *.cab 217 | *.msi 218 | *.msix 219 | *.msm 220 | *.msp 221 | 222 | # Windows shortcuts 223 | *.lnk 224 | 225 | # End of https://www.toptal.com/developers/gitignore/api/Windows,VisualStudioCode,Python,venv -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | max@mosin.pw. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Maxim Mosin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyCryptoPayAPI 2 | ![CryptoPay](https://raw.githubusercontent.com/Foile/crypto-pay-api/24a2c869ddc78d12109319c180764ad055fbe687/media/header.svg) 3 | 4 | **[Crypto Pay](http://t.me/CryptoBot/?start=pay)** is a payment system based on [@CryptoBot](http://t.me/CryptoBot), which allows you to accept payments in cryptocurrency using the API. 5 | 6 | This library help you to work with **Crypto Pay** via [Crypto Pay API](https://help.crypt.bot/crypto-pay-api) in yours Python scripts. 7 | 8 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/LulzLoL231/pyCryptoPayAPI)](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [![CodeQL](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [![Library test](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml) 9 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pycryptopay-sdk) 10 | Documentation available on [English language](https://lulzlol231.github.io/pyCryptoPayAPI/en) 11 | Документация доступна на [Русском языке](https://lulzlol231.github.io/pyCryptoPayAPI/ru) 12 | 13 | ## Install 14 | Via pip: 15 | ``` 16 | pip install pycryptopay-sdk 17 | ``` 18 | Via git: 19 | ``` 20 | pip install git+https://github.com/LulzLoL231/pyCryptoPayAPI.git 21 | ``` 22 | Via source, *in source folder*: 23 | ``` 24 | pip install ./ 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### API 30 | First, you need to create your application and get an API token. Open [@CryptoBot](http://t.me/CryptoBot?start=pay) or [@CryptoTestnetBot](http://t.me/CryptoTestnetBot?start=pay) (for testnet), send a command `/pay` to create a new app and get API Token. 31 | Next step: try to call a simple `get_me()` method to check that everything is working well: 32 | 33 | ```python 34 | from asyncio import run 35 | 36 | from CryptoPayAPI import CryptoPay 37 | 38 | cp = CryptoPay('YOUR_API_TOKEN') 39 | print(run(cp.get_me())) # Returns Application object. 40 | ``` 41 | 42 | You can use `testnet` for testing your applications. Defaults is `mainnet`. 43 | 44 | ```python 45 | from CryptoPayAPI import CryptoPay 46 | 47 | cp = CryptoPay('YOUR_API_TOKEN', testnet=True) 48 | ``` 49 | 50 | You can find all available methods in [Methods chapter](#api-methods). 51 | Also, you can get supported [assets](#schemasassets), [paid button names](#schemaspaidbuttonnames) and [invoice status](#schemasinvoicestatus): 52 | 53 | ```python 54 | from asyncio import get_event_loop 55 | from CryptoPayAPI import CryptoPay 56 | from CryptoPayAPI.schemas import Assets, PaidButtonNames, InvoiceStatus 57 | 58 | 59 | lp = get_event_loop() 60 | cp = CryptoPay('YOUR_API_TOKEN') 61 | 62 | print(lp.run_until_complete(cp.create_invoice( 63 | Assets.USDT, 5.25, 64 | description='Example page for $5.25!', 65 | paid_btn_name=PaidButtonNames.VIEW_ITEM, 66 | paid_btn_url='https://example.com' 67 | ))) # Prints information about created invoice. 68 | 69 | print(lp.run_until_complete(cp.get_invoices( 70 | Assets.USDT, status=InvoiceStatus.PAID 71 | ))) # Prints all paid invoices. 72 | ``` 73 | 74 | ### Webhooks 75 | Use Webhooks to get updates for your app, Crypto Pay will send an HTTPS POST request to the specified URL, containing a JSON-serialized [Update](#schemasupdate). 76 | Read more about webhooks in [Crypto Pay Docs](https://help.crypt.bot/crypto-pay-api#webhooks)! 77 | Use `CryptoPay.process_webhook_update` function, for processing Crypto Pay requests. 78 | Check [webhook example](https://github.com/LulzLoL231/pyCryptoPayAPI/tree/main/examples/webhook-example.py) for more info. 79 | 80 | #### CryptoPay.process_webhook_update 81 | *Coroutine*. Processing webhook request, returns [Update](#schemasupdate) object. 82 | 83 | Arguments: 84 | * **body** (`bytes`) - JSON content from Crypto Pay request in bytes. 85 | * **headers** (`dict[str, str]`) - Request headers. 86 | ```python 87 | update = await cp.process_webhook_update(body, headers) 88 | print(f'Recieved {update.payload.amount} {update.payload.asset}!') # Recieved 10.0 ETH 89 | ``` 90 | 91 | Look full code in the [examples](https://github.com/LulzLoL231/pyCryptoPayAPI/tree/main/examples). 92 | 93 | 94 | ## API methods 95 | * [get_me](#get_me) 96 | * [create_invoice](#create_invoice) 97 | * [transfer](#transfer) 98 | * [get_invoices](#get_invoices) 99 | * [get_balances](#get_balances) 100 | * [get_exchange_rates](#get_exchange_rates) 101 | * [get_currencies](#get_currencies) 102 | 103 | ### get_me 104 | A simple method for testing your app's authentication token. Requires no parameters. Returns basic information about the app. 105 | Returns: [Application](#schemasapplication) object. 106 | 107 | ```python 108 | cp.get_me() 109 | ``` 110 | 111 | ### create_invoice 112 | Use this method to create a new invoice. Returns object of created invoice. 113 | 114 | Arguments: 115 | * **asset** ([Assets](#schemasassets) | `str`) - Currency code. Supported assets: `BTC`, `TON`, `ETH` (only testnet), `USDT`, `USDC`, `BUSD`. 116 | * **amount** (`float`) - Amount of the invoice in float. For example: `125.50` 117 | * **description** (`str`) - *Optional*. Description of the invoice. Up to 1024 symbols. 118 | * **hidden_message** (`str`) - *Optional*. The message will show when the user pays your invoice. 119 | * **paid_btn_name** ([PaidButtonName](#schemaspaidbuttonname) | `str`) - *Optional*. Paid button name. This button will be shown when your invoice was paid. Supported names: 120 | 121 | * `viewItem` - View Item 122 | * `openChannel` - Open Channel 123 | * `openBot` - Open Bot 124 | * `callback` - Return 125 | * **paid_btn_url** (`str`) - *Optional but requried when you use paid_btn_name*. Paid button URL. You can set any payment success link (for example link on your bot). Start with https or http. 126 | * **payload** (`str`, up to 4kb) - *Optional*. Some data. User ID, payment id, or any data you want to attach to the invoice. 127 | * **allow_comments** (`bool`) - *Optional*. Allow adding comments when paying an invoice. Default is True. 128 | * **allow_anonymous** (`bool`) - *Optional*. Allow pay invoice as anonymous. Default is True. 129 | * **expires_in** (`int`) - *Optional*. You can set the expiration date of the invoice in seconds. Use this period: 1-2678400 seconds. 130 | 131 | Returns: [Invoice](#schemasinvoice) object of created invoice. 132 | 133 | ```python 134 | cp.create_invoice( 135 | Assets.USDT, 5.25, 136 | description='Example page for $5.25!', 137 | paid_btn_name=PaidButtonNames.VIEW_ITEM, 138 | paid_btn_url='https://example.com' 139 | ) 140 | ``` 141 | 142 | ### transfer 143 | Use this method to send coins from your app to the user. Returns object of completed transfer. 144 | 145 | Arguments: 146 | * **user_id** (`int`) - Telegram User ID. The user needs to have an account in our bot (send /start if no). 147 | * **asset** ([Assets](#schemasassets)) - Currency code. Supported assets: `BTC`, `TON`, `ETH` (only testnet), `USDT`, `USDC`, `BUSD`. 148 | * **amount** (`float`) - Amount of the transfer in float. For example: `125.50` 149 | * **spend_id** (`str`) - It is used to make your request idempotent. It's guaranteed that only one of the transfers with the same spend_id will be accepted by Crypto Pay API. This parameter is useful when the transfer should be retried (i.e. request timeout/connection reset/500 HTTP status/etc). You can use a withdrawal id or something. Up to 64 symbols. 150 | * **comment** (`str`) - *Optional*. The comment of the invoice. The comment will show in the notification about the transfer. Up to 1024 symbols. 151 | 152 | Returns: [Transfer](#schemastransfer) object of created transfer. 153 | 154 | ```python 155 | cp.transfer(265300852, Assets.USDT, 3.0, 'pCBA226ghd', comment='donate') 156 | ``` 157 | 158 | 159 | ### get_invoice 160 | Use this method to get invoices of your app. On success, the returns array of [Invoice](#schemasinvoice). 161 | 162 | Arguments: 163 | * **asset** ([Assets](#schemasassets)) - *Optional*. Currency code. Supported assets: `BTC`, `TON`, `ETH` (only testnet), `USDT`, `USDC`, `BUSD`. Default: all assets. 164 | * **invoice_ids** (`str`) - *Optional*. Invoice IDs separated by comma. 165 | * **status** ([InvoiceStatus](#schemasinvoicestatus)) - *Optional*. Status of invoices. Available statuses: active, paid and expired. Default: all statuses. 166 | * **offset** (`int`) - *Optional*. Offset needed to return a specific subset of invoices. Default 0. 167 | * **count** (`int`) - *Optional*. Number of invoices to return. Default 100, max 1000. 168 | 169 | Returns: array of [Invoice](#schemasinvoice) objects. 170 | 171 | ```python 172 | cp.get_invoices( 173 | schemas.Assets.USDT, status=schemas.InvoiceStatus.PAID, count=10 174 | ) 175 | ``` 176 | 177 | ### get_balance 178 | Use this method to get balance of your app. Returns array of assets. 179 | 180 | Returns: array of [Balance](#schemasbalance) objects. 181 | 182 | ```python 183 | cp.get_balance() 184 | ``` 185 | 186 | ### get_exchange_rates 187 | Use this method to get exchange rates of supported currencies. Returns array of currencies. 188 | 189 | Returns: array of [ExchangeRate](#schemasexchangerate) objects. 190 | 191 | ```python 192 | cp.get_exchange_rates() 193 | ``` 194 | 195 | ### get_currencies 196 | Use this method to supported currencies. Returns array of currencies. 197 | 198 | Returns: array of [Currency](#schemascurrency) objects. 199 | 200 | ```python 201 | cp.get_currencies() 202 | ``` 203 | 204 | ## Constants and schemas 205 | ```python 206 | from CryptoBotAPI import schemas 207 | ``` 208 | 209 | #### schemas.Asset 210 | constant | value 211 | ------------- | ------ 212 | `Assets.BTC` | `BTC` 213 | `Assets.TON` | `TON` 214 | `Assets.ETH` | `ETH` 215 | `Assets.USDT` | `USDT` 216 | `Assets.USDC` | `USDC` 217 | `Assets.BUSD` | `BUSD` 218 | 219 | #### schemas.PaidButtonNames 220 | constant | value 221 | ------------------------------ | ------------- 222 | `PaidButtonNames.VIEW_ITEM` | `viewItem` 223 | `PaidButtonNames.OPEN_CHANNEL` | `openChannel` 224 | `PaidButtonNames.OPEN_BOT` | `openBot` 225 | `PaidButtonNames.CALLBACK` | `callback` 226 | 227 | #### schemas.InvoiceStatus 228 | constant | value 229 | ----------------------- | --------- 230 | `InvoiceStatus.ACTIVE` | `active` 231 | `InvoiceStatus.PAID` | `paid` 232 | `InvoiceStatus.EXPIRED` | `expired` 233 | 234 | #### schemas.Invoice 235 | key | type 236 | ------------------ | ------------------------------------ 237 | `invoice_id` | `int` 238 | `status` | [InvoiceStatus](#schemasinvoicestatus) 239 | `hash` | `str` 240 | `asset` | [Assets](#schemasassets) 241 | `amount` | `decimal.Decimal` 242 | `pay_url` | `str` 243 | `description` | `Optional[str]` 244 | `created_at` | `datetime.datetime` 245 | `allow_comments` | `bool` 246 | `allow_anonymous` | `bool` 247 | `expiration_date` | `Optional[datetime.datetime]` 248 | `paid_at` | `Optional[datetime.datetime]` 249 | `paid_anonymously` | `Optional[bool]` 250 | `comment` | `Optional[str]` 251 | `hidden_message` | `Optional[str]` 252 | `payload` | `Optional[str]` 253 | `paid_btn_name` | `Optional[`[PaidButtonNames](#schemaspaidbuttonnames)`]` 254 | `paid_btn_url` | `Optional[str]` 255 | 256 | #### schemas.Transfer 257 | key | type 258 | -------------- | ----------------------- 259 | `transfer_id` | `int` 260 | `user_id` | `int` 261 | `asset` | [Assets](#schemasassets) 262 | `amount` | `decimal.Decimal` 263 | `status` | `Literal['completed']` 264 | `completed_at` | `datetime.datetime` 265 | `comment` | `Optional[str]` 266 | 267 | #### schemas.Application 268 | key | type 269 | --------------------------------- | ----- 270 | `app_id` | `int` 271 | `name` | `str` 272 | `payment_processing_bot_username` | `str` 273 | 274 | #### schemas.Balance 275 | key | type 276 | --------------- | ------------------ 277 | `currency_code` | `str` 278 | `available` | `decimal.Decimal ` 279 | 280 | #### schemas.ExchangeRate 281 | key | type 282 | ---------- | ----------------- 283 | `is_valid` | `bool` 284 | `source` | `str` 285 | `target` | `str` 286 | `rate` | `decimal.Decimal` 287 | 288 | #### schemas.Currency 289 | key | type 290 | --------------- | ------------------ 291 | `is_blockchain` | `bool` 292 | `is_stablecoin` | `bool` 293 | `is_fiat` | `bool` 294 | `name` | `str` 295 | `code` | `str` 296 | `url` | `Optional[str]` 297 | `decimals` | `int` 298 | 299 | #### schemas.UpdateType 300 | constant | value 301 | ------------------------- | -------------- 302 | `UpdateType.INVOICE_PAID` | `invoice_paid` 303 | 304 | #### schemas.Update 305 | key | type 306 | -------------- | ------------------------------ 307 | `update_id` | `int` 308 | `update_type` | [UpdateType](#schemasupdatetype) 309 | `request_date` | `datetime` 310 | `payload` | [Invoice](#schemasinvoice) 311 | -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/errors.en.md: -------------------------------------------------------------------------------- 1 | # Errors 2 | ::: src.CryptoPayAPI.errors -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/errors.ru.md: -------------------------------------------------------------------------------- 1 | # Исключения 2 | ::: src.CryptoPayAPI.errors -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/index.en.md: -------------------------------------------------------------------------------- 1 | # CryptoPay 2 | ::: src.CryptoPayAPI.api -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/index.ru.md: -------------------------------------------------------------------------------- 1 | # Класс CryptoPay 2 | ::: src.CryptoPayAPI.api -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/schemas.en.md: -------------------------------------------------------------------------------- 1 | # Schemas 2 | ::: src.CryptoPayAPI.schemas -------------------------------------------------------------------------------- /docs/API/CryptoPayAPI/schemas.ru.md: -------------------------------------------------------------------------------- 1 | # Схемы 2 | ::: src.CryptoPayAPI.schemas -------------------------------------------------------------------------------- /docs/_images/en/dark/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/app.png -------------------------------------------------------------------------------- /docs/_images/en/dark/cryptopay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/cryptopay.png -------------------------------------------------------------------------------- /docs/_images/en/dark/main_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/main_bot_info.png -------------------------------------------------------------------------------- /docs/_images/en/dark/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/start.png -------------------------------------------------------------------------------- /docs/_images/en/dark/test_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/test_bot_info.png -------------------------------------------------------------------------------- /docs/_images/en/dark/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/dark/token.png -------------------------------------------------------------------------------- /docs/_images/en/light/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/app.png -------------------------------------------------------------------------------- /docs/_images/en/light/cryptopay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/cryptopay.png -------------------------------------------------------------------------------- /docs/_images/en/light/main_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/main_bot_info.png -------------------------------------------------------------------------------- /docs/_images/en/light/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/start.png -------------------------------------------------------------------------------- /docs/_images/en/light/test_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/test_bot_info.png -------------------------------------------------------------------------------- /docs/_images/en/light/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/en/light/token.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/app.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/cryptopay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/cryptopay.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/main_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/main_bot_info.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/start.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/test_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/test_bot_info.png -------------------------------------------------------------------------------- /docs/_images/ru/dark/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/dark/token.png -------------------------------------------------------------------------------- /docs/_images/ru/light/app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/app.png -------------------------------------------------------------------------------- /docs/_images/ru/light/cryptopay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/cryptopay.png -------------------------------------------------------------------------------- /docs/_images/ru/light/main_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/main_bot_info.png -------------------------------------------------------------------------------- /docs/_images/ru/light/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/start.png -------------------------------------------------------------------------------- /docs/_images/ru/light/test_bot_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/test_bot_info.png -------------------------------------------------------------------------------- /docs/_images/ru/light/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LulzLoL231/pyCryptoPayAPI/24a351e66d19945729b2333daf37f28556bc6f16/docs/_images/ru/light/token.png -------------------------------------------------------------------------------- /docs/examples/get_me.en.md: -------------------------------------------------------------------------------- 1 | # Get application 2 | ```python 3 | --8<-- "examples/get_me.py" 4 | ``` -------------------------------------------------------------------------------- /docs/examples/get_me.ru.md: -------------------------------------------------------------------------------- 1 | # Получение объекта приложения 2 | ```python 3 | --8<-- "examples/get_me.py" 4 | ``` -------------------------------------------------------------------------------- /docs/examples/testnet_usage.en.md: -------------------------------------------------------------------------------- 1 | # Use testnet 2 | ```python 3 | --8<-- "examples/testnet-usage.py" 4 | ``` -------------------------------------------------------------------------------- /docs/examples/testnet_usage.ru.md: -------------------------------------------------------------------------------- 1 | # Использование тестовой сети 2 | ```python 3 | --8<-- "examples/testnet-usage.py" 4 | ``` -------------------------------------------------------------------------------- /docs/examples/transfer_usage.en.md: -------------------------------------------------------------------------------- 1 | # Transfer crypto 2 | !!! warning "Transfer method maybe disabled!" 3 | 4 | From Crypto Pay API v1.1.2, `transfer` method disabled by default for new bots, before using this method, activate it in bot settings. 5 | 6 | ```python 7 | --8<-- "examples/transfer-usage.py" 8 | ``` -------------------------------------------------------------------------------- /docs/examples/transfer_usage.ru.md: -------------------------------------------------------------------------------- 1 | # Отправка криптовалюты 2 | !!! warning "Метод Transfer может быть отключен!" 3 | 4 | Начиная с Crypto Pay API v1.1.2, метод `transfer` отключен для новых ботов, перед использованием этого метода, активируйте его в настройках бота. 5 | 6 | ```python 7 | --8<-- "examples/transfer-usage.py" 8 | ``` -------------------------------------------------------------------------------- /docs/examples/webhook_example.en.md: -------------------------------------------------------------------------------- 1 | # Webhook 2 | Using `fastapi` as a server. 3 | ```python 4 | --8<-- "examples/webhook-example.py" 5 | ``` -------------------------------------------------------------------------------- /docs/examples/webhook_example.ru.md: -------------------------------------------------------------------------------- 1 | # Webhook 2 | Используем `fastapi` в качестве сервера. 3 | ```python 4 | --8<-- "examples/webhook-example.py" 5 | ``` -------------------------------------------------------------------------------- /docs/get_token.en.md: -------------------------------------------------------------------------------- 1 | # Get API token 2 | To get a CryptoPay API token, you need to contact the bot [@CryptoBot](https://t.me/CryptoBot). 3 | !!! note "Using the testnet" 4 | 5 | To get a token in the test network, you should contact the bot [@CryptoTestnetBot](https://t.me/CryptoTestnetBot), and follow this instruction. 6 | 7 | ## About bot 8 | !!! warning "Check bot name" 9 | 10 | Before using the bot, make sure that the information about the bot matches the one below! 11 | 12 | For main bot [@CryptoBot](https://t.me/CryptoBot): 13 | ![main_bot_info](../_images/en/dark/main_bot_info.png#only-dark){ loading=lazy } 14 | ![main_bot_info](../_images/en/light/main_bot_info.png#only-light){ loading=lazy } 15 | 16 | from test bot [@CryptoTestnetBot](https://t.me/CryptoTestnetBot): 17 | ![test_bot_info](../_images/en/dark/test_bot_info.png#only-dark){ loading=lazy } 18 | ![test_bot_info](../_images/en/light/test_bot_info.png#only-light){ loading=lazy } 19 | 20 | ## Start bot 21 | Use the `/start` command in the bot to exit to the main menu and press the button 🏝️ Crypto Pay 22 | ![start](../_images/en/dark/start.png#only-dark){ loading=lazy } 23 | ![start](../_images/en/light/start.png#only-light){ loading=lazy } 24 | 25 | ## Creating of application 26 | Click the Create application button, CryptoBot will automatically create an application for you with a unique name. 27 | ![cryptopay](../_images/en/dark/cryptopay.png#only-dark){ loading=lazy } 28 | ![cryptopay](../_images/en/light/cryptopay.png#only-light){ loading=lazy } 29 | 30 | ## Getting API token 31 | Click the "API token" button to see your API token, it consists of an application identifier and a unique string in the format `000000:XXXXXXXXXXXXXXXXXXXXXXXXX` 32 | ![app](../_images/en/dark/app.png#only-dark){ loading=lazy } 33 | ![app](../_images/en/light/app.png#only-light){ loading=lazy } 34 | ![token](../_images/en/dark/token.png#only-dark){ loading=lazy } 35 | ![token](../_images/en/light/token.png#only-light){ loading=lazy } 36 | 37 | ## Using of token 38 | After receiving the token, use it when creating an instance of the class [`CryptoPay`][src.CryptoPayAPI.CryptoPay] like this `CryptoPay('000000:XXXXXXXXXXXXXXXXXXXXXXXXX')`. 39 | 40 | !!! warning 41 | 42 | Don't forget to set the `testnet=True` flag if you are using a test bot token, otherwise authorization will fail. 43 | -------------------------------------------------------------------------------- /docs/get_token.ru.md: -------------------------------------------------------------------------------- 1 | # Получение API токена 2 | Для получения CryptoPay API токена, необходимо обратиться к боту [@CryptoBot](https://t.me/CryptoBot). 3 | !!! note "Использование тестовой сети" 4 | 5 | Для получения токена в тестовой сети, обращаться следует к боту [@CryptoTestnetBot](https://t.me/CryptoTestnetBot), и следовать этой инструкции. 6 | 7 | ## Информация о боте 8 | !!! warning "Проверяйте название бота" 9 | 10 | Перед использованием бота, убедитесь что информация о боте соответствует с указанной ниже! 11 | 12 | Для основного бота [@CryptoBot](https://t.me/CryptoBot): 13 | ![main_bot_info](../_images/ru/dark/main_bot_info.png#only-dark){ loading=lazy } 14 | ![main_bot_info](../_images/ru/light/main_bot_info.png#only-light){ loading=lazy } 15 | 16 | Для тестового бота [@CryptoTestnetBot](https://t.me/CryptoTestnetBot): 17 | ![test_bot_info](../_images/ru/dark/test_bot_info.png#only-dark){ loading=lazy } 18 | ![test_bot_info](../_images/ru/light/test_bot_info.png#only-light){ loading=lazy } 19 | 20 | ## Вход в бота 21 | Используйте команду `/start` в боте для выхода в главное меню и нажмите кнопку 🏝️ Crypto Pay 22 | ![start](../_images/ru/dark/start.png#only-dark){ loading=lazy } 23 | ![start](../_images/ru/light/start.png#only-light){ loading=lazy } 24 | 25 | ## Создание приложения 26 | Нажмите кнопку Создать приложение, CryptoBot автоматически создаст вам приложение с уникальным именем. 27 | ![cryptopay](../_images/ru/dark/cryptopay.png#only-dark){ loading=lazy } 28 | ![cryptopay](../_images/ru/light/cryptopay.png#only-light){ loading=lazy } 29 | 30 | ## Получение API токена 31 | Нажмите кнопку "API-токен" чтобы увидеть свой API токен, состоит он из идентификатора приложения и уникальной строки в формате `000000:XXXXXXXXXXXXXXXXXXXXXXXXX` 32 | ![app](../_images/ru/dark/app.png#only-dark){ loading=lazy } 33 | ![app](../_images/ru/light/app.png#only-light){ loading=lazy } 34 | ![token](../_images/ru/dark/token.png#only-dark){ loading=lazy } 35 | ![token](../_images/ru/light/token.png#only-light){ loading=lazy } 36 | 37 | ## Использование токена 38 | Получив токен используйте его при создании инстанса класса [`CryptoPay`][src.CryptoPayAPI.CryptoPay] вот так `CryptoPay('000000:XXXXXXXXXXXXXXXXXXXXXXXXX')`. 39 | 40 | !!! warning "Внимание" 41 | 42 | Не забудьте указать флаг `testnet=True` если вы используете токен тестового бота, иначе авторизация не будет пройдена. 43 | -------------------------------------------------------------------------------- /docs/index.en.md: -------------------------------------------------------------------------------- 1 | # Home 2 | ![CryptoPay](https://raw.githubusercontent.com/Foile/crypto-pay-api/24a2c869ddc78d12109319c180764ad055fbe687/media/header.svg) 3 | 4 | **[Crypto Pay](http://t.me/CryptoBot/?start=pay)** is a payment system based on [@CryptoBot](http://t.me/CryptoBot), which allows you to accept payments in cryptocurrency using the API. 5 | 6 | This library help you to work with **Crypto Pay** via [Crypto Pay API](https://help.crypt.bot/crypto-pay-api) in yours Python scripts. 7 | 8 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/LulzLoL231/pyCryptoPayAPI)](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [![CodeQL](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [![Library test](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml) 9 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pycryptopay-sdk) 10 | 11 | Documentation available on [English language](./en/) 12 | Документация доступна на [Русском языке](./ru/) -------------------------------------------------------------------------------- /docs/index.ru.md: -------------------------------------------------------------------------------- 1 | # Главная 2 | ![CryptoPay](https://raw.githubusercontent.com/Foile/crypto-pay-api/24a2c869ddc78d12109319c180764ad055fbe687/media/header.svg) 3 | 4 | **[Crypto Pay](http://t.me/CryptoBot/?start=pay)** система оплаты на основе [@CryptoBot](http://t.me/CryptoBot), который позволяет вам принимать платежи криптовалютой через их API. 5 | 6 | Эта библиотека поможет вам взаимодействовать с **Crypto Pay** с помощью [Crypto Pay API](https://help.crypt.bot/crypto-pay-api) в ваших Python скриптах. 7 | 8 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/LulzLoL231/pyCryptoPayAPI)](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [![CodeQL](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [![Library test](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml/badge.svg)](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml) 9 | ![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pycryptopay-sdk) 10 | 11 | Documentation available on [English language](./en/) 12 | Документация доступна на [Русском языке](./ru/) -------------------------------------------------------------------------------- /docs/install.en.md: -------------------------------------------------------------------------------- 1 | # Install 2 | The library can be installed in several ways: 3 | === "With PYPI" 4 | ```sh 5 | pip install pycryptopay-sdk 6 | ``` 7 | 8 | === "With pip+git" 9 | ```sh 10 | pip install git+https://github.com/LulzLoL231/pyCryptoPayAPI.git 11 | ``` 12 | 13 | === "From source" 14 | ```sh 15 | pip install . # (1)! 16 | ``` 17 | 18 | 1. Execute in root folder. 19 | -------------------------------------------------------------------------------- /docs/install.ru.md: -------------------------------------------------------------------------------- 1 | # Установка 2 | Библиотеку можно установить несколькими способами: 3 | === "Через PYPI" 4 | ```sh 5 | pip install pycryptopay-sdk 6 | ``` 7 | 8 | === "Через pip+git" 9 | ```sh 10 | pip install git+https://github.com/LulzLoL231/pyCryptoPayAPI.git 11 | ``` 12 | 13 | === "Из исходников" 14 | ```sh 15 | pip install . # (1)! 16 | ``` 17 | 18 | 1. Выполнять в папке с библиотекой 19 | -------------------------------------------------------------------------------- /examples/constants-usage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - Constants example usage. 4 | # Created by LulzLoL231 at 3/6/22 5 | # 6 | from os import environ 7 | from asyncio import run 8 | 9 | from CryptoPayAPI import CryptoPay 10 | from CryptoPayAPI.schemas import Assets, PaidButtonNames, InvoiceStatus 11 | 12 | 13 | TOKEN = environ.get('CRYPTOPAY_API_TOKEN', '') 14 | if not TOKEN: 15 | print('Use shell argument "CRYPTOPAY_API_TOKEN" for your Crypto Pay API token!') 16 | exit(1) 17 | 18 | 19 | async def main(): 20 | cp = CryptoPay(TOKEN) 21 | 22 | new_invoice = await cp.create_invoice( 23 | Assets.USDT, 5.25, 24 | description='Example page for $5.25!', 25 | paid_btn_name=PaidButtonNames.VIEW_ITEM, 26 | paid_btn_url='https://example.com' 27 | ) 28 | print('Your a new Invoice: ', new_invoice) 29 | invoices = await cp.get_invoices( 30 | status=InvoiceStatus.ACTIVE 31 | ) 32 | print(f'You have {len(invoices)} active invoices!') 33 | 34 | 35 | run(main()) 36 | -------------------------------------------------------------------------------- /examples/get_me.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - get_me example usage. 4 | # Created by LulzLoL231 at 3/6/22 5 | # 6 | from os import environ 7 | from asyncio import run 8 | 9 | from CryptoPayAPI import CryptoPay 10 | 11 | 12 | TOKEN = environ.get('CRYPTOPAY_API_TOKEN', '') 13 | if not TOKEN: 14 | print('Use shell argument "CRYPTOPAY_API_TOKEN" for your Crypto Pay API token!') 15 | exit(1) 16 | 17 | 18 | async def main(): 19 | cp = CryptoPay(TOKEN) 20 | 21 | app = await cp.get_me() 22 | print('Application: ', app) 23 | 24 | 25 | run(main()) 26 | -------------------------------------------------------------------------------- /examples/testnet-usage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - Testnet example usage. 4 | # Created by LulzLoL231 at 3/6/22 5 | # 6 | from os import environ 7 | from asyncio import run 8 | 9 | from CryptoPayAPI import CryptoPay 10 | 11 | 12 | TOKEN = environ.get('CRYPTOPAY_API_TOKEN', '') 13 | if not TOKEN: 14 | print('Use shell argument "CRYPTOPAY_API_TOKEN" for your Crypto Pay API token!') 15 | exit(1) 16 | 17 | 18 | async def main(): 19 | cp = CryptoPay(TOKEN, testnet=True) 20 | 21 | app = await cp.get_me() 22 | 23 | print('Testnet application: ', app) 24 | 25 | 26 | run(main()) 27 | -------------------------------------------------------------------------------- /examples/transfer-usage.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - Transfer example usage. 4 | # Created by LulzLoL231 at 3/6/22 5 | # 6 | from os import environ 7 | from asyncio import run 8 | 9 | from CryptoPayAPI import CryptoPay 10 | from CryptoPayAPI.schemas import Assets 11 | 12 | 13 | TOKEN = environ.get('CRYPTOPAY_API_TOKEN', '') 14 | if not TOKEN: 15 | print('Use shell argument "CRYPTOPAY_API_TOKEN" for your Crypto Pay API token!') 16 | exit(1) 17 | 18 | 19 | async def main(): 20 | cp = CryptoPay(TOKEN) 21 | 22 | if input('You want to donate me 3 USDT? -> ').lower() in ['n', 'no', '-']: 23 | print('Okay :(') 24 | exit() 25 | 26 | transfer = cp.transfer( 27 | 265300852, Assets.USDT, 3.0, 'pCBA226ghd', comment='donate' 28 | ) 29 | 30 | print('Transfer: ', transfer) 31 | 32 | 33 | run(main()) 34 | -------------------------------------------------------------------------------- /examples/webhook-example.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - webhook example usage. 4 | # Created by LulzLoL231 at 12/9/22 5 | # 6 | from os import environ 7 | 8 | from uvicorn import run 9 | from fastapi import FastAPI, Request 10 | 11 | from CryptoPayAPI import CryptoPay 12 | 13 | 14 | TOKEN = environ.get('CRYPTOPAY_API_TOKEN', '') 15 | if not TOKEN: 16 | print('Use shell argument "CRYPTOPAY_API_TOKEN" for your Crypto Pay API token!') 17 | exit(1) 18 | 19 | 20 | app = FastAPI( 21 | openapi_tags=None, # disable docs generating 22 | redoc_url=None # disable docs generating 23 | ) 24 | cp = CryptoPay(TOKEN) 25 | 26 | 27 | @app.post('/') 28 | async def process_update(request: Request): 29 | body = await request.body() 30 | headers = dict(request.headers) 31 | update = await cp.process_webhook_update(body, headers) 32 | print(f'Recieved {update.payload.amount} {update.payload.asset}!') 33 | return 'ok' 34 | 35 | 36 | if __name__ == '__main__': 37 | run(app) 38 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: pyCryptoPay-SDK Documentation 2 | repo_url: https://github.com/LulzLoL231/pyCryptoPayAPI 3 | repo_name: LulzLoL231/pyCryptoPayAPI 4 | edit_uri: edit/master/docs/ 5 | copyright: Copyright © 2023 Maxim Mosin 6 | 7 | nav: 8 | - Главная: 'index.md' 9 | - Установка: 'install.md' 10 | - Получение API токена: 'get_token.md' 11 | - Примеры: 12 | - Получение объекта приложения: 'examples/get_me.md' 13 | - Использование тестовой сети: 'examples/testnet_usage.md' 14 | - Отправка криптовалюты: 'examples/transfer_usage.md' 15 | - Вебхук: 'examples/webhook_example.md' 16 | - API: 17 | - CryptoPay: 'API/CryptoPayAPI/index.md' 18 | - Схемы: 'API/CryptoPayAPI/schemas.md' 19 | - Исключения: 'API/CryptoPayAPI/errors.md' 20 | - Помощь: 21 | - Сообщить о багах: 'https://github.com/LulzLoL231/pyCryptoPayAPI/issues' 22 | - Документация CryptoPay API: 'https://help.crypt.bot/crypto-pay-api' 23 | 24 | theme: 25 | name: material 26 | language: ru 27 | icon: 28 | repo: fontawesome/brands/git-alt 29 | features: 30 | - navigation.tracking 31 | - navigation.sections 32 | - navigation.top 33 | - content.code.annotate 34 | palette: 35 | - media: "(prefers-color-scheme: light)" 36 | scheme: default 37 | toggle: 38 | icon: material/weather-night 39 | name: Switch to dark mode 40 | - media: "(prefers-color-scheme: dark)" 41 | scheme: slate 42 | toggle: 43 | icon: material/weather-sunny 44 | name: Switch to light mode 45 | 46 | plugins: 47 | - git-committers: 48 | repository: LulzLoL231/pyCryptoPayAPI 49 | - git-authors 50 | - search 51 | - mkdocstrings 52 | - glightbox 53 | - i18n: 54 | default_language: ru 55 | docs_structure: suffix 56 | material_alternate: true 57 | languages: 58 | en: 59 | name: English 60 | site_name: pyCryptoPay-SDK Documentation 61 | homepage: ./en/ 62 | ru: 63 | name: Русский 64 | site_name: Документация pyCryptoPay-SDK 65 | homepage: ./ru/ 66 | nav_translations: 67 | en: 68 | Главная: Home 69 | Установка: Install 70 | Получение API токена: Get API token 71 | Примеры: Examples 72 | Получение объекта приложения: Get application 73 | Использование тестовой сети: Use testnet 74 | Отправка криптовалюты: Transfer crypto 75 | Вебхук: Webhook 76 | CryptoPay: CryptoPay 77 | Классы ошибок: Errors 78 | Схемы: Schemas 79 | Помощь: Help 80 | Сообщить о багах: Issue tracker 81 | Документация CryptoPay API: CryptoPay API Docs 82 | 83 | - git-revision-date-localized: 84 | enable_creation_date: true 85 | fallback_to_build_date: true 86 | - section-index 87 | 88 | extra: 89 | social: 90 | - icon: fontawesome/brands/python 91 | link: https://pypi.org/project/pycryptopay-sdk/ 92 | name: Project on PYPI 93 | - icon: fontawesome/brands/github 94 | link: https://github.com/LulzLoL231 95 | name: Author GitHub 96 | 97 | markdown_extensions: 98 | - admonition 99 | - pymdownx.details 100 | - pymdownx.superfences 101 | - pymdownx.snippets 102 | - pymdownx.tabbed: 103 | alternate_style: true 104 | - attr_list 105 | - md_in_html -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "anyio" 3 | version = "3.6.2" 4 | description = "High level compatibility layer for multiple asynchronous event loop implementations" 5 | category = "main" 6 | optional = false 7 | python-versions = ">=3.6.2" 8 | 9 | [package.dependencies] 10 | idna = ">=2.8" 11 | sniffio = ">=1.1" 12 | 13 | [package.extras] 14 | doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] 15 | test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] 16 | trio = ["trio (>=0.16,<0.22)"] 17 | 18 | [[package]] 19 | name = "attrs" 20 | version = "22.2.0" 21 | description = "Classes Without Boilerplate" 22 | category = "dev" 23 | optional = false 24 | python-versions = ">=3.6" 25 | 26 | [package.extras] 27 | cov = ["attrs", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] 28 | dev = ["attrs"] 29 | docs = ["furo", "sphinx", "myst-parser", "zope.interface", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"] 30 | tests = ["attrs", "zope.interface"] 31 | tests-no-zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] 32 | tests_no_zope = ["hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist", "cloudpickle", "mypy (>=0.971,<0.990)", "pytest-mypy-plugins"] 33 | 34 | [[package]] 35 | name = "autopep8" 36 | version = "2.0.1" 37 | description = "A tool that automatically formats Python code to conform to the PEP 8 style guide" 38 | category = "dev" 39 | optional = false 40 | python-versions = ">=3.6" 41 | 42 | [package.dependencies] 43 | pycodestyle = ">=2.10.0" 44 | tomli = {version = "*", markers = "python_version < \"3.11\""} 45 | 46 | [[package]] 47 | name = "babel" 48 | version = "2.11.0" 49 | description = "Internationalization utilities" 50 | category = "dev" 51 | optional = false 52 | python-versions = ">=3.6" 53 | 54 | [package.dependencies] 55 | pytz = ">=2015.7" 56 | 57 | [[package]] 58 | name = "beautifulsoup4" 59 | version = "4.11.1" 60 | description = "Screen-scraping library" 61 | category = "dev" 62 | optional = false 63 | python-versions = ">=3.6.0" 64 | 65 | [package.dependencies] 66 | soupsieve = ">1.2" 67 | 68 | [package.extras] 69 | html5lib = ["html5lib"] 70 | lxml = ["lxml"] 71 | 72 | [[package]] 73 | name = "bumpver" 74 | version = "2022.1120" 75 | description = "Bump version numbers in project files." 76 | category = "dev" 77 | optional = false 78 | python-versions = ">=2.7" 79 | 80 | [package.dependencies] 81 | click = {version = "*", markers = "python_version >= \"3.6\""} 82 | colorama = ">=0.4" 83 | lexid = "*" 84 | pathlib2 = "*" 85 | toml = "*" 86 | 87 | [[package]] 88 | name = "certifi" 89 | version = "2022.12.7" 90 | description = "Python package for providing Mozilla's CA Bundle." 91 | category = "main" 92 | optional = false 93 | python-versions = ">=3.6" 94 | 95 | [[package]] 96 | name = "charset-normalizer" 97 | version = "2.1.1" 98 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 99 | category = "dev" 100 | optional = false 101 | python-versions = ">=3.6.0" 102 | 103 | [package.extras] 104 | unicode_backport = ["unicodedata2"] 105 | 106 | [[package]] 107 | name = "click" 108 | version = "8.1.3" 109 | description = "Composable command line interface toolkit" 110 | category = "dev" 111 | optional = false 112 | python-versions = ">=3.7" 113 | 114 | [package.dependencies] 115 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 116 | 117 | [[package]] 118 | name = "colorama" 119 | version = "0.4.6" 120 | description = "Cross-platform colored terminal text." 121 | category = "dev" 122 | optional = false 123 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" 124 | 125 | [[package]] 126 | name = "exceptiongroup" 127 | version = "1.1.0" 128 | description = "Backport of PEP 654 (exception groups)" 129 | category = "dev" 130 | optional = false 131 | python-versions = ">=3.7" 132 | 133 | [package.extras] 134 | test = ["pytest (>=6)"] 135 | 136 | [[package]] 137 | name = "fastapi" 138 | version = "0.88.0" 139 | description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" 140 | category = "dev" 141 | optional = false 142 | python-versions = ">=3.7" 143 | 144 | [package.dependencies] 145 | pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" 146 | starlette = "0.22.0" 147 | 148 | [package.extras] 149 | all = ["email-validator (>=1.1.1)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] 150 | dev = ["pre-commit (>=2.17.0,<3.0.0)", "ruff (==0.0.138)", "uvicorn[standard] (>=0.12.0,<0.19.0)"] 151 | doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer[all] (>=0.6.1,<0.7.0)"] 152 | test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.10.0)", "coverage[toml] (>=6.5.0,<7.0)", "databases[sqlite] (>=0.3.2,<0.7.0)", "email-validator (>=1.1.1,<2.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.23.0,<0.24.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.982)", "orjson (>=3.2.1,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=7.1.3,<8.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "ruff (==0.0.138)", "sqlalchemy (>=1.3.18,<=1.4.41)", "types-orjson (==3.6.2)", "types-ujson (==5.5.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] 153 | 154 | [[package]] 155 | name = "flake8" 156 | version = "6.0.0" 157 | description = "the modular source code checker: pep8 pyflakes and co" 158 | category = "dev" 159 | optional = false 160 | python-versions = ">=3.8.1" 161 | 162 | [package.dependencies] 163 | mccabe = ">=0.7.0,<0.8.0" 164 | pycodestyle = ">=2.10.0,<2.11.0" 165 | pyflakes = ">=3.0.0,<3.1.0" 166 | 167 | [[package]] 168 | name = "ghp-import" 169 | version = "2.1.0" 170 | description = "Copy your docs directly to the gh-pages branch." 171 | category = "dev" 172 | optional = false 173 | python-versions = "*" 174 | 175 | [package.dependencies] 176 | python-dateutil = ">=2.8.1" 177 | 178 | [package.extras] 179 | dev = ["twine", "markdown", "flake8", "wheel"] 180 | 181 | [[package]] 182 | name = "gitdb" 183 | version = "4.0.10" 184 | description = "Git Object Database" 185 | category = "dev" 186 | optional = false 187 | python-versions = ">=3.7" 188 | 189 | [package.dependencies] 190 | smmap = ">=3.0.1,<6" 191 | 192 | [[package]] 193 | name = "gitpython" 194 | version = "3.1.30" 195 | description = "GitPython is a python library used to interact with Git repositories" 196 | category = "dev" 197 | optional = false 198 | python-versions = ">=3.7" 199 | 200 | [package.dependencies] 201 | gitdb = ">=4.0.1,<5" 202 | 203 | [[package]] 204 | name = "griffe" 205 | version = "0.25.3" 206 | description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." 207 | category = "dev" 208 | optional = false 209 | python-versions = ">=3.7" 210 | 211 | [package.dependencies] 212 | colorama = ">=0.4" 213 | 214 | [package.extras] 215 | async = ["aiofiles (>=0.7,<1.0)"] 216 | 217 | [[package]] 218 | name = "h11" 219 | version = "0.14.0" 220 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 221 | category = "main" 222 | optional = false 223 | python-versions = ">=3.7" 224 | 225 | [[package]] 226 | name = "httpcore" 227 | version = "0.16.3" 228 | description = "A minimal low-level HTTP client." 229 | category = "main" 230 | optional = false 231 | python-versions = ">=3.7" 232 | 233 | [package.dependencies] 234 | anyio = ">=3.0,<5.0" 235 | certifi = "*" 236 | h11 = ">=0.13,<0.15" 237 | sniffio = ">=1.0.0,<2.0.0" 238 | 239 | [package.extras] 240 | http2 = ["h2 (>=3,<5)"] 241 | socks = ["socksio (>=1.0.0,<2.0.0)"] 242 | 243 | [[package]] 244 | name = "httpx" 245 | version = "0.23.3" 246 | description = "The next generation HTTP client." 247 | category = "main" 248 | optional = false 249 | python-versions = ">=3.7" 250 | 251 | [package.dependencies] 252 | certifi = "*" 253 | httpcore = ">=0.15.0,<0.17.0" 254 | rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} 255 | sniffio = "*" 256 | 257 | [package.extras] 258 | brotli = ["brotli", "brotlicffi"] 259 | cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] 260 | http2 = ["h2 (>=3,<5)"] 261 | socks = ["socksio (>=1.0.0,<2.0.0)"] 262 | 263 | [[package]] 264 | name = "idna" 265 | version = "3.4" 266 | description = "Internationalized Domain Names in Applications (IDNA)" 267 | category = "main" 268 | optional = false 269 | python-versions = ">=3.5" 270 | 271 | [[package]] 272 | name = "importlib-metadata" 273 | version = "6.0.0" 274 | description = "Read metadata from Python packages" 275 | category = "dev" 276 | optional = false 277 | python-versions = ">=3.7" 278 | 279 | [package.dependencies] 280 | zipp = ">=0.5" 281 | 282 | [package.extras] 283 | docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "sphinx-lint", "jaraco.tidelift (>=1.4)"] 284 | perf = ["ipython"] 285 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8", "importlib-resources (>=1.3)"] 286 | 287 | [[package]] 288 | name = "iniconfig" 289 | version = "2.0.0" 290 | description = "brain-dead simple config-ini parsing" 291 | category = "dev" 292 | optional = false 293 | python-versions = ">=3.7" 294 | 295 | [[package]] 296 | name = "jinja2" 297 | version = "3.1.2" 298 | description = "A very fast and expressive template engine." 299 | category = "dev" 300 | optional = false 301 | python-versions = ">=3.7" 302 | 303 | [package.dependencies] 304 | MarkupSafe = ">=2.0" 305 | 306 | [package.extras] 307 | i18n = ["Babel (>=2.7)"] 308 | 309 | [[package]] 310 | name = "lexid" 311 | version = "2021.1006" 312 | description = "Variable width build numbers with lexical ordering." 313 | category = "dev" 314 | optional = false 315 | python-versions = ">=2.7" 316 | 317 | [[package]] 318 | name = "lxml" 319 | version = "4.9.2" 320 | description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." 321 | category = "dev" 322 | optional = false 323 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" 324 | 325 | [package.extras] 326 | cssselect = ["cssselect (>=0.7)"] 327 | html5 = ["html5lib"] 328 | htmlsoup = ["beautifulsoup4"] 329 | source = ["Cython (>=0.29.7)"] 330 | 331 | [[package]] 332 | name = "markdown" 333 | version = "3.3.7" 334 | description = "Python implementation of Markdown." 335 | category = "dev" 336 | optional = false 337 | python-versions = ">=3.6" 338 | 339 | [package.dependencies] 340 | importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} 341 | 342 | [package.extras] 343 | testing = ["coverage", "pyyaml"] 344 | 345 | [[package]] 346 | name = "markupsafe" 347 | version = "2.1.1" 348 | description = "Safely add untrusted strings to HTML/XML markup." 349 | category = "dev" 350 | optional = false 351 | python-versions = ">=3.7" 352 | 353 | [[package]] 354 | name = "mccabe" 355 | version = "0.7.0" 356 | description = "McCabe checker, plugin for flake8" 357 | category = "dev" 358 | optional = false 359 | python-versions = ">=3.6" 360 | 361 | [[package]] 362 | name = "mergedeep" 363 | version = "1.3.4" 364 | description = "A deep merge function for 🐍." 365 | category = "dev" 366 | optional = false 367 | python-versions = ">=3.6" 368 | 369 | [[package]] 370 | name = "mkdocs" 371 | version = "1.4.2" 372 | description = "Project documentation with Markdown." 373 | category = "dev" 374 | optional = false 375 | python-versions = ">=3.7" 376 | 377 | [package.dependencies] 378 | click = ">=7.0" 379 | colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} 380 | ghp-import = ">=1.0" 381 | importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} 382 | jinja2 = ">=2.11.1" 383 | markdown = ">=3.2.1,<3.4" 384 | mergedeep = ">=1.3.4" 385 | packaging = ">=20.5" 386 | pyyaml = ">=5.1" 387 | pyyaml-env-tag = ">=0.1" 388 | watchdog = ">=2.0" 389 | 390 | [package.extras] 391 | i18n = ["babel (>=2.9.0)"] 392 | min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml-env-tag (==0.1)", "pyyaml (==5.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] 393 | 394 | [[package]] 395 | name = "mkdocs-autorefs" 396 | version = "0.4.1" 397 | description = "Automatically link across pages in MkDocs." 398 | category = "dev" 399 | optional = false 400 | python-versions = ">=3.7" 401 | 402 | [package.dependencies] 403 | Markdown = ">=3.3" 404 | mkdocs = ">=1.1" 405 | 406 | [[package]] 407 | name = "mkdocs-git-authors-plugin" 408 | version = "0.7.0" 409 | description = "Mkdocs plugin to display git authors of a page" 410 | category = "dev" 411 | optional = false 412 | python-versions = ">=3.6" 413 | 414 | [package.dependencies] 415 | mkdocs = ">=1.0" 416 | 417 | [[package]] 418 | name = "mkdocs-git-committers-plugin-2" 419 | version = "1.1.2" 420 | description = "" 421 | category = "dev" 422 | optional = false 423 | python-versions = ">=2.7" 424 | develop = false 425 | 426 | [package.dependencies] 427 | beautifulsoup4 = "*" 428 | gitpython = "*" 429 | mkdocs = ">=1.0.3" 430 | requests = "*" 431 | 432 | [package.source] 433 | type = "git" 434 | url = "https://github.com/LulzLoL231/mkdocs-git-committers-plugin-2.git" 435 | reference = "v1.1.2" 436 | resolved_reference = "9b68645e226d1d2ecea20c2a4f19ec5d8d164f89" 437 | 438 | [[package]] 439 | name = "mkdocs-git-revision-date-localized-plugin" 440 | version = "1.1.0" 441 | description = "Mkdocs plugin that enables displaying the localized date of the last git modification of a markdown file." 442 | category = "dev" 443 | optional = false 444 | python-versions = ">=3.6" 445 | 446 | [package.dependencies] 447 | babel = ">=2.7.0" 448 | GitPython = "*" 449 | mkdocs = ">=1.0" 450 | 451 | [[package]] 452 | name = "mkdocs-glightbox" 453 | version = "0.3.1" 454 | description = "MkDocs plugin supports image lightbox with GLightbox." 455 | category = "dev" 456 | optional = false 457 | python-versions = "*" 458 | 459 | [package.dependencies] 460 | beautifulsoup4 = ">=4.11.1" 461 | 462 | [[package]] 463 | name = "mkdocs-literate-nav" 464 | version = "0.5.0" 465 | description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" 466 | category = "dev" 467 | optional = false 468 | python-versions = ">=3.6,<4.0" 469 | 470 | [package.dependencies] 471 | mkdocs = ">=1.0.3,<2.0.0" 472 | 473 | [[package]] 474 | name = "mkdocs-material" 475 | version = "8.5.11" 476 | description = "Documentation that simply works" 477 | category = "dev" 478 | optional = false 479 | python-versions = ">=3.7" 480 | 481 | [package.dependencies] 482 | jinja2 = ">=3.0.2" 483 | markdown = ">=3.2" 484 | mkdocs = ">=1.4.0" 485 | mkdocs-material-extensions = ">=1.1" 486 | pygments = ">=2.12" 487 | pymdown-extensions = ">=9.4" 488 | requests = ">=2.26" 489 | 490 | [[package]] 491 | name = "mkdocs-material-extensions" 492 | version = "1.1.1" 493 | description = "Extension pack for Python Markdown and MkDocs Material." 494 | category = "dev" 495 | optional = false 496 | python-versions = ">=3.7" 497 | 498 | [[package]] 499 | name = "mkdocs-section-index" 500 | version = "0.3.4" 501 | description = "MkDocs plugin to allow clickable sections that lead to an index page" 502 | category = "dev" 503 | optional = false 504 | python-versions = ">=3.6,<4.0" 505 | 506 | [package.dependencies] 507 | mkdocs = ">=1.1,<2.0" 508 | 509 | [[package]] 510 | name = "mkdocs-static-i18n" 511 | version = "0.54" 512 | description = "" 513 | category = "dev" 514 | optional = false 515 | python-versions = ">=3.7" 516 | develop = false 517 | 518 | [package.dependencies] 519 | mkdocs = ">=1.2.3" 520 | 521 | [package.source] 522 | type = "git" 523 | url = "https://github.com/LulzLoL231/mkdocs-static-i18n.git" 524 | reference = "v0.54" 525 | resolved_reference = "426872da30eacb12e94c54c9104722f04bb38011" 526 | 527 | [[package]] 528 | name = "mkdocstrings" 529 | version = "0.19.1" 530 | description = "Automatic documentation from sources, for MkDocs." 531 | category = "dev" 532 | optional = false 533 | python-versions = ">=3.7" 534 | 535 | [package.dependencies] 536 | Jinja2 = ">=2.11.1" 537 | Markdown = ">=3.3" 538 | MarkupSafe = ">=1.1" 539 | mkdocs = ">=1.2" 540 | mkdocs-autorefs = ">=0.3.1" 541 | mkdocstrings-python = {version = ">=0.5.2", optional = true, markers = "extra == \"python\""} 542 | pymdown-extensions = ">=6.3" 543 | 544 | [package.extras] 545 | crystal = ["mkdocstrings-crystal (>=0.3.4)"] 546 | python = ["mkdocstrings-python (>=0.5.2)"] 547 | python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] 548 | 549 | [[package]] 550 | name = "mkdocstrings-python" 551 | version = "0.8.3" 552 | description = "A Python handler for mkdocstrings." 553 | category = "dev" 554 | optional = false 555 | python-versions = ">=3.7" 556 | 557 | [package.dependencies] 558 | griffe = ">=0.24" 559 | mkdocstrings = ">=0.19" 560 | 561 | [[package]] 562 | name = "mypy" 563 | version = "0.991" 564 | description = "Optional static typing for Python" 565 | category = "dev" 566 | optional = false 567 | python-versions = ">=3.7" 568 | 569 | [package.dependencies] 570 | mypy-extensions = ">=0.4.3" 571 | tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} 572 | typing-extensions = ">=3.10" 573 | 574 | [package.extras] 575 | dmypy = ["psutil (>=4.0)"] 576 | install-types = ["pip"] 577 | python2 = ["typed-ast (>=1.4.0,<2)"] 578 | reports = ["lxml"] 579 | 580 | [[package]] 581 | name = "mypy-extensions" 582 | version = "0.4.3" 583 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 584 | category = "dev" 585 | optional = false 586 | python-versions = "*" 587 | 588 | [[package]] 589 | name = "packaging" 590 | version = "23.0" 591 | description = "Core utilities for Python packages" 592 | category = "dev" 593 | optional = false 594 | python-versions = ">=3.7" 595 | 596 | [[package]] 597 | name = "pathlib2" 598 | version = "2.3.7.post1" 599 | description = "Object-oriented filesystem paths" 600 | category = "dev" 601 | optional = false 602 | python-versions = "*" 603 | 604 | [package.dependencies] 605 | six = "*" 606 | 607 | [[package]] 608 | name = "pluggy" 609 | version = "1.0.0" 610 | description = "plugin and hook calling mechanisms for python" 611 | category = "dev" 612 | optional = false 613 | python-versions = ">=3.6" 614 | 615 | [package.extras] 616 | dev = ["pre-commit", "tox"] 617 | testing = ["pytest", "pytest-benchmark"] 618 | 619 | [[package]] 620 | name = "pycodestyle" 621 | version = "2.10.0" 622 | description = "Python style guide checker" 623 | category = "dev" 624 | optional = false 625 | python-versions = ">=3.6" 626 | 627 | [[package]] 628 | name = "pydantic" 629 | version = "1.10.4" 630 | description = "Data validation and settings management using python type hints" 631 | category = "main" 632 | optional = false 633 | python-versions = ">=3.7" 634 | 635 | [package.dependencies] 636 | typing-extensions = ">=4.2.0" 637 | 638 | [package.extras] 639 | dotenv = ["python-dotenv (>=0.10.4)"] 640 | email = ["email-validator (>=1.0.3)"] 641 | 642 | [[package]] 643 | name = "pyflakes" 644 | version = "3.0.1" 645 | description = "passive checker of Python programs" 646 | category = "dev" 647 | optional = false 648 | python-versions = ">=3.6" 649 | 650 | [[package]] 651 | name = "pygments" 652 | version = "2.14.0" 653 | description = "Pygments is a syntax highlighting package written in Python." 654 | category = "dev" 655 | optional = false 656 | python-versions = ">=3.6" 657 | 658 | [package.extras] 659 | plugins = ["importlib-metadata"] 660 | 661 | [[package]] 662 | name = "pymdown-extensions" 663 | version = "9.9" 664 | description = "Extension pack for Python Markdown." 665 | category = "dev" 666 | optional = false 667 | python-versions = ">=3.7" 668 | 669 | [package.dependencies] 670 | markdown = ">=3.2" 671 | 672 | [[package]] 673 | name = "pytest" 674 | version = "7.2.0" 675 | description = "pytest: simple powerful testing with Python" 676 | category = "dev" 677 | optional = false 678 | python-versions = ">=3.7" 679 | 680 | [package.dependencies] 681 | attrs = ">=19.2.0" 682 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 683 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 684 | iniconfig = "*" 685 | packaging = "*" 686 | pluggy = ">=0.12,<2.0" 687 | tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} 688 | 689 | [package.extras] 690 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 691 | 692 | [[package]] 693 | name = "pytest-asyncio" 694 | version = "0.20.3" 695 | description = "Pytest support for asyncio" 696 | category = "dev" 697 | optional = false 698 | python-versions = ">=3.7" 699 | 700 | [package.dependencies] 701 | pytest = ">=6.1.0" 702 | 703 | [package.extras] 704 | docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] 705 | testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] 706 | 707 | [[package]] 708 | name = "python-dateutil" 709 | version = "2.8.2" 710 | description = "Extensions to the standard Python datetime module" 711 | category = "dev" 712 | optional = false 713 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" 714 | 715 | [package.dependencies] 716 | six = ">=1.5" 717 | 718 | [[package]] 719 | name = "pytz" 720 | version = "2022.7" 721 | description = "World timezone definitions, modern and historical" 722 | category = "dev" 723 | optional = false 724 | python-versions = "*" 725 | 726 | [[package]] 727 | name = "pyyaml" 728 | version = "6.0" 729 | description = "YAML parser and emitter for Python" 730 | category = "dev" 731 | optional = false 732 | python-versions = ">=3.6" 733 | 734 | [[package]] 735 | name = "pyyaml-env-tag" 736 | version = "0.1" 737 | description = "A custom YAML tag for referencing environment variables in YAML files. " 738 | category = "dev" 739 | optional = false 740 | python-versions = ">=3.6" 741 | 742 | [package.dependencies] 743 | pyyaml = "*" 744 | 745 | [[package]] 746 | name = "requests" 747 | version = "2.28.1" 748 | description = "Python HTTP for Humans." 749 | category = "dev" 750 | optional = false 751 | python-versions = ">=3.7, <4" 752 | 753 | [package.dependencies] 754 | certifi = ">=2017.4.17" 755 | charset-normalizer = ">=2,<3" 756 | idna = ">=2.5,<4" 757 | urllib3 = ">=1.21.1,<1.27" 758 | 759 | [package.extras] 760 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 761 | use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] 762 | 763 | [[package]] 764 | name = "rfc3986" 765 | version = "1.5.0" 766 | description = "Validating URI References per RFC 3986" 767 | category = "main" 768 | optional = false 769 | python-versions = "*" 770 | 771 | [package.dependencies] 772 | idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} 773 | 774 | [package.extras] 775 | idna2008 = ["idna"] 776 | 777 | [[package]] 778 | name = "six" 779 | version = "1.16.0" 780 | description = "Python 2 and 3 compatibility utilities" 781 | category = "dev" 782 | optional = false 783 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 784 | 785 | [[package]] 786 | name = "smmap" 787 | version = "5.0.0" 788 | description = "A pure Python implementation of a sliding window memory map manager" 789 | category = "dev" 790 | optional = false 791 | python-versions = ">=3.6" 792 | 793 | [[package]] 794 | name = "sniffio" 795 | version = "1.3.0" 796 | description = "Sniff out which async library your code is running under" 797 | category = "main" 798 | optional = false 799 | python-versions = ">=3.7" 800 | 801 | [[package]] 802 | name = "soupsieve" 803 | version = "2.3.2.post1" 804 | description = "A modern CSS selector implementation for Beautiful Soup." 805 | category = "dev" 806 | optional = false 807 | python-versions = ">=3.6" 808 | 809 | [[package]] 810 | name = "starlette" 811 | version = "0.22.0" 812 | description = "The little ASGI library that shines." 813 | category = "dev" 814 | optional = false 815 | python-versions = ">=3.7" 816 | 817 | [package.dependencies] 818 | anyio = ">=3.4.0,<5" 819 | typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} 820 | 821 | [package.extras] 822 | full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyaml"] 823 | 824 | [[package]] 825 | name = "toml" 826 | version = "0.10.2" 827 | description = "Python Library for Tom's Obvious, Minimal Language" 828 | category = "dev" 829 | optional = false 830 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 831 | 832 | [[package]] 833 | name = "tomli" 834 | version = "2.0.1" 835 | description = "A lil' TOML parser" 836 | category = "dev" 837 | optional = false 838 | python-versions = ">=3.7" 839 | 840 | [[package]] 841 | name = "typing-extensions" 842 | version = "4.4.0" 843 | description = "Backported and Experimental Type Hints for Python 3.7+" 844 | category = "main" 845 | optional = false 846 | python-versions = ">=3.7" 847 | 848 | [[package]] 849 | name = "urllib3" 850 | version = "1.26.13" 851 | description = "HTTP library with thread-safe connection pooling, file post, and more." 852 | category = "dev" 853 | optional = false 854 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 855 | 856 | [package.extras] 857 | brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"] 858 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"] 859 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 860 | 861 | [[package]] 862 | name = "uvicorn" 863 | version = "0.20.0" 864 | description = "The lightning-fast ASGI server." 865 | category = "dev" 866 | optional = false 867 | python-versions = ">=3.7" 868 | 869 | [package.dependencies] 870 | click = ">=7.0" 871 | h11 = ">=0.8" 872 | 873 | [package.extras] 874 | standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"] 875 | 876 | [[package]] 877 | name = "watchdog" 878 | version = "2.2.1" 879 | description = "Filesystem events monitoring" 880 | category = "dev" 881 | optional = false 882 | python-versions = ">=3.6" 883 | 884 | [package.extras] 885 | watchmedo = ["PyYAML (>=3.10)"] 886 | 887 | [[package]] 888 | name = "zipp" 889 | version = "3.11.0" 890 | description = "Backport of pathlib-compatible object wrapper for zip files" 891 | category = "dev" 892 | optional = false 893 | python-versions = ">=3.7" 894 | 895 | [package.extras] 896 | docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"] 897 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "jaraco.functools", "more-itertools", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "pytest-flake8"] 898 | 899 | [metadata] 900 | lock-version = "1.1" 901 | python-versions = "^3.8.1" 902 | content-hash = "3b0289bc6188300fc93375895479f01b2f46c53488a39a74865ce523c255256d" 903 | 904 | [metadata.files] 905 | anyio = [ 906 | {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, 907 | {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, 908 | ] 909 | attrs = [ 910 | {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, 911 | {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, 912 | ] 913 | autopep8 = [ 914 | {file = "autopep8-2.0.1-py2.py3-none-any.whl", hash = "sha256:be5bc98c33515b67475420b7b1feafc8d32c1a69862498eda4983b45bffd2687"}, 915 | {file = "autopep8-2.0.1.tar.gz", hash = "sha256:d27a8929d8dcd21c0f4b3859d2d07c6c25273727b98afc984c039df0f0d86566"}, 916 | ] 917 | babel = [ 918 | {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, 919 | {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, 920 | ] 921 | beautifulsoup4 = [ 922 | {file = "beautifulsoup4-4.11.1-py3-none-any.whl", hash = "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30"}, 923 | {file = "beautifulsoup4-4.11.1.tar.gz", hash = "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693"}, 924 | ] 925 | bumpver = [ 926 | {file = "bumpver-2022.1120-py2.py3-none-any.whl", hash = "sha256:9da18a6997ade04c66bec05f5349acc5f2f146b16fb77b307f91ef3370c6aa55"}, 927 | {file = "bumpver-2022.1120.tar.gz", hash = "sha256:ff8ad562a2ed87e862e07683cb68c4b61046679bf155f7a7ebb20b2ea47775cd"}, 928 | ] 929 | certifi = [ 930 | {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, 931 | {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, 932 | ] 933 | charset-normalizer = [ 934 | {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, 935 | {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, 936 | ] 937 | click = [ 938 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 939 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 940 | ] 941 | colorama = [ 942 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, 943 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, 944 | ] 945 | exceptiongroup = [ 946 | {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, 947 | {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, 948 | ] 949 | fastapi = [ 950 | {file = "fastapi-0.88.0-py3-none-any.whl", hash = "sha256:263b718bb384422fe3d042ffc9a0c8dece5e034ab6586ff034f6b4b1667c3eee"}, 951 | {file = "fastapi-0.88.0.tar.gz", hash = "sha256:915bf304180a0e7c5605ec81097b7d4cd8826ff87a02bb198e336fb9f3b5ff02"}, 952 | ] 953 | flake8 = [ 954 | {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"}, 955 | {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"}, 956 | ] 957 | ghp-import = [ 958 | {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, 959 | {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, 960 | ] 961 | gitdb = [ 962 | {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, 963 | {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, 964 | ] 965 | gitpython = [ 966 | {file = "GitPython-3.1.30-py3-none-any.whl", hash = "sha256:cd455b0000615c60e286208ba540271af9fe531fa6a87cc590a7298785ab2882"}, 967 | {file = "GitPython-3.1.30.tar.gz", hash = "sha256:769c2d83e13f5d938b7688479da374c4e3d49f71549aaf462b646db9602ea6f8"}, 968 | ] 969 | griffe = [ 970 | {file = "griffe-0.25.3-py3-none-any.whl", hash = "sha256:c98e8471a4fc7675a7989f45563a9f7ccbfdfb1713725526d69dec1bbdcda74a"}, 971 | {file = "griffe-0.25.3.tar.gz", hash = "sha256:a71f156851649b3f0bdad6eb6bf7d7ac70e720a30da9f2d5a60e042480e92c03"}, 972 | ] 973 | h11 = [ 974 | {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, 975 | {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, 976 | ] 977 | httpcore = [ 978 | {file = "httpcore-0.16.3-py3-none-any.whl", hash = "sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0"}, 979 | {file = "httpcore-0.16.3.tar.gz", hash = "sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb"}, 980 | ] 981 | httpx = [ 982 | {file = "httpx-0.23.3-py3-none-any.whl", hash = "sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6"}, 983 | {file = "httpx-0.23.3.tar.gz", hash = "sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9"}, 984 | ] 985 | idna = [ 986 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 987 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 988 | ] 989 | importlib-metadata = [ 990 | {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, 991 | {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, 992 | ] 993 | iniconfig = [ 994 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 995 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 996 | ] 997 | jinja2 = [ 998 | {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, 999 | {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, 1000 | ] 1001 | lexid = [ 1002 | {file = "lexid-2021.1006-py2.py3-none-any.whl", hash = "sha256:5526bb5606fd74c7add23320da5f02805bddd7c77916f2dc1943e6bada8605ed"}, 1003 | {file = "lexid-2021.1006.tar.gz", hash = "sha256:509a3a4cc926d3dbf22b203b18a4c66c25e6473fb7c0e0d30374533ac28bafe5"}, 1004 | ] 1005 | lxml = [ 1006 | {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, 1007 | {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, 1008 | {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, 1009 | {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, 1010 | {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, 1011 | {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, 1012 | {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, 1013 | {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, 1014 | {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, 1015 | {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, 1016 | {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, 1017 | {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, 1018 | {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, 1019 | {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, 1020 | {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, 1021 | {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, 1022 | {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, 1023 | {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, 1024 | {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, 1025 | {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, 1026 | {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, 1027 | {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, 1028 | {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, 1029 | {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, 1030 | {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, 1031 | {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, 1032 | {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, 1033 | {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, 1034 | {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, 1035 | {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, 1036 | {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, 1037 | {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, 1038 | {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, 1039 | {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, 1040 | {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, 1041 | {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, 1042 | {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, 1043 | {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, 1044 | {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, 1045 | {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, 1046 | {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, 1047 | {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, 1048 | {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, 1049 | {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, 1050 | {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, 1051 | {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, 1052 | {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, 1053 | {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, 1054 | {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, 1055 | {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, 1056 | {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, 1057 | {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, 1058 | {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, 1059 | {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, 1060 | {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, 1061 | {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, 1062 | {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, 1063 | {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, 1064 | {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, 1065 | {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, 1066 | {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, 1067 | {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, 1068 | {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, 1069 | {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, 1070 | {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, 1071 | {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, 1072 | {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, 1073 | {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, 1074 | {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, 1075 | {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, 1076 | {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, 1077 | {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, 1078 | {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, 1079 | {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, 1080 | {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, 1081 | {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, 1082 | {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, 1083 | ] 1084 | markdown = [ 1085 | {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"}, 1086 | {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"}, 1087 | ] 1088 | markupsafe = [ 1089 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, 1090 | {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, 1091 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, 1092 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, 1093 | {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, 1094 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, 1095 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, 1096 | {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, 1097 | {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, 1098 | {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, 1099 | {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, 1100 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, 1101 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, 1102 | {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, 1103 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, 1104 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, 1105 | {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, 1106 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, 1107 | {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, 1108 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, 1109 | {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, 1110 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, 1111 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, 1112 | {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, 1113 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, 1114 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, 1115 | {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, 1116 | {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, 1117 | {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, 1118 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, 1119 | {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, 1120 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, 1121 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, 1122 | {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, 1123 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, 1124 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, 1125 | {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, 1126 | {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, 1127 | {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, 1128 | {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, 1129 | ] 1130 | mccabe = [ 1131 | {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, 1132 | {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, 1133 | ] 1134 | mergedeep = [ 1135 | {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, 1136 | {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, 1137 | ] 1138 | mkdocs = [ 1139 | {file = "mkdocs-1.4.2-py3-none-any.whl", hash = "sha256:c8856a832c1e56702577023cd64cc5f84948280c1c0fcc6af4cd39006ea6aa8c"}, 1140 | {file = "mkdocs-1.4.2.tar.gz", hash = "sha256:8947af423a6d0facf41ea1195b8e1e8c85ad94ac95ae307fe11232e0424b11c5"}, 1141 | ] 1142 | mkdocs-autorefs = [ 1143 | {file = "mkdocs-autorefs-0.4.1.tar.gz", hash = "sha256:70748a7bd025f9ecd6d6feeba8ba63f8e891a1af55f48e366d6d6e78493aba84"}, 1144 | {file = "mkdocs_autorefs-0.4.1-py3-none-any.whl", hash = "sha256:a2248a9501b29dc0cc8ba4c09f4f47ff121945f6ce33d760f145d6f89d313f5b"}, 1145 | ] 1146 | mkdocs-git-authors-plugin = [ 1147 | {file = "mkdocs-git-authors-plugin-0.7.0.tar.gz", hash = "sha256:087b63090ebbf6b93f20d8b8e5fbac8e8b140e2107e432ca2ac8dd1d3a1000f5"}, 1148 | {file = "mkdocs_git_authors_plugin-0.7.0-py3-none-any.whl", hash = "sha256:cc469208f98e9db08561eac08a9d8ccd0209a60ee5bd0e3e94b6840a5abc54b6"}, 1149 | ] 1150 | mkdocs-git-committers-plugin-2 = [] 1151 | mkdocs-git-revision-date-localized-plugin = [ 1152 | {file = "mkdocs-git-revision-date-localized-plugin-1.1.0.tar.gz", hash = "sha256:38517e2084229da1a1b9460e846c2748d238c2d79efd405d1b9174a87bd81d79"}, 1153 | {file = "mkdocs_git_revision_date_localized_plugin-1.1.0-py3-none-any.whl", hash = "sha256:4ba0e49abea3e9f6ee26e2623ff7283873da657471c61f1d0cfbb986f403316d"}, 1154 | ] 1155 | mkdocs-glightbox = [ 1156 | {file = "mkdocs-glightbox-0.3.1.tar.gz", hash = "sha256:ac85e2d4d422cc4a670fa276840f0aa3064a1ec4ad25ccb6d6e82d11bb11e513"}, 1157 | {file = "mkdocs_glightbox-0.3.1-py3-none-any.whl", hash = "sha256:1974f505e3272b617b5e7552fd09d8d918d267631ed991772b4bd103dc74bea2"}, 1158 | ] 1159 | mkdocs-literate-nav = [ 1160 | {file = "mkdocs-literate-nav-0.5.0.tar.gz", hash = "sha256:c63d4385bb2b520baede25badad2d0936acebff3da175922c600d0a91902d8ff"}, 1161 | {file = "mkdocs_literate_nav-0.5.0-py3-none-any.whl", hash = "sha256:b41149172af38c1a1df5e8d63292cbe7ed2a1431cd5daf884289036f2a9c7cca"}, 1162 | ] 1163 | mkdocs-material = [ 1164 | {file = "mkdocs_material-8.5.11-py3-none-any.whl", hash = "sha256:c907b4b052240a5778074a30a78f31a1f8ff82d7012356dc26898b97559f082e"}, 1165 | {file = "mkdocs_material-8.5.11.tar.gz", hash = "sha256:b0ea0513fd8cab323e8a825d6692ea07fa83e917bb5db042e523afecc7064ab7"}, 1166 | ] 1167 | mkdocs-material-extensions = [ 1168 | {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, 1169 | {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"}, 1170 | ] 1171 | mkdocs-section-index = [ 1172 | {file = "mkdocs-section-index-0.3.4.tar.gz", hash = "sha256:050151bfe7c0e374f197335e0ecb19c45b53dbafc0f817aa203f0cc24bcf7d10"}, 1173 | {file = "mkdocs_section_index-0.3.4-py3-none-any.whl", hash = "sha256:214f7a6df9d35a5772e9577f3899ff3edd90044064589e6dd4d84615b72a8024"}, 1174 | ] 1175 | mkdocs-static-i18n = [] 1176 | mkdocstrings = [ 1177 | {file = "mkdocstrings-0.19.1-py3-none-any.whl", hash = "sha256:32a38d88f67f65b264184ea71290f9332db750d189dea4200cbbe408d304c261"}, 1178 | {file = "mkdocstrings-0.19.1.tar.gz", hash = "sha256:d1037cacb4b522c1e8c164ed5d00d724a82e49dcee0af80db8fb67b384faeef9"}, 1179 | ] 1180 | mkdocstrings-python = [ 1181 | {file = "mkdocstrings-python-0.8.3.tar.gz", hash = "sha256:9ae473f6dc599339b09eee17e4d2b05d6ac0ec29860f3fc9b7512d940fc61adf"}, 1182 | {file = "mkdocstrings_python-0.8.3-py3-none-any.whl", hash = "sha256:4e6e1cd6f37a785de0946ced6eb846eb2f5d891ac1cc2c7b832943d3529087a7"}, 1183 | ] 1184 | mypy = [ 1185 | {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, 1186 | {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, 1187 | {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, 1188 | {file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, 1189 | {file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, 1190 | {file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, 1191 | {file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, 1192 | {file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, 1193 | {file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, 1194 | {file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, 1195 | {file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, 1196 | {file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, 1197 | {file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, 1198 | {file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, 1199 | {file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, 1200 | {file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, 1201 | {file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, 1202 | {file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, 1203 | {file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, 1204 | {file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, 1205 | {file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, 1206 | {file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, 1207 | {file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, 1208 | {file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, 1209 | {file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, 1210 | {file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, 1211 | {file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"}, 1212 | {file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"}, 1213 | {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, 1214 | {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, 1215 | ] 1216 | mypy-extensions = [ 1217 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 1218 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 1219 | ] 1220 | packaging = [ 1221 | {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, 1222 | {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, 1223 | ] 1224 | pathlib2 = [ 1225 | {file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"}, 1226 | {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, 1227 | ] 1228 | pluggy = [ 1229 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 1230 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 1231 | ] 1232 | pycodestyle = [ 1233 | {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, 1234 | {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, 1235 | ] 1236 | pydantic = [ 1237 | {file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"}, 1238 | {file = "pydantic-1.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817"}, 1239 | {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c"}, 1240 | {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cec42b95dbb500a1f7120bdf95c401f6abb616bbe8785ef09887306792e66e"}, 1241 | {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8775d4ef5e7299a2f4699501077a0defdaac5b6c4321173bcb0f3c496fbadf85"}, 1242 | {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:572066051eeac73d23f95ba9a71349c42a3e05999d0ee1572b7860235b850cc6"}, 1243 | {file = "pydantic-1.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:7feb6a2d401f4d6863050f58325b8d99c1e56f4512d98b11ac64ad1751dc647d"}, 1244 | {file = "pydantic-1.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39f4a73e5342b25c2959529f07f026ef58147249f9b7431e1ba8414a36761f53"}, 1245 | {file = "pydantic-1.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:983e720704431a6573d626b00662eb78a07148c9115129f9b4351091ec95ecc3"}, 1246 | {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d52162fe6b2b55964fbb0af2ee58e99791a3138588c482572bb6087953113a"}, 1247 | {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdf8d759ef326962b4678d89e275ffc55b7ce59d917d9f72233762061fd04a2d"}, 1248 | {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05a81b006be15655b2a1bae5faa4280cf7c81d0e09fcb49b342ebf826abe5a72"}, 1249 | {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d88c4c0e5c5dfd05092a4b271282ef0588e5f4aaf345778056fc5259ba098857"}, 1250 | {file = "pydantic-1.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:6a05a9db1ef5be0fe63e988f9617ca2551013f55000289c671f71ec16f4985e3"}, 1251 | {file = "pydantic-1.10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:887ca463c3bc47103c123bc06919c86720e80e1214aab79e9b779cda0ff92a00"}, 1252 | {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdf88ab63c3ee282c76d652fc86518aacb737ff35796023fae56a65ced1a5978"}, 1253 | {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a48f1953c4a1d9bd0b5167ac50da9a79f6072c63c4cef4cf2a3736994903583e"}, 1254 | {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a9f2de23bec87ff306aef658384b02aa7c32389766af3c5dee9ce33e80222dfa"}, 1255 | {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd8702c5142afda03dc2b1ee6bc358b62b3735b2cce53fc77b31ca9f728e4bc8"}, 1256 | {file = "pydantic-1.10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6e7124d6855b2780611d9f5e1e145e86667eaa3bd9459192c8dc1a097f5e9903"}, 1257 | {file = "pydantic-1.10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b53e1d41e97063d51a02821b80538053ee4608b9a181c1005441f1673c55423"}, 1258 | {file = "pydantic-1.10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:55b1625899acd33229c4352ce0ae54038529b412bd51c4915349b49ca575258f"}, 1259 | {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:301d626a59edbe5dfb48fcae245896379a450d04baeed50ef40d8199f2733b06"}, 1260 | {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6f9d649892a6f54a39ed56b8dfd5e08b5f3be5f893da430bed76975f3735d15"}, 1261 | {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d7b5a3821225f5c43496c324b0d6875fde910a1c2933d726a743ce328fbb2a8c"}, 1262 | {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f2f7eb6273dd12472d7f218e1fef6f7c7c2f00ac2e1ecde4db8824c457300416"}, 1263 | {file = "pydantic-1.10.4-cp38-cp38-win_amd64.whl", hash = "sha256:4b05697738e7d2040696b0a66d9f0a10bec0efa1883ca75ee9e55baf511909d6"}, 1264 | {file = "pydantic-1.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a9a6747cac06c2beb466064dda999a13176b23535e4c496c9d48e6406f92d42d"}, 1265 | {file = "pydantic-1.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb992a1ef739cc7b543576337bebfc62c0e6567434e522e97291b251a41dad7f"}, 1266 | {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:990406d226dea0e8f25f643b370224771878142155b879784ce89f633541a024"}, 1267 | {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e82a6d37a95e0b1b42b82ab340ada3963aea1317fd7f888bb6b9dfbf4fff57c"}, 1268 | {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9193d4f4ee8feca58bc56c8306bcb820f5c7905fd919e0750acdeeeef0615b28"}, 1269 | {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b3ce5f16deb45c472dde1a0ee05619298c864a20cded09c4edd820e1454129f"}, 1270 | {file = "pydantic-1.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:9cbdc268a62d9a98c56e2452d6c41c0263d64a2009aac69246486f01b4f594c4"}, 1271 | {file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"}, 1272 | {file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"}, 1273 | ] 1274 | pyflakes = [ 1275 | {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"}, 1276 | {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"}, 1277 | ] 1278 | pygments = [ 1279 | {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, 1280 | {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, 1281 | ] 1282 | pymdown-extensions = [ 1283 | {file = "pymdown_extensions-9.9-py3-none-any.whl", hash = "sha256:ac698c15265680db5eb13cd4342abfcde2079ac01e5486028f47a1b41547b859"}, 1284 | {file = "pymdown_extensions-9.9.tar.gz", hash = "sha256:0f8fb7b74a37a61cc34e90b2c91865458b713ec774894ffad64353a5fce85cfc"}, 1285 | ] 1286 | pytest = [ 1287 | {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, 1288 | {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, 1289 | ] 1290 | pytest-asyncio = [ 1291 | {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, 1292 | {file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"}, 1293 | ] 1294 | python-dateutil = [ 1295 | {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, 1296 | {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, 1297 | ] 1298 | pytz = [ 1299 | {file = "pytz-2022.7-py2.py3-none-any.whl", hash = "sha256:93007def75ae22f7cd991c84e02d434876818661f8df9ad5df9e950ff4e52cfd"}, 1300 | {file = "pytz-2022.7.tar.gz", hash = "sha256:7ccfae7b4b2c067464a6733c6261673fdb8fd1be905460396b97a073e9fa683a"}, 1301 | ] 1302 | pyyaml = [ 1303 | {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, 1304 | {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, 1305 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, 1306 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, 1307 | {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, 1308 | {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, 1309 | {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, 1310 | {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, 1311 | {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, 1312 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, 1313 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, 1314 | {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, 1315 | {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, 1316 | {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, 1317 | {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, 1318 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, 1319 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, 1320 | {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, 1321 | {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, 1322 | {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, 1323 | {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, 1324 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, 1325 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, 1326 | {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, 1327 | {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, 1328 | {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, 1329 | {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, 1330 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, 1331 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, 1332 | {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, 1333 | {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, 1334 | {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, 1335 | {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, 1336 | {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, 1337 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, 1338 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, 1339 | {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, 1340 | {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, 1341 | {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, 1342 | {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, 1343 | ] 1344 | pyyaml-env-tag = [ 1345 | {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, 1346 | {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, 1347 | ] 1348 | requests = [ 1349 | {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, 1350 | {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, 1351 | ] 1352 | rfc3986 = [ 1353 | {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, 1354 | {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, 1355 | ] 1356 | six = [ 1357 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 1358 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 1359 | ] 1360 | smmap = [ 1361 | {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, 1362 | {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, 1363 | ] 1364 | sniffio = [ 1365 | {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, 1366 | {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, 1367 | ] 1368 | soupsieve = [ 1369 | {file = "soupsieve-2.3.2.post1-py3-none-any.whl", hash = "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759"}, 1370 | {file = "soupsieve-2.3.2.post1.tar.gz", hash = "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d"}, 1371 | ] 1372 | starlette = [ 1373 | {file = "starlette-0.22.0-py3-none-any.whl", hash = "sha256:b5eda991ad5f0ee5d8ce4c4540202a573bb6691ecd0c712262d0bc85cf8f2c50"}, 1374 | {file = "starlette-0.22.0.tar.gz", hash = "sha256:b092cbc365bea34dd6840b42861bdabb2f507f8671e642e8272d2442e08ea4ff"}, 1375 | ] 1376 | toml = [ 1377 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1378 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1379 | ] 1380 | tomli = [ 1381 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 1382 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 1383 | ] 1384 | typing-extensions = [ 1385 | {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, 1386 | {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, 1387 | ] 1388 | urllib3 = [ 1389 | {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, 1390 | {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, 1391 | ] 1392 | uvicorn = [ 1393 | {file = "uvicorn-0.20.0-py3-none-any.whl", hash = "sha256:c3ed1598a5668208723f2bb49336f4509424ad198d6ab2615b7783db58d919fd"}, 1394 | {file = "uvicorn-0.20.0.tar.gz", hash = "sha256:a4e12017b940247f836bc90b72e725d7dfd0c8ed1c51eb365f5ba30d9f5127d8"}, 1395 | ] 1396 | watchdog = [ 1397 | {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a09483249d25cbdb4c268e020cb861c51baab2d1affd9a6affc68ffe6a231260"}, 1398 | {file = "watchdog-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5100eae58133355d3ca6c1083a33b81355c4f452afa474c2633bd2fbbba398b3"}, 1399 | {file = "watchdog-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e618a4863726bc7a3c64f95c218437f3349fb9d909eb9ea3a1ed3b567417c661"}, 1400 | {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:102a60093090fc3ff76c983367b19849b7cc24ec414a43c0333680106e62aae1"}, 1401 | {file = "watchdog-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:748ca797ff59962e83cc8e4b233f87113f3cf247c23e6be58b8a2885c7337aa3"}, 1402 | {file = "watchdog-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ccd8d84b9490a82b51b230740468116b8205822ea5fdc700a553d92661253a3"}, 1403 | {file = "watchdog-2.2.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6e01d699cd260d59b84da6bda019dce0a3353e3fcc774408ae767fe88ee096b7"}, 1404 | {file = "watchdog-2.2.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8586d98c494690482c963ffb24c49bf9c8c2fe0589cec4dc2f753b78d1ec301d"}, 1405 | {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:adaf2ece15f3afa33a6b45f76b333a7da9256e1360003032524d61bdb4c422ae"}, 1406 | {file = "watchdog-2.2.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83a7cead445008e880dbde833cb9e5cc7b9a0958edb697a96b936621975f15b9"}, 1407 | {file = "watchdog-2.2.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8ac23ff2c2df4471a61af6490f847633024e5aa120567e08d07af5718c9d092"}, 1408 | {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d0f29fd9f3f149a5277929de33b4f121a04cf84bb494634707cfa8ea8ae106a8"}, 1409 | {file = "watchdog-2.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:967636031fa4c4955f0f3f22da3c5c418aa65d50908d31b73b3b3ffd66d60640"}, 1410 | {file = "watchdog-2.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96cbeb494e6cbe3ae6aacc430e678ce4b4dd3ae5125035f72b6eb4e5e9eb4f4e"}, 1411 | {file = "watchdog-2.2.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:61fdb8e9c57baf625e27e1420e7ca17f7d2023929cd0065eb79c83da1dfbeacd"}, 1412 | {file = "watchdog-2.2.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb5ecc332112017fbdb19ede78d92e29a8165c46b68a0b8ccbd0a154f196d5e"}, 1413 | {file = "watchdog-2.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a480d122740debf0afac4ddd583c6c0bb519c24f817b42ed6f850e2f6f9d64a8"}, 1414 | {file = "watchdog-2.2.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:978a1aed55de0b807913b7482d09943b23a2d634040b112bdf31811a422f6344"}, 1415 | {file = "watchdog-2.2.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:8c28c23972ec9c524967895ccb1954bc6f6d4a557d36e681a36e84368660c4ce"}, 1416 | {file = "watchdog-2.2.1-py3-none-manylinux2014_i686.whl", hash = "sha256:c27d8c1535fd4474e40a4b5e01f4ba6720bac58e6751c667895cbc5c8a7af33c"}, 1417 | {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d6b87477752bd86ac5392ecb9eeed92b416898c30bd40c7e2dd03c3146105646"}, 1418 | {file = "watchdog-2.2.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cece1aa596027ff56369f0b50a9de209920e1df9ac6d02c7f9e5d8162eb4f02b"}, 1419 | {file = "watchdog-2.2.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:8b5cde14e5c72b2df5d074774bdff69e9b55da77e102a91f36ef26ca35f9819c"}, 1420 | {file = "watchdog-2.2.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e038be858425c4f621900b8ff1a3a1330d9edcfeaa1c0468aeb7e330fb87693e"}, 1421 | {file = "watchdog-2.2.1-py3-none-win32.whl", hash = "sha256:bc43c1b24d2f86b6e1cc15f68635a959388219426109233e606517ff7d0a5a73"}, 1422 | {file = "watchdog-2.2.1-py3-none-win_amd64.whl", hash = "sha256:17f1708f7410af92ddf591e94ae71a27a13974559e72f7e9fde3ec174b26ba2e"}, 1423 | {file = "watchdog-2.2.1-py3-none-win_ia64.whl", hash = "sha256:195ab1d9d611a4c1e5311cbf42273bc541e18ea8c32712f2fb703cfc6ff006f9"}, 1424 | {file = "watchdog-2.2.1.tar.gz", hash = "sha256:cdcc23c9528601a8a293eb4369cbd14f6b4f34f07ae8769421252e9c22718b6f"}, 1425 | ] 1426 | zipp = [ 1427 | {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, 1428 | {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, 1429 | ] 1430 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "pyCryptoPay-SDK" 3 | version = "1.7.1" 4 | description = "Python API wrapper for CryptoPay API" 5 | authors = ["Maxim Mosin "] 6 | license = "MIT" 7 | readme = "README.md" 8 | homepage = "https://github.com/LulzLoL231/pyCryptoPayAPI/" 9 | repository = "https://github.com/LulzLoL231/pyCryptoPayAPI" 10 | documentation = "https://lulzlol231.github.io/pyCryptoPayAPI" 11 | keywords= ["cryptopay", "crypto"] 12 | classifiers = [ 13 | "Topic :: Software Development :: Libraries :: Python Modules", 14 | "Operating System :: OS Independent", 15 | "Development Status :: 5 - Production/Stable", 16 | "Framework :: AsyncIO" 17 | ] 18 | packages = [ 19 | { include = "CryptoPayAPI", from = "src" } 20 | ] 21 | 22 | [tool.poetry.dependencies] 23 | python = "^3.8.1" 24 | httpx = "^0.23.1" 25 | pydantic = "^1.10.2" 26 | 27 | [tool.poetry.dev-dependencies] 28 | mypy = "^0.991" 29 | flake8 = "^6.0.0" 30 | autopep8 = "^2.0.1" 31 | pytest = "^7.2.0" 32 | pytest-asyncio = "^0.20.3" 33 | fastapi = "^0.88.0" 34 | uvicorn = "^0.20.0" 35 | bumpver = "^2022.1120" 36 | mkdocs-material = "^8.5.11" 37 | mkdocs-git-revision-date-localized-plugin = "^1.1.0" 38 | mkdocs-git-authors-plugin = "^0.7.0" 39 | mkdocs-git-committers-plugin-2 = { git = "https://github.com/LulzLoL231/mkdocs-git-committers-plugin-2.git", tag = "v1.1.2" } 40 | mkdocstrings = {extras = ["python"], version = "^0.19.1"} 41 | mkdocs-glightbox = "^0.3.1" 42 | mkdocs-literate-nav = "^0.5.0" 43 | mkdocs-section-index = "^0.3.4" 44 | mkdocs-static-i18n = { git = "https://github.com/LulzLoL231/mkdocs-static-i18n.git", tag = "v0.54" } 45 | lxml = "^4.9.2" 46 | 47 | [build-system] 48 | requires = ["poetry-core>=1.0.0"] 49 | build-backend = "poetry.core.masonry.api" 50 | 51 | [tool.bumpver] 52 | current_version = "1.7.1" 53 | version_pattern = "MAJOR.MINOR.PATCH" 54 | commit_message = "Bump version {old_version} -> {new_version}" 55 | commit = true 56 | tag = true 57 | push = false 58 | 59 | [tool.bumpver.file_patterns] 60 | "pyproject.toml" = [ 61 | 'current_version = "{version}"', 62 | 'version = "{version}"', 63 | ] 64 | "src/CryptoPayAPI/__init__.py" = [ 65 | "__version__ = '{version}'", 66 | ] 67 | 68 | -------------------------------------------------------------------------------- /src/CryptoPayAPI/__init__.py: -------------------------------------------------------------------------------- 1 | from .api import CryptoPay 2 | 3 | 4 | __version__ = '1.7.1' 5 | __doc__ = 'CryptoPay API client' 6 | __author__ = 'Maxim Mosin (@LulzLoL231) ' 7 | -------------------------------------------------------------------------------- /src/CryptoPayAPI/api.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # CryptoPayAPI - API. 4 | # Created by LulzLoL231 at 2/6/22 5 | # 6 | import logging 7 | import urllib.parse 8 | from json import loads 9 | from typing import Dict, Optional, Union, List 10 | 11 | from httpx import AsyncClient, Timeout 12 | 13 | from . import schemas 14 | from .errors import ( 15 | UnauthorizedError, MethodNotFoundError, UnexpectedError, 16 | ExpiresInInvalidError, UpdateSignatureError, MethodDisabledError 17 | ) 18 | 19 | 20 | MAINHOST = 'https://pay.crypt.bot/api' 21 | TESTHOST = 'https://testnet-pay.crypt.bot/api' 22 | 23 | 24 | class CryptoPay: 25 | '''CryptoPay payment system. 26 | ''' 27 | def __init__( 28 | self, api_key: str, testnet: bool = False, 29 | client: Optional[AsyncClient] = None 30 | ) -> None: 31 | ''' 32 | Args: 33 | api_key (str): CryptoPay API token. 34 | testnet (bool): Use Testnet? Defaults to False. 35 | client (AsyncClient, optional): Using custom AsyncClient. Defaults is None. 36 | ''' 37 | self.timeout_sec = 5 38 | self.log = logging.getLogger('CryptoPay') 39 | self.api_key = api_key 40 | self.headers = { 41 | 'Crypto-Pay-API-Token': api_key 42 | } 43 | self.testnet = testnet 44 | if testnet: 45 | self.endpoint = TESTHOST 46 | else: 47 | self.endpoint = MAINHOST 48 | self.client = client or AsyncClient( 49 | headers=self.headers, base_url=self.endpoint, 50 | timeout=Timeout(self.timeout_sec) 51 | ) 52 | 53 | async def _callApi(self, http_method: str, api_method: str, query: dict = {}) -> dict: 54 | '''Makes a api call. 55 | 56 | Args: 57 | http_method (str): HTTP method. Available is "GET" and "POST". 58 | api_method (str): API method. 59 | query (dict, optional): Request query in dict. Defaults to {}. 60 | 61 | Returns: 62 | dict: API response as JSON dict viceversa None. 63 | ''' 64 | self.log.debug(f'Called with args ({http_method}, {api_method}, {query})') 65 | if query: 66 | params = urllib.parse.urlencode(query) 67 | else: 68 | params = None 69 | resp = await self.client.request(http_method, api_method, params=params) 70 | if resp.is_success: 71 | data = resp.json() 72 | self.log.debug(f'API answer: {data}') 73 | if data['ok']: 74 | return data['result'] 75 | else: 76 | raise UnexpectedError( 77 | f'[{data["error"]["code"]}] {data["error"]["name"]}', 78 | data 79 | ) 80 | else: 81 | if resp.status_code == 401: 82 | raise UnauthorizedError('Token not found!') 83 | elif resp.status_code == 405: 84 | raise MethodNotFoundError( 85 | f'Method {api_method} not found!' 86 | ) 87 | elif resp.status_code == 400: 88 | data = resp.json() 89 | err = data['error']['name'] 90 | if err == 'EXPIRES_IN_INVALID': 91 | raise ExpiresInInvalidError( 92 | f'Expires "{query["expires_in"]}" is invalid!', 93 | raw_response=data 94 | ) 95 | elif resp.status_code == 403: 96 | data = resp.json() 97 | err = data['error']['name'] 98 | if err == 'METHOD_DISABLED': 99 | raise MethodDisabledError( 100 | f'Method "{api_method}" is disabled!', 101 | raw_response=data 102 | ) 103 | data = resp.json() 104 | raise UnexpectedError( 105 | f'[{data["error"]["code"]}] {data["error"]["name"]}', 106 | raw_response=data 107 | ) 108 | 109 | async def get_me(self) -> schemas.Application: 110 | '''Returns basic information about an app. 111 | 112 | Returns: 113 | schemas.Application: Basic information about an app. 114 | ''' 115 | self.log.debug('Called!') 116 | result = await self._callApi('GET', 'getMe') 117 | return schemas.Application(**result) 118 | 119 | async def get_balance(self) -> List[schemas.Balance]: 120 | '''Use this method to get a balance of your app. 121 | 122 | Returns: 123 | List[schemas.Balance]: Array of assets. 124 | ''' 125 | self.log.debug('Called!') 126 | result = await self._callApi('GET', 'getBalance') 127 | return [schemas.Balance(**i) for i in result] 128 | 129 | async def get_exchange_rates(self) -> List[schemas.ExchangeRate]: 130 | '''Use this method to get exchange rates of supported currencies. 131 | 132 | Returns: 133 | List[schemas.ExchangeRate]: Array of currencies. 134 | ''' 135 | self.log.debug('Called!') 136 | result = await self._callApi('GET', 'getExchangeRates') 137 | return [schemas.ExchangeRate(**i) for i in result] 138 | 139 | async def get_currencies(self) -> List[schemas.Currency]: 140 | '''Use this method to get a list of supported currencies. 141 | 142 | Returns: 143 | List[schemas.Currency]: Array of currencies. 144 | ''' 145 | self.log.debug('Called!') 146 | result = await self._callApi('GET', 'getCurrencies') 147 | return [schemas.Currency(**i) for i in result] 148 | 149 | async def create_invoice(self, 150 | asset: schemas.Assets, 151 | amount: float, 152 | description: Optional[str] = None, 153 | hidden_message: Optional[str] = None, 154 | paid_btn_name: Optional[schemas.PaidButtonNames] = None, 155 | paid_btn_url: Optional[str] = None, 156 | payload: Optional[str] = None, 157 | allow_comments: bool = True, 158 | allow_anonymous: bool = True, 159 | expires_in: Optional[int] = None) -> schemas.Invoice: 160 | '''Create a new invoice. 161 | 162 | Args: 163 | asset (schemas.Assets): Currency. 164 | amount (float): Amount of invoice in float. 165 | description (Optional[str]): Description for the invoice. User will see this description when they pay the invoice. Up to 1024 characters. Defaults to None. 166 | hidden_message (Optional[str]): Text of the message that will be shown to a user after the invoice is paid. Up to 2048 characters. Defaults to None. 167 | paid_btn_name (Optional[schemas.PaidButtonNames]): Name of the button that will be shown to a user after the invoice is paid. Defaults to None. 168 | paid_btn_url (Optional[str]): Required if paid_btn_name is used. URL to be opened when the button is pressed. You can set any success link (for example, a link to your bot). Starts with https or http. Defaults to None. 169 | payload (Optional[str]): Any data you want to attach to the invoice (for example, user ID, payment ID, ect). Up to 4kb. Defaults to None. 170 | allow_comments (bool): Allow a user to add a comment to the payment. Defaults to True. 171 | allow_anonymous (bool): Allow a user to pay the invoice anonymously. Defaults to True. 172 | expires_in (Optional[int]): You can set a payment time limit for the invoice in seconds. Values between 1-2678400 are accepted. Defaults to None. 173 | 174 | Returns: 175 | schemas.Invoice: Object of the created invoice. 176 | ''' 177 | self.log.debug(f'Called with args ({asset}, {amount}, {description}, {hidden_message}, {paid_btn_name}, {paid_btn_url}, {payload}, {allow_comments}, {allow_anonymous}, {expires_in})') 178 | params = { 179 | 'asset': str(asset), 180 | 'amount': amount, 181 | 'allow_comments': allow_comments, 182 | 'allow_anonymous': allow_anonymous 183 | } 184 | if description: 185 | params['description'] = description 186 | elif hidden_message: 187 | params['hidden_message'] = hidden_message 188 | elif paid_btn_name: 189 | params['paid_btn_name'] = str(paid_btn_name) 190 | params['paid_btn_url'] = paid_btn_url 191 | elif payload: 192 | params['payload'] = payload 193 | elif expires_in: 194 | params['expires_in'] = expires_in 195 | result = await self._callApi('POST', 'createInvoice', params) 196 | return schemas.Invoice(**result) 197 | 198 | async def get_invoices(self, 199 | asset: Optional[schemas.Assets] = None, 200 | invoice_ids: Optional[str] = None, 201 | status: Optional[schemas.InvoiceStatus] = None, 202 | offset: int = 0, 203 | count: int = 100) -> List[schemas.Invoice]: 204 | '''Use this method to get invoices of your app. 205 | 206 | Args: 207 | asset (Optional[schemas.Assets]): Currency codes separated by comma. Defaults to all assets. 208 | invoice_ids (Optional[str]): Invoice IDs separated by comma. Defaults to None. 209 | status (Optional[schemas.InvoiceStatus]): Status of invoices to be returned. Defaults to all statuses. 210 | offset (int): Offset needed to return a specific subset of invoices. Defaults to 0. 211 | count (int): Number of invoices to be returned. Values between 1-1000 are accepted. Defaults to 100. 212 | 213 | Returns: 214 | List[schemas.Invoice]: Array of invoices. 215 | ''' 216 | self.log.debug(f'Called with args ({asset}, {invoice_ids}, {status}, {offset}, {count})') 217 | params: Dict[str, Union[str, int]] = { 218 | 'offset': offset, 219 | 'count': count 220 | } 221 | if asset: 222 | params['asset'] = str(asset) 223 | elif invoice_ids: 224 | params['invoice_ids'] = invoice_ids 225 | elif status: 226 | params['status'] = str(status) 227 | result = await self._callApi('GET', 'getInvoices', params) 228 | return [schemas.Invoice(**i) for i in result['items']] 229 | 230 | async def transfer(self, 231 | user_id: int, 232 | asset: schemas.Assets, 233 | amount: float, 234 | spend_id: str, 235 | comment: Optional[str] = None, 236 | disable_send_notification: Optional[bool] = False) -> schemas.Transfer: 237 | '''Use this method to send coins from your app's balance to a user. 238 | 239 | Args: 240 | user_id (int): Telegram user_id. 241 | asset (schemas.Assets): Currency. 242 | amount (float): Amount of the transfer in float. The minimum and maximum amounts for each of the support asset roughly correspond to the limit of 0.01-25000 USD. Use `get_exchange_rates` to convert amounts. 243 | spend_id (str): Unique ID to make your request idempotent and ensure that only one of the transfers with the same `spend_id` will be accepted by Crypto Pay API. This parameter is useful when the transfer should be retried (i.e. request timeout, connection reset, 500 HTTP status, etc). It can be some unique withdrawal identifier for example. Up to 64 symbols. 244 | comment (Optional[str], optional): Comment for the transfer. Users will see this comment when they receive a notification about the transfer. Up to 1024 symbols. Defaults to None. 245 | disable_send_notification (Optional[bool], optional): Pass `True` if the user should not receive a notification about the transfer. Defaults to False. 246 | 247 | Returns: 248 | schemas.Transfer: Object of completed `transfer`. 249 | ''' 250 | self.log.debug(f'Called with args ({user_id}, {asset}, {amount}, {spend_id}, {comment}, {disable_send_notification})') 251 | params = { 252 | 'user_id': user_id, 253 | 'asset': str(asset), 254 | 'amount': amount, 255 | 'spend_id': spend_id 256 | } 257 | if comment: 258 | params['comment'] = comment 259 | elif disable_send_notification: 260 | params['disable_send_notification'] = 'true' 261 | result = await self._callApi('POST', 'transfer', params) 262 | return schemas.Transfer(**result) 263 | 264 | async def process_webhook_update(self, 265 | body: bytes, 266 | headers: dict) -> schemas.Update: 267 | '''Process webhook update. 268 | 269 | Args: 270 | body (bytes): Update request body. 271 | headers (dict): Update request headers. 272 | 273 | Returns: 274 | schemas.Update: Webhook update. 275 | ''' 276 | self.log.debug(f'Called with args: ({body}, {headers})') # type: ignore 277 | update = schemas.Update(**loads(body), raw_body=body) 278 | sign = headers.get('crypto-pay-api-signature', '') 279 | if not sign: 280 | raise UpdateSignatureError( 281 | 'Not found signature!', 282 | raw_response=update.dict(), 283 | raw_headers=headers 284 | ) 285 | if not update.check_signature(self.api_key, sign): 286 | raise UpdateSignatureError( 287 | 'Signature validation error!', 288 | raw_response=update.dict(), 289 | raw_headers=headers 290 | ) 291 | return update 292 | -------------------------------------------------------------------------------- /src/CryptoPayAPI/errors.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # CryptoPayAPI - API errors. 4 | # Created by LulzLoL231 at 2/6/22 5 | # 6 | from typing import Optional 7 | 8 | 9 | class BaseError(Exception): 10 | '''Base error class 11 | 12 | Attributes: 13 | raw_response (dict, optional): RAW response from CryptoPay API. 14 | raw_headers (dict, optional): RAW headers from CryptoPay API response. 15 | ''' 16 | def __init__(self, 17 | *args: object, 18 | raw_response: Optional[dict] = None, 19 | raw_headers: Optional[dict] = None) -> None: 20 | super().__init__(*args) 21 | self.raw_response = raw_response 22 | self.raw_headers = raw_headers 23 | 24 | 25 | class UnauthorizedError(BaseError): 26 | '''Authorization on CryptoPay API is failed, maybe incorect/expired API token. 27 | ''' 28 | pass 29 | 30 | 31 | class MethodNotFoundError(BaseError): 32 | '''Requested method is not found. 33 | ''' 34 | pass 35 | 36 | 37 | class UnexpectedError(BaseError): 38 | '''Unexpected API error. 39 | ''' 40 | pass 41 | 42 | 43 | class ExpiresInInvalidError(BaseError): 44 | '''Value of `expires_in` is invalid. 45 | ''' 46 | pass 47 | 48 | 49 | class UpdateSignatureError(BaseError): 50 | '''Webhook signature validation error. 51 | ''' 52 | pass 53 | 54 | 55 | class MethodDisabledError(BaseError): 56 | '''Requested method is disabled. Check bot settings. 57 | ''' 58 | pass 59 | -------------------------------------------------------------------------------- /src/CryptoPayAPI/schemas.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # CryptoPayAPI - schemas. 4 | # Created by LulzLoL231 at 2/6/22 5 | # 6 | import logging 7 | from enum import Enum 8 | from hmac import HMAC 9 | from hashlib import sha256 10 | from decimal import Decimal 11 | from datetime import datetime 12 | from typing import Literal, Optional 13 | 14 | from pydantic import BaseModel 15 | 16 | 17 | log = logging.getLogger('CryptoPay') 18 | 19 | 20 | class Assets(Enum): 21 | '''Currency code. 22 | 23 | Attributes: 24 | BTC (str): Bitcoin 25 | TON (str): Toncoin 26 | ETH (str): Ethereum 27 | USDT (str): Tether 28 | USDC (str): USD Coin 29 | BUSD (str): Binance USD 30 | ''' 31 | BTC = 'BTC' 32 | TON = 'TON' 33 | ETH = 'ETH' 34 | USDT = 'USDT' 35 | USDC = 'USDC' 36 | BUSD = 'BUSD' 37 | 38 | def __str__(self) -> str: 39 | return self.value 40 | 41 | 42 | class PaidButtonNames(Enum): 43 | '''Name of the button. 44 | 45 | Attributes: 46 | VIEW_ITEM (str): 'viewItem' 47 | OPEN_CHANNEL (str): 'openChannel' 48 | OPEN_BOT (str): 'openBot' 49 | CALLBACK (str): 'callback' 50 | ''' 51 | VIEW_ITEM = 'viewItem' 52 | OPEN_CHANNEL = 'openChannel' 53 | OPEN_BOT = 'openBot' 54 | CALLBACK = 'callback' 55 | 56 | def __str__(self) -> str: 57 | return self.value 58 | 59 | 60 | class InvoiceStatus(Enum): 61 | '''Status of invoice. 62 | 63 | Attributes: 64 | ACTIVE (str): 'active' 65 | PAID (str): 'paid' 66 | EXPIRED (str): 'expired' 67 | ''' 68 | ACTIVE = 'active' 69 | PAID = 'paid' 70 | EXPIRED = 'expired' 71 | 72 | def __str__(self) -> str: 73 | return self.value 74 | 75 | 76 | class UpdateType(Enum): 77 | '''Webhook update type. 78 | 79 | Attributes: 80 | INVOICE_PAID (str): 'invoice_paid 81 | ''' 82 | INVOICE_PAID = 'invoice_paid' 83 | 84 | 85 | class Invoice(BaseModel): 86 | '''Invoice info. 87 | 88 | Attributes: 89 | invoice_id (int): Unique ID for this invoice. 90 | status (InvoiceStatus): Status of the invoice. 91 | hash (str): Hash of the invoice. 92 | asset (Assets): Currency code. 93 | amount (Decimal): Amount of the invoice. 94 | pay_url (str): URL should be presented to the user to pay the invoice. 95 | description (Optional[str]): *Optional*. Description for this invoice. 96 | created_at (datetime): Date the invoice was created in ISO 8601 format. 97 | allow_comments (bool): `True`, if the user can add comment to the payment. 98 | allow_anonymous (bool): `True`, if the user can pay the invoice anonymously. 99 | expiration_date (Optional[datetime]): *Optional*. Date the invoice expires in Unix time. 100 | paid_at (Optional[datetime]): *Optional*. Date the invoice was paid in Unix time. 101 | paid_anonymously (Optional[bool]): `True`, if the invoice was paid anonymously. 102 | comment (Optional[str]): *Optional*. Comment to the payment from the user. 103 | hidden_message (Optional[str]): *Optional*. Text of the hidden message for this invoice. 104 | payload (Optional[str]): *Optional*. Previously provided data for this invoice. 105 | paid_btn_name (Optional[PaidButtonNames]): *Optional*. Name of the button. 106 | paid_btn_url (Optional[str]): *Optional*. URL of the button. 107 | fee (Optional[Decimal]): *Optional*. Amount of charged service fees. Returned only if the invoice has paid status. 108 | usd_rate (Optional[Decimal]): *Optional*. Price of the asset in USD. Returned only if the invoice has paid status. 109 | ''' 110 | invoice_id: int 111 | status: InvoiceStatus 112 | hash: str 113 | asset: Assets 114 | amount: Decimal 115 | pay_url: str 116 | description: Optional[str] 117 | created_at: datetime 118 | allow_comments: bool 119 | allow_anonymous: bool 120 | expiration_date: Optional[datetime] 121 | paid_at: Optional[datetime] 122 | paid_anonymously: Optional[bool] 123 | comment: Optional[str] 124 | hidden_message: Optional[str] 125 | payload: Optional[str] 126 | paid_btn_name: Optional[PaidButtonNames] 127 | paid_btn_url: Optional[str] 128 | fee: Optional[Decimal] 129 | usd_rate: Optional[Decimal] 130 | 131 | 132 | class Transfer(BaseModel): 133 | '''Transfer info. 134 | 135 | Attributes: 136 | transfer_id (int): Unique ID for this transfer. 137 | user_id (int): Telegram user ID the transfer was sent to. 138 | asset (Assets): Currency code. 139 | amount (Decimal): Amount of the transfer. 140 | status (Literal['completed']): Status of the transfer, can be “completed”. 141 | completed_at (datetime): Date the transfer was completed in ISO 8601 format. 142 | comment (Optional[str]): *Optional*. Comment for this transfer. 143 | ''' 144 | transfer_id: int 145 | user_id: int 146 | asset: Assets 147 | amount: Decimal 148 | status: Literal['completed'] 149 | completed_at: datetime 150 | comment: Optional[str] 151 | 152 | 153 | class Application(BaseModel): 154 | '''Application info. 155 | 156 | Attributes: 157 | app_id (int): Application unique ID. 158 | name (str): Application name. 159 | payment_processing_bot_username (str): Username of Crypto bot. 160 | ''' 161 | app_id: int 162 | name: str 163 | payment_processing_bot_username: str 164 | 165 | 166 | class Balance(BaseModel): 167 | '''Balance info. 168 | 169 | Attributes: 170 | currency_code (str): Currency code. 171 | available (Decimal): Available for using. 172 | ''' 173 | currency_code: str 174 | available: Decimal 175 | 176 | 177 | class ExchangeRate(BaseModel): 178 | '''Exchange rate info. 179 | 180 | Attributes: 181 | is_valid (bool): Is valid? 182 | source (str): Source asset. 183 | target (str): Target asset. 184 | rate (Decimal): Exchange rate. 185 | ''' 186 | is_valid: bool 187 | source: str 188 | target: str 189 | rate: Decimal 190 | 191 | 192 | class Currency(BaseModel): 193 | '''Currency info. 194 | 195 | Attributes: 196 | is_blockchain (bool): Is blockchain asset? 197 | is_stablecoin (bool): Is stable coin? 198 | is_fiat (bool): Is fiat asset? 199 | name (str): Name of currency. 200 | code (str): Code of currency. 201 | url (Optional[str]): *Optional*. URL of currency site. 202 | decimals (int): ? 203 | ''' 204 | is_blockchain: bool 205 | is_stablecoin: bool 206 | is_fiat: bool 207 | name: str 208 | code: str 209 | url: Optional[str] 210 | decimals: int 211 | 212 | 213 | class Update(BaseModel): 214 | '''Webhook update object. 215 | 216 | Attributes: 217 | update_id (int): Non-unique update ID. 218 | update_type (UpdateType): Webhook update type. 219 | request_date (datetime): Date the request was sent in ISO 8601 format. 220 | payload (Invoice): Payload contains `Invoice` object. 221 | raw_body (Optional[bytes]): *Optional*. Raw body of update, for check sign purpose. 222 | ''' 223 | update_id: int 224 | update_type: UpdateType 225 | request_date: datetime 226 | payload: Invoice 227 | raw_body: Optional[bytes] = None 228 | 229 | def check_signature(self, api_key: str, sign: str) -> bool: 230 | '''Check update signature. 231 | 232 | Args: 233 | api_key (str): CryptoPay app API key. 234 | sign (str): Update signature. In request headers `crypto-pay-api-signature`. 235 | 236 | Returns: 237 | bool: Is signature verified? 238 | ''' 239 | log.debug(f'Called with args: ({api_key}, {sign})') 240 | secret = sha256(api_key.encode()).digest() 241 | hmac = HMAC(secret, self.raw_body, digestmod=sha256) 242 | body_sign = hmac.hexdigest() 243 | log.debug(f'Calculated hash: {body_sign}') 244 | return body_sign == sign 245 | -------------------------------------------------------------------------------- /src/CryptoPayAPI/types.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # For backward compatibility 3 | import warnings 4 | 5 | from .schemas import * 6 | 7 | 8 | warnings.warn( 9 | '"CryptoPayAPI.types" name is deprecated, use "CryptoPayAPI.schemas" instead!', 10 | DeprecationWarning, stacklevel=2 11 | ) 12 | -------------------------------------------------------------------------------- /tests/test_main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # pyCryptoPayAPI - Test testnet connection. 4 | # Created by LulzLoL231 at 12/9/22 5 | # 6 | from os import environ 7 | 8 | import pytest 9 | 10 | from CryptoPayAPI import CryptoPay 11 | 12 | 13 | TOKEN = environ.get('API_TOKEN', '') 14 | APP_NAME = environ.get('APP_NAME', '') 15 | APP_ID = int(environ.get('APP_ID', 0)) 16 | if not TOKEN: 17 | print('Use shell argument "API_TOKEN" for your Crypto Pay API token!') 18 | exit(1) 19 | if not APP_NAME: 20 | print('Use shell argument "APP_NAME" for your Crypto Pay app name!') 21 | exit(1) 22 | if not APP_ID: 23 | print('Use shell argument "APP_ID" for your Crypto Pay app id!') 24 | exit(1) 25 | 26 | 27 | @pytest.mark.asyncio 28 | async def test_testnetconnect(): 29 | cp = CryptoPay(TOKEN, testnet=True) 30 | 31 | app = await cp.get_me() 32 | 33 | assert app.app_id == APP_ID 34 | assert app.name == APP_NAME 35 | 36 | await cp.client.aclose() 37 | --------------------------------------------------------------------------------