├── .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 | 
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 | [](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml)
9 | 
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 | { loading=lazy }
14 | { loading=lazy }
15 |
16 | from test bot [@CryptoTestnetBot](https://t.me/CryptoTestnetBot):
17 | { loading=lazy }
18 | { 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 | { loading=lazy }
23 | { 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 | { loading=lazy }
28 | { 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 | { loading=lazy }
33 | { loading=lazy }
34 | { loading=lazy }
35 | { 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 | { loading=lazy }
14 | { loading=lazy }
15 |
16 | Для тестового бота [@CryptoTestnetBot](https://t.me/CryptoTestnetBot):
17 | { loading=lazy }
18 | { loading=lazy }
19 |
20 | ## Вход в бота
21 | Используйте команду `/start` в боте для выхода в главное меню и нажмите кнопку 🏝️ Crypto Pay
22 | { loading=lazy }
23 | { loading=lazy }
24 |
25 | ## Создание приложения
26 | Нажмите кнопку Создать приложение
, CryptoBot автоматически создаст вам приложение с уникальным именем.
27 | { loading=lazy }
28 | { loading=lazy }
29 |
30 | ## Получение API токена
31 | Нажмите кнопку "API-токен" чтобы увидеть свой API токен, состоит он из идентификатора приложения и уникальной строки в формате `000000:XXXXXXXXXXXXXXXXXXXXXXXXX`
32 | { loading=lazy }
33 | { loading=lazy }
34 | { loading=lazy }
35 | { 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 | 
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 | [](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml)
9 | 
10 |
11 | Documentation available on [English language](./en/)
12 | Документация доступна на [Русском языке](./ru/)
--------------------------------------------------------------------------------
/docs/index.ru.md:
--------------------------------------------------------------------------------
1 | # Главная
2 | 
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 | [](https://github.com/LulzLoL231/pyCryptoPayAPI/releases/latest) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/codeql-analysis.yml) [](https://github.com/LulzLoL231/pyCryptoPayAPI/actions/workflows/lib-test.yml)
9 | 
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 |
--------------------------------------------------------------------------------