├── .dockerignore
├── .github
└── workflows
│ └── tests.yml
├── .gitignore
├── .idea
├── .gitignore
├── apyr.iml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── pylint.xml
├── vcs.xml
└── webResources.xml
├── .pydocstyle
├── .pylintrc
├── Dockerfile
├── LICENSE
├── README.md
├── apyr
├── __init__.py
├── dependencies.py
├── exceptions.py
├── function_handler.py
├── functions.py
├── main.py
├── models.py
├── routers
│ ├── apyr_endpoints.py
│ └── endpoints.py
└── utils.py
├── assets
└── help.html
├── docker-compose.yaml
├── endpoints.yaml
├── poetry.lock
├── poetry.toml
├── pyproject.toml
└── tests
├── __init__.py
├── data
├── string1.txt
└── string2.txt
├── integration
├── __init__.py
├── conftest.py
└── test_endpoints.py
└── unit
├── __init__.py
├── test_functions.py
├── test_utils.py
└── test_validators.py
/.dockerignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | *.pyc
3 | *.pyo
4 | *.pyd
5 | .Python
6 | env
7 | pip-log.txt
8 | pip-delete-this-directory.txt
9 | .tox
10 | .coverage
11 | .coverage.*
12 | .cache
13 | nosetests.xml
14 | coverage.xml
15 | *,cover
16 | *.log
17 | .git
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: tests
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 | jobs:
9 | test:
10 | runs-on: ubuntu-latest
11 | steps:
12 | #----------------------------------------------
13 | # check-out repo and set-up python
14 | #----------------------------------------------
15 | - name: Check out repository
16 | uses: actions/checkout@v2
17 | - name: Set up python
18 | uses: actions/setup-python@v2
19 | with:
20 | python-version: 3.7
21 | #----------------------------------------------
22 | # ----- install & configure poetry -----
23 | #----------------------------------------------
24 | - name: Install Poetry
25 | uses: snok/install-poetry@v1.1.1
26 | with:
27 | virtualenvs-create: true
28 | virtualenvs-in-project: true
29 | #----------------------------------------------
30 | # load cached venv if cache exists
31 | #----------------------------------------------
32 | - name: Load cached venv
33 | id: cached-poetry-dependencies
34 | uses: actions/cache@v2
35 | with:
36 | path: .venv
37 | key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
38 | #----------------------------------------------
39 | # install dependencies if cache does not exist
40 | #----------------------------------------------
41 | - name: Install dependencies
42 | if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
43 | run: poetry install --no-interaction --no-root
44 | #----------------------------------------------
45 | # install your root project, if required
46 | #----------------------------------------------
47 | - name: Install library
48 | run: poetry install --no-interaction
49 | #----------------------------------------------
50 | # run test suite
51 | #----------------------------------------------
52 | - name: Run tests
53 | run: |
54 | source .venv/bin/activate
55 | pytest tests/
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.toptal.com/developers/gitignore/api/pycharm,vscode,python,macos
3 | # Edit at https://www.toptal.com/developers/gitignore?templates=pycharm,vscode,python,macos
4 |
5 | ### macOS ###
6 | # General
7 | .DS_Store
8 | .AppleDouble
9 | .LSOverride
10 |
11 | # Icon must end with two \r
12 | Icon
13 |
14 |
15 | # Thumbnails
16 | ._*
17 |
18 | # Files that might appear in the root of a volume
19 | .DocumentRevisions-V100
20 | .fseventsd
21 | .Spotlight-V100
22 | .TemporaryItems
23 | .Trashes
24 | .VolumeIcon.icns
25 | .com.apple.timemachine.donotpresent
26 |
27 | # Directories potentially created on remote AFP share
28 | .AppleDB
29 | .AppleDesktop
30 | Network Trash Folder
31 | Temporary Items
32 | .apdisk
33 |
34 | ### PyCharm ###
35 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
36 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
37 |
38 | # User-specific stuff
39 | .idea/**/workspace.xml
40 | .idea/**/tasks.xml
41 | .idea/**/usage.statistics.xml
42 | .idea/**/dictionaries
43 | .idea/**/shelf
44 |
45 | # Generated files
46 | .idea/**/contentModel.xml
47 |
48 | # Sensitive or high-churn files
49 | .idea/**/dataSources/
50 | .idea/**/dataSources.ids
51 | .idea/**/dataSources.local.xml
52 | .idea/**/sqlDataSources.xml
53 | .idea/**/dynamic.xml
54 | .idea/**/uiDesigner.xml
55 | .idea/**/dbnavigator.xml
56 |
57 | # Gradle
58 | .idea/**/gradle.xml
59 | .idea/**/libraries
60 |
61 | # Gradle and Maven with auto-import
62 | # When using Gradle or Maven with auto-import, you should exclude module files,
63 | # since they will be recreated, and may cause churn. Uncomment if using
64 | # auto-import.
65 | # .idea/artifacts
66 | # .idea/compiler.xml
67 | # .idea/jarRepositories.xml
68 | # .idea/modules.xml
69 | # .idea/*.iml
70 | # .idea/modules
71 | # *.iml
72 | # *.ipr
73 |
74 | # CMake
75 | cmake-build-*/
76 |
77 | # Mongo Explorer plugin
78 | .idea/**/mongoSettings.xml
79 |
80 | # File-based project format
81 | *.iws
82 |
83 | # IntelliJ
84 | out/
85 |
86 | # mpeltonen/sbt-idea plugin
87 | .idea_modules/
88 |
89 | # JIRA plugin
90 | atlassian-ide-plugin.xml
91 |
92 | # Cursive Clojure plugin
93 | .idea/replstate.xml
94 |
95 | # Crashlytics plugin (for Android Studio and IntelliJ)
96 | com_crashlytics_export_strings.xml
97 | crashlytics.properties
98 | crashlytics-build.properties
99 | fabric.properties
100 |
101 | # Editor-based Rest Client
102 | .idea/httpRequests
103 |
104 | # Android studio 3.1+ serialized cache file
105 | .idea/caches/build_file_checksums.ser
106 |
107 | ### PyCharm Patch ###
108 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
109 |
110 | # *.iml
111 | # modules.xml
112 | # .idea/misc.xml
113 | # *.ipr
114 |
115 | # Sonarlint plugin
116 | # https://plugins.jetbrains.com/plugin/7973-sonarlint
117 | .idea/**/sonarlint/
118 |
119 | # SonarQube Plugin
120 | # https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
121 | .idea/**/sonarIssues.xml
122 |
123 | # Markdown Navigator plugin
124 | # https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
125 | .idea/**/markdown-navigator.xml
126 | .idea/**/markdown-navigator-enh.xml
127 | .idea/**/markdown-navigator/
128 |
129 | # Cache file creation bug
130 | # See https://youtrack.jetbrains.com/issue/JBR-2257
131 | .idea/$CACHE_FILE$
132 |
133 | # CodeStream plugin
134 | # https://plugins.jetbrains.com/plugin/12206-codestream
135 | .idea/codestream.xml
136 |
137 | ### Python ###
138 | # Byte-compiled / optimized / DLL files
139 | __pycache__/
140 | *.py[cod]
141 | *$py.class
142 |
143 | # C extensions
144 | *.so
145 |
146 | # Distribution / packaging
147 | .Python
148 | build/
149 | develop-eggs/
150 | dist/
151 | downloads/
152 | eggs/
153 | .eggs/
154 | lib/
155 | lib64/
156 | parts/
157 | sdist/
158 | var/
159 | wheels/
160 | pip-wheel-metadata/
161 | share/python-wheels/
162 | *.egg-info/
163 | .installed.cfg
164 | *.egg
165 | MANIFEST
166 |
167 | # PyInstaller
168 | # Usually these files are written by a python script from a template
169 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
170 | *.manifest
171 | *.spec
172 |
173 | # Installer logs
174 | pip-log.txt
175 | pip-delete-this-directory.txt
176 |
177 | # Unit test / coverage reports
178 | htmlcov/
179 | .tox/
180 | .nox/
181 | .coverage
182 | .coverage.*
183 | .cache
184 | nosetests.xml
185 | coverage.xml
186 | *.cover
187 | *.py,cover
188 | .hypothesis/
189 | .pytest_cache/
190 | pytestdebug.log
191 |
192 | # Translations
193 | *.mo
194 | *.pot
195 |
196 | # Django stuff:
197 | *.log
198 | local_settings.py
199 | db.sqlite3
200 | db.sqlite3-journal
201 |
202 | # Flask stuff:
203 | instance/
204 | .webassets-cache
205 |
206 | # Scrapy stuff:
207 | .scrapy
208 |
209 | # Sphinx documentation
210 | docs/_build/
211 | doc/_build/
212 |
213 | # PyBuilder
214 | target/
215 |
216 | # Jupyter Notebook
217 | .ipynb_checkpoints
218 |
219 | # IPython
220 | profile_default/
221 | ipython_config.py
222 |
223 | # pyenv
224 | .python-version
225 |
226 | # pipenv
227 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
228 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
229 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
230 | # install all needed dependencies.
231 | #Pipfile.lock
232 |
233 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
234 | __pypackages__/
235 |
236 | # Celery stuff
237 | celerybeat-schedule
238 | celerybeat.pid
239 |
240 | # SageMath parsed files
241 | *.sage.py
242 |
243 | # Environments
244 | .env
245 | .venv
246 | env/
247 | venv/
248 | ENV/
249 | env.bak/
250 | venv.bak/
251 | pythonenv*
252 |
253 | # Spyder project settings
254 | .spyderproject
255 | .spyproject
256 |
257 | # Rope project settings
258 | .ropeproject
259 |
260 | # mkdocs documentation
261 | /site
262 |
263 | # mypy
264 | .mypy_cache/
265 | .dmypy.json
266 | dmypy.json
267 |
268 | # Pyre type checker
269 | .pyre/
270 |
271 | # pytype static type analyzer
272 | .pytype/
273 |
274 | # profiling data
275 | .prof
276 |
277 | ### vscode ###
278 | .vscode/*
279 | !.vscode/settings.json
280 | !.vscode/tasks.json
281 | !.vscode/launch.json
282 | !.vscode/extensions.json
283 | *.code-workspace
284 |
285 | # End of https://www.toptal.com/developers/gitignore/api/pycharm,vscode,python,macos
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/.idea/apyr.iml:
--------------------------------------------------------------------------------
1 |
2 |
Ghostbusters, whaddya want.
96 | 97 | 98 | # The same method as above, but the content is referenced from another file. Path is relative to project root. 99 | - method: GET 100 | path: test/help2 101 | status_code: 200 102 | media_type: text/html 103 | content_path: assets/help.html 104 | ``` 105 | 106 | ### Example usage 107 | 108 | An example of making a `curl` request to our second endpoint defined above: 109 | 110 | ```bash 111 | ~ λ curl 0.0.0.0:8000/test/employee/2 -v 112 | > GET /test/employee/2 HTTP/1.1 113 | > 114 | < HTTP/1.1 200 OK 115 | < server: uvicorn 116 | < content-length: 52 117 | < content-type: application/json 118 | < 119 | { "first_name": "Geoffrey", "last_name": "Greeley", "age": 28 } 120 | ``` 121 | 122 | No need to restart **apyr** after editing `endpoints.yaml`- it's all taken care of! 123 | 124 | ## Functions 125 | 126 | **apyr** supports different kinds of functions inside the content parameter. 127 | 128 | Currently supported functions are: 129 | 130 | | Name | Parameters | Description | Examples | 131 | | :--- | :--- | :--- | :--- | 132 | | `%random_first_name(gender)%` | `gender`: Optional string. Can be `male` or `female`. If left empty, will default to both | Will be replaced by a random first name | `%random_first_name(male)%`, `%random_first_name(female)%`, `%random_first_name()%` 133 | | `%random_last_name()%` | | Will be replaced by a random last name | `%random_last_name()%` | 134 | | `%random_int(start, end)%` | `start`: Required int, `end`: Required int | Will be replaced by a random integer between `start` and `end` (both inclusive) | `%random_int(0, 20)%`, `%random_int(20, 50)%` | 135 | 136 | ## Contributing 137 | 138 | If you like this project, please consider [donating to the Electronic Frontier Foundation](https://supporters.eff.org/donate). -------------------------------------------------------------------------------- /apyr/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umutseven92/apyr/5b73482db03b273443d0d67dcf03d50ab74f0205/apyr/__init__.py -------------------------------------------------------------------------------- /apyr/dependencies.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import List 3 | 4 | import yaml 5 | from fastapi import HTTPException 6 | from starlette.responses import Response 7 | 8 | from apyr.exceptions import ( 9 | TooManyEndpointsException, 10 | NoEndpointsException, 11 | FunctionException, 12 | ) 13 | from apyr.function_handler import FunctionHandler 14 | from apyr.functions import FUNCTIONS 15 | from apyr.models import Endpoint 16 | from apyr.utils import get_project_root, get_digest, load_file 17 | 18 | 19 | class EndpointsRepo: 20 | def __init__(self): 21 | self.last_hash: str = "" 22 | self.endpoints: List[Endpoint] = [] 23 | self.endpoints_path = get_project_root().joinpath("endpoints.yaml") 24 | 25 | def _load_endpoints(self): 26 | stream = open(self.endpoints_path, "r") 27 | endpoints = yaml.full_load(stream) 28 | 29 | self.endpoints = [Endpoint(**endpoint) for endpoint in endpoints] 30 | 31 | def _check_if_file_changed(self, path: Path) -> bool: 32 | """Check to see if the file changed. 33 | 34 | We hash the file and compare it to the previous hash. 35 | """ 36 | new_hash = get_digest(str(path)) 37 | if new_hash != self.last_hash: 38 | self.last_hash = new_hash 39 | return True 40 | 41 | return False 42 | 43 | def get_response(self, path: str, method: str) -> Response: 44 | # Do not reload endpoints if the file has not changed 45 | if self._check_if_file_changed(self.endpoints_path): 46 | self._load_endpoints() 47 | 48 | def _filter_endpoints(endpoint: Endpoint): 49 | return endpoint.path == path and endpoint.method.lower() == method.lower() 50 | 51 | filtered: List[Endpoint] = list(filter(_filter_endpoints, self.endpoints)) 52 | 53 | if len(filtered) > 1: 54 | raise TooManyEndpointsException() 55 | if len(filtered) == 0: 56 | raise NoEndpointsException() 57 | 58 | filtered_endpoint = filtered[0] 59 | 60 | if filtered_endpoint.content is None and filtered_endpoint.content_path is None: 61 | return Response( 62 | status_code=filtered_endpoint.status_code, 63 | ) 64 | 65 | content: str = "" 66 | if filtered_endpoint.content: 67 | content = filtered_endpoint.content 68 | elif filtered_endpoint.content_path: 69 | full_path = get_project_root().joinpath(filtered_endpoint.content_path) 70 | content = load_file(str(full_path)) 71 | 72 | try: 73 | body = FunctionHandler.run(content, FUNCTIONS) 74 | except FunctionException as ex: 75 | raise HTTPException( 76 | status_code=500, detail={"error": ex.error, "reason": ex.detail} 77 | ) from ex 78 | 79 | return Response( 80 | status_code=filtered_endpoint.status_code, 81 | media_type=filtered_endpoint.media_type, 82 | content=body, 83 | ) 84 | -------------------------------------------------------------------------------- /apyr/exceptions.py: -------------------------------------------------------------------------------- 1 | class EndpointException(Exception): 2 | pass 3 | 4 | 5 | class TooManyEndpointsException(EndpointException): 6 | def __init__(self): 7 | self.message = "There are too many endpoints matching the conditions." 8 | super().__init__(self.message) 9 | 10 | 11 | class NoEndpointsException(EndpointException): 12 | def __init__(self): 13 | self.message = "There are no endpoints matching the conditions." 14 | super().__init__(self.message) 15 | 16 | 17 | class FunctionException(Exception): 18 | def __init__(self, fun_name: str, detail: str): 19 | self.error = f"Error in function {fun_name}" 20 | self.detail = detail 21 | super().__init__(detail) 22 | -------------------------------------------------------------------------------- /apyr/function_handler.py: -------------------------------------------------------------------------------- 1 | import re 2 | from typing import List, Tuple, Dict 3 | 4 | from apyr.exceptions import FunctionException 5 | from apyr.models import ContentFunction 6 | 7 | 8 | class FunctionHandler: 9 | @staticmethod 10 | def parse_content(content: str) -> List[ContentFunction]: 11 | regex = re.compile( 12 | r"(?PGhostbusters, whaddya want.
6 | 7 | 8 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | apyr: 4 | build: . 5 | ports: 6 | - "8000:8000" 7 | volumes: 8 | - "./endpoints.yaml:/apyr/endpoints.yaml" 9 | -------------------------------------------------------------------------------- /endpoints.yaml: -------------------------------------------------------------------------------- 1 | # A GET method that returns a list of employees. 2 | - method: GET 3 | path: test/employees 4 | status_code: 200 5 | content: > 6 | [ 7 | { "first_name": "Peter", "last_name": "Venkman" }, 8 | { "first_name": "Ray", "last_name": "Stantz" }, 9 | { "first_name": "Egon", "last_name": "Spengler" } 10 | ] 11 | # A GET method that returns an employee. 12 | # Take note of the two %functions%- the employee's first name, last name and age will be random at every response. 13 | - method: GET 14 | path: test/employee/2 15 | status_code: 200 16 | content: > 17 | { 18 | "first_name": "%random_first_name(female)%", 19 | "last_name": "%random_last_name()%", 20 | "age": %random_int(20, 50)% 21 | } 22 | # A POST method that returns a 500. Great for testing error pages. 23 | - method: POST 24 | path: test/employee 25 | media_type: text 26 | status_code: 500 27 | content: An unexpected error occurred while creating the employee. 28 | # A PUT method that returns a 201. Does not return a body- content is optional. 29 | - method: PUT 30 | path: test/employee/3 31 | status_code: 201 32 | # A GET method that returns an HTML page. 33 | - method: GET 34 | path: test/help 35 | status_code: 200 36 | media_type: text/html 37 | content: |- 38 | 39 | 40 | 41 |Ghostbusters, whaddya want.
43 | 44 | 45 | # The same method as above, but the content is referenced from another file. Path is relative to project root. 46 | - method: GET 47 | path: test/help2 48 | status_code: 200 49 | media_type: text/html 50 | content_path: assets/help.html 51 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appdirs" 3 | version = "1.4.4" 4 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "astroid" 11 | version = "2.4.2" 12 | description = "An abstract syntax tree for Python with inference support." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=3.5" 16 | 17 | [package.dependencies] 18 | lazy-object-proxy = ">=1.4.0,<1.5.0" 19 | six = ">=1.12,<2.0" 20 | typed-ast = {version = ">=1.4.0,<1.5", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} 21 | wrapt = ">=1.11,<2.0" 22 | 23 | [[package]] 24 | name = "atomicwrites" 25 | version = "1.4.0" 26 | description = "Atomic file writes." 27 | category = "dev" 28 | optional = false 29 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 30 | 31 | [[package]] 32 | name = "attrs" 33 | version = "20.3.0" 34 | description = "Classes Without Boilerplate" 35 | category = "dev" 36 | optional = false 37 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 38 | 39 | [package.extras] 40 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] 41 | docs = ["furo", "sphinx", "zope.interface"] 42 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] 43 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] 44 | 45 | [[package]] 46 | name = "bcrypt" 47 | version = "3.2.0" 48 | description = "Modern password hashing for your software and your servers" 49 | category = "dev" 50 | optional = false 51 | python-versions = ">=3.6" 52 | 53 | [package.dependencies] 54 | cffi = ">=1.1" 55 | six = ">=1.4.1" 56 | 57 | [package.extras] 58 | tests = ["pytest (>=3.2.1,!=3.3.0)"] 59 | typecheck = ["mypy"] 60 | 61 | [[package]] 62 | name = "black" 63 | version = "20.8b1" 64 | description = "The uncompromising code formatter." 65 | category = "dev" 66 | optional = false 67 | python-versions = ">=3.6" 68 | 69 | [package.dependencies] 70 | appdirs = "*" 71 | click = ">=7.1.2" 72 | mypy-extensions = ">=0.4.3" 73 | pathspec = ">=0.6,<1" 74 | regex = ">=2020.1.8" 75 | toml = ">=0.10.1" 76 | typed-ast = ">=1.4.0" 77 | typing-extensions = ">=3.7.4" 78 | 79 | [package.extras] 80 | colorama = ["colorama (>=0.4.3)"] 81 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 82 | 83 | [[package]] 84 | name = "cached-property" 85 | version = "1.5.2" 86 | description = "A decorator for caching properties in classes." 87 | category = "dev" 88 | optional = false 89 | python-versions = "*" 90 | 91 | [[package]] 92 | name = "certifi" 93 | version = "2020.12.5" 94 | description = "Python package for providing Mozilla's CA Bundle." 95 | category = "dev" 96 | optional = false 97 | python-versions = "*" 98 | 99 | [[package]] 100 | name = "cffi" 101 | version = "1.14.5" 102 | description = "Foreign Function Interface for Python calling C code." 103 | category = "dev" 104 | optional = false 105 | python-versions = "*" 106 | 107 | [package.dependencies] 108 | pycparser = "*" 109 | 110 | [[package]] 111 | name = "chardet" 112 | version = "4.0.0" 113 | description = "Universal encoding detector for Python 2 and 3" 114 | category = "dev" 115 | optional = false 116 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 117 | 118 | [[package]] 119 | name = "click" 120 | version = "7.1.2" 121 | description = "Composable command line interface toolkit" 122 | category = "main" 123 | optional = false 124 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 125 | 126 | [[package]] 127 | name = "colorama" 128 | version = "0.4.4" 129 | description = "Cross-platform colored terminal text." 130 | category = "main" 131 | optional = false 132 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 133 | 134 | [[package]] 135 | name = "cryptography" 136 | version = "3.4.6" 137 | description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." 138 | category = "dev" 139 | optional = false 140 | python-versions = ">=3.6" 141 | 142 | [package.dependencies] 143 | cffi = ">=1.12" 144 | 145 | [package.extras] 146 | docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] 147 | docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"] 148 | pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] 149 | sdist = ["setuptools-rust (>=0.11.4)"] 150 | ssh = ["bcrypt (>=3.1.5)"] 151 | test = ["pytest (>=6.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] 152 | 153 | [[package]] 154 | name = "distro" 155 | version = "1.5.0" 156 | description = "Distro - an OS platform information API" 157 | category = "dev" 158 | optional = false 159 | python-versions = "*" 160 | 161 | [[package]] 162 | name = "docker" 163 | version = "4.4.4" 164 | description = "A Python library for the Docker Engine API." 165 | category = "dev" 166 | optional = false 167 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 168 | 169 | [package.dependencies] 170 | paramiko = {version = ">=2.4.2", optional = true, markers = "extra == \"ssh\""} 171 | pywin32 = {version = "227", markers = "sys_platform == \"win32\""} 172 | requests = ">=2.14.2,<2.18.0 || >2.18.0" 173 | six = ">=1.4.0" 174 | websocket-client = ">=0.32.0" 175 | 176 | [package.extras] 177 | ssh = ["paramiko (>=2.4.2)"] 178 | tls = ["pyOpenSSL (>=17.5.0)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] 179 | 180 | [[package]] 181 | name = "docker-compose" 182 | version = "1.28.5" 183 | description = "Multi-container orchestration for Docker" 184 | category = "dev" 185 | optional = false 186 | python-versions = ">=3.4" 187 | 188 | [package.dependencies] 189 | cached-property = ">=1.2.0,<2" 190 | colorama = {version = ">=0.4,<1", markers = "sys_platform == \"win32\""} 191 | distro = ">=1.5.0,<2" 192 | docker = {version = ">=4.4.4,<5", extras = ["ssh"]} 193 | dockerpty = ">=0.4.1,<1" 194 | docopt = ">=0.6.1,<1" 195 | jsonschema = ">=2.5.1,<4" 196 | python-dotenv = ">=0.13.0,<1" 197 | PyYAML = ">=3.10,<6" 198 | requests = ">=2.20.0,<3" 199 | texttable = ">=0.9.0,<2" 200 | websocket-client = ">=0.32.0,<1" 201 | 202 | [package.extras] 203 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2)"] 204 | tests = ["ddt (>=1.2.2,<2)", "pytest (<6)"] 205 | 206 | [[package]] 207 | name = "dockerpty" 208 | version = "0.4.1" 209 | description = "Python library to use the pseudo-tty of a docker container" 210 | category = "dev" 211 | optional = false 212 | python-versions = "*" 213 | 214 | [package.dependencies] 215 | six = ">=1.3.0" 216 | 217 | [[package]] 218 | name = "docopt" 219 | version = "0.6.2" 220 | description = "Pythonic argument parser, that will make you smile" 221 | category = "dev" 222 | optional = false 223 | python-versions = "*" 224 | 225 | [[package]] 226 | name = "fastapi" 227 | version = "0.63.0" 228 | description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" 229 | category = "main" 230 | optional = false 231 | python-versions = ">=3.6" 232 | 233 | [package.dependencies] 234 | pydantic = ">=1.0.0,<2.0.0" 235 | starlette = "0.13.6" 236 | 237 | [package.extras] 238 | all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.6.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=3.0.0,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"] 239 | dev = ["python-jose[cryptography] (>=3.1.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.14.0)", "graphene (>=2.1.8,<3.0.0)"] 240 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=6.1.4,<7.0.0)", "markdown-include (>=0.5.1,<0.6.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer-cli (>=0.0.9,<0.0.10)", "pyyaml (>=5.3.1,<6.0.0)"] 241 | test = ["pytest (==5.4.3)", "pytest-cov (==2.10.0)", "pytest-asyncio (>=0.14.0,<0.15.0)", "mypy (==0.790)", "flake8 (>=3.8.3,<4.0.0)", "black (==20.8b1)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.15.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.6.0)", "flask (>=1.1.2,<2.0.0)"] 242 | 243 | [[package]] 244 | name = "h11" 245 | version = "0.12.0" 246 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 247 | category = "main" 248 | optional = false 249 | python-versions = ">=3.6" 250 | 251 | [[package]] 252 | name = "httptools" 253 | version = "0.1.1" 254 | description = "A collection of framework independent HTTP protocol utils." 255 | category = "main" 256 | optional = false 257 | python-versions = "*" 258 | 259 | [package.extras] 260 | test = ["Cython (==0.29.14)"] 261 | 262 | [[package]] 263 | name = "idna" 264 | version = "2.10" 265 | description = "Internationalized Domain Names in Applications (IDNA)" 266 | category = "dev" 267 | optional = false 268 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 269 | 270 | [[package]] 271 | name = "importlib-metadata" 272 | version = "3.4.0" 273 | description = "Read metadata from Python packages" 274 | category = "dev" 275 | optional = false 276 | python-versions = ">=3.6" 277 | 278 | [package.dependencies] 279 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 280 | zipp = ">=0.5" 281 | 282 | [package.extras] 283 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 284 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] 285 | 286 | [[package]] 287 | name = "iniconfig" 288 | version = "1.1.1" 289 | description = "iniconfig: brain-dead simple config-ini parsing" 290 | category = "dev" 291 | optional = false 292 | python-versions = "*" 293 | 294 | [[package]] 295 | name = "isort" 296 | version = "5.7.0" 297 | description = "A Python utility / library to sort Python imports." 298 | category = "dev" 299 | optional = false 300 | python-versions = ">=3.6,<4.0" 301 | 302 | [package.extras] 303 | pipfile_deprecated_finder = ["pipreqs", "requirementslib"] 304 | requirements_deprecated_finder = ["pipreqs", "pip-api"] 305 | colors = ["colorama (>=0.4.3,<0.5.0)"] 306 | 307 | [[package]] 308 | name = "jsonschema" 309 | version = "3.2.0" 310 | description = "An implementation of JSON Schema validation for Python" 311 | category = "dev" 312 | optional = false 313 | python-versions = "*" 314 | 315 | [package.dependencies] 316 | attrs = ">=17.4.0" 317 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 318 | pyrsistent = ">=0.14.0" 319 | six = ">=1.11.0" 320 | 321 | [package.extras] 322 | format = ["idna", "jsonpointer (>1.13)", "rfc3987", "strict-rfc3339", "webcolors"] 323 | format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator (>0.1.0)", "rfc3339-validator"] 324 | 325 | [[package]] 326 | name = "lazy-object-proxy" 327 | version = "1.4.3" 328 | description = "A fast and thorough lazy object proxy." 329 | category = "dev" 330 | optional = false 331 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 332 | 333 | [[package]] 334 | name = "mccabe" 335 | version = "0.6.1" 336 | description = "McCabe checker, plugin for flake8" 337 | category = "dev" 338 | optional = false 339 | python-versions = "*" 340 | 341 | [[package]] 342 | name = "mypy-extensions" 343 | version = "0.4.3" 344 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 345 | category = "dev" 346 | optional = false 347 | python-versions = "*" 348 | 349 | [[package]] 350 | name = "names" 351 | version = "0.3.0" 352 | description = "Generate random names" 353 | category = "main" 354 | optional = false 355 | python-versions = "*" 356 | 357 | [[package]] 358 | name = "packaging" 359 | version = "20.9" 360 | description = "Core utilities for Python packages" 361 | category = "dev" 362 | optional = false 363 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 364 | 365 | [package.dependencies] 366 | pyparsing = ">=2.0.2" 367 | 368 | [[package]] 369 | name = "paramiko" 370 | version = "2.7.2" 371 | description = "SSH2 protocol library" 372 | category = "dev" 373 | optional = false 374 | python-versions = "*" 375 | 376 | [package.dependencies] 377 | bcrypt = ">=3.1.3" 378 | cryptography = ">=2.5" 379 | pynacl = ">=1.0.1" 380 | 381 | [package.extras] 382 | all = ["pyasn1 (>=0.1.7)", "pynacl (>=1.0.1)", "bcrypt (>=3.1.3)", "invoke (>=1.3)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] 383 | ed25519 = ["pynacl (>=1.0.1)", "bcrypt (>=3.1.3)"] 384 | gssapi = ["pyasn1 (>=0.1.7)", "gssapi (>=1.4.1)", "pywin32 (>=2.1.8)"] 385 | invoke = ["invoke (>=1.3)"] 386 | 387 | [[package]] 388 | name = "pathspec" 389 | version = "0.8.1" 390 | description = "Utility library for gitignore style pattern matching of file paths." 391 | category = "dev" 392 | optional = false 393 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 394 | 395 | [[package]] 396 | name = "pluggy" 397 | version = "0.13.1" 398 | description = "plugin and hook calling mechanisms for python" 399 | category = "dev" 400 | optional = false 401 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 402 | 403 | [package.dependencies] 404 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 405 | 406 | [package.extras] 407 | dev = ["pre-commit", "tox"] 408 | 409 | [[package]] 410 | name = "py" 411 | version = "1.10.0" 412 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 413 | category = "dev" 414 | optional = false 415 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 416 | 417 | [[package]] 418 | name = "pycparser" 419 | version = "2.20" 420 | description = "C parser in Python" 421 | category = "dev" 422 | optional = false 423 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 424 | 425 | [[package]] 426 | name = "pydantic" 427 | version = "1.7.3" 428 | description = "Data validation and settings management using python 3.6 type hinting" 429 | category = "main" 430 | optional = false 431 | python-versions = ">=3.6" 432 | 433 | [package.extras] 434 | dotenv = ["python-dotenv (>=0.10.4)"] 435 | email = ["email-validator (>=1.0.3)"] 436 | typing_extensions = ["typing-extensions (>=3.7.2)"] 437 | 438 | [[package]] 439 | name = "pydocstyle" 440 | version = "5.1.1" 441 | description = "Python docstring style checker" 442 | category = "dev" 443 | optional = false 444 | python-versions = ">=3.5" 445 | 446 | [package.dependencies] 447 | snowballstemmer = "*" 448 | 449 | [[package]] 450 | name = "pylint" 451 | version = "2.6.0" 452 | description = "python code static checker" 453 | category = "dev" 454 | optional = false 455 | python-versions = ">=3.5.*" 456 | 457 | [package.dependencies] 458 | astroid = ">=2.4.0,<=2.5" 459 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 460 | isort = ">=4.2.5,<6" 461 | mccabe = ">=0.6,<0.7" 462 | toml = ">=0.7.1" 463 | 464 | [[package]] 465 | name = "pynacl" 466 | version = "1.4.0" 467 | description = "Python binding to the Networking and Cryptography (NaCl) library" 468 | category = "dev" 469 | optional = false 470 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 471 | 472 | [package.dependencies] 473 | cffi = ">=1.4.1" 474 | six = "*" 475 | 476 | [package.extras] 477 | docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] 478 | tests = ["pytest (>=3.2.1,!=3.3.0)", "hypothesis (>=3.27.0)"] 479 | 480 | [[package]] 481 | name = "pyparsing" 482 | version = "2.4.7" 483 | description = "Python parsing module" 484 | category = "dev" 485 | optional = false 486 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 487 | 488 | [[package]] 489 | name = "pyrsistent" 490 | version = "0.17.3" 491 | description = "Persistent/Functional/Immutable data structures" 492 | category = "dev" 493 | optional = false 494 | python-versions = ">=3.5" 495 | 496 | [[package]] 497 | name = "pytest" 498 | version = "6.2.2" 499 | description = "pytest: simple powerful testing with Python" 500 | category = "dev" 501 | optional = false 502 | python-versions = ">=3.6" 503 | 504 | [package.dependencies] 505 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 506 | attrs = ">=19.2.0" 507 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 508 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 509 | iniconfig = "*" 510 | packaging = "*" 511 | pluggy = ">=0.12,<1.0.0a1" 512 | py = ">=1.8.2" 513 | toml = "*" 514 | 515 | [package.extras] 516 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 517 | 518 | [[package]] 519 | name = "pytest-dependency" 520 | version = "0.5.1" 521 | description = "Manage dependencies of tests" 522 | category = "dev" 523 | optional = false 524 | python-versions = "*" 525 | 526 | [package.dependencies] 527 | pytest = ">=3.6.0" 528 | 529 | [[package]] 530 | name = "pytest-docker" 531 | version = "0.10.1" 532 | description = "Simple pytest fixtures for Docker and docker-compose based tests" 533 | category = "dev" 534 | optional = false 535 | python-versions = ">=3.6" 536 | 537 | [package.dependencies] 538 | attrs = ">=19,<21" 539 | docker-compose = ">=1.27.3,<2.0" 540 | pytest = ">=4.0,<7.0" 541 | 542 | [package.extras] 543 | tests = ["requests (>=2.22.0,<3.0)", "pytest-pylint (>=0.14.1,<1.0)", "pytest-pycodestyle (>=2.0.0,<3.0)"] 544 | 545 | [[package]] 546 | name = "pytest-mock" 547 | version = "3.5.1" 548 | description = "Thin-wrapper around the mock package for easier use with pytest" 549 | category = "dev" 550 | optional = false 551 | python-versions = ">=3.5" 552 | 553 | [package.dependencies] 554 | pytest = ">=5.0" 555 | 556 | [package.extras] 557 | dev = ["pre-commit", "tox", "pytest-asyncio"] 558 | 559 | [[package]] 560 | name = "python-dotenv" 561 | version = "0.15.0" 562 | description = "Add .env support to your django/flask apps in development and deployments" 563 | category = "main" 564 | optional = false 565 | python-versions = "*" 566 | 567 | [package.extras] 568 | cli = ["click (>=5.0)"] 569 | 570 | [[package]] 571 | name = "pywin32" 572 | version = "227" 573 | description = "Python for Window Extensions" 574 | category = "dev" 575 | optional = false 576 | python-versions = "*" 577 | 578 | [[package]] 579 | name = "pyyaml" 580 | version = "5.4.1" 581 | description = "YAML parser and emitter for Python" 582 | category = "main" 583 | optional = false 584 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 585 | 586 | [[package]] 587 | name = "regex" 588 | version = "2020.11.13" 589 | description = "Alternative regular expression module, to replace re." 590 | category = "dev" 591 | optional = false 592 | python-versions = "*" 593 | 594 | [[package]] 595 | name = "requests" 596 | version = "2.25.1" 597 | description = "Python HTTP for Humans." 598 | category = "dev" 599 | optional = false 600 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 601 | 602 | [package.dependencies] 603 | certifi = ">=2017.4.17" 604 | chardet = ">=3.0.2,<5" 605 | idna = ">=2.5,<3" 606 | urllib3 = ">=1.21.1,<1.27" 607 | 608 | [package.extras] 609 | security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] 610 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 611 | 612 | [[package]] 613 | name = "six" 614 | version = "1.15.0" 615 | description = "Python 2 and 3 compatibility utilities" 616 | category = "dev" 617 | optional = false 618 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 619 | 620 | [[package]] 621 | name = "snowballstemmer" 622 | version = "2.1.0" 623 | description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." 624 | category = "dev" 625 | optional = false 626 | python-versions = "*" 627 | 628 | [[package]] 629 | name = "starlette" 630 | version = "0.13.6" 631 | description = "The little ASGI library that shines." 632 | category = "main" 633 | optional = false 634 | python-versions = ">=3.6" 635 | 636 | [package.extras] 637 | full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"] 638 | 639 | [[package]] 640 | name = "texttable" 641 | version = "1.6.3" 642 | description = "module for creating simple ASCII tables" 643 | category = "dev" 644 | optional = false 645 | python-versions = "*" 646 | 647 | [[package]] 648 | name = "toml" 649 | version = "0.10.2" 650 | description = "Python Library for Tom's Obvious, Minimal Language" 651 | category = "dev" 652 | optional = false 653 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 654 | 655 | [[package]] 656 | name = "typed-ast" 657 | version = "1.4.2" 658 | description = "a fork of Python 2 and 3 ast modules with type comment support" 659 | category = "dev" 660 | optional = false 661 | python-versions = "*" 662 | 663 | [[package]] 664 | name = "typing-extensions" 665 | version = "3.7.4.3" 666 | description = "Backported and Experimental Type Hints for Python 3.5+" 667 | category = "main" 668 | optional = false 669 | python-versions = "*" 670 | 671 | [[package]] 672 | name = "urllib3" 673 | version = "1.26.3" 674 | description = "HTTP library with thread-safe connection pooling, file post, and more." 675 | category = "dev" 676 | optional = false 677 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" 678 | 679 | [package.extras] 680 | brotli = ["brotlipy (>=0.6.0)"] 681 | secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] 682 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 683 | 684 | [[package]] 685 | name = "uvicorn" 686 | version = "0.13.4" 687 | description = "The lightning-fast ASGI server." 688 | category = "main" 689 | optional = false 690 | python-versions = "*" 691 | 692 | [package.dependencies] 693 | click = ">=7.0.0,<8.0.0" 694 | colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} 695 | h11 = ">=0.8" 696 | httptools = {version = ">=0.1.0,<0.2.0", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} 697 | python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} 698 | PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} 699 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 700 | uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} 701 | watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""} 702 | websockets = {version = ">=8.0.0,<9.0.0", optional = true, markers = "extra == \"standard\""} 703 | 704 | [package.extras] 705 | standard = ["websockets (>=8.0.0,<9.0.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "httptools (>=0.1.0,<0.2.0)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] 706 | 707 | [[package]] 708 | name = "uvloop" 709 | version = "0.14.0" 710 | description = "Fast implementation of asyncio event loop on top of libuv" 711 | category = "main" 712 | optional = false 713 | python-versions = "*" 714 | 715 | [[package]] 716 | name = "watchgod" 717 | version = "0.6" 718 | description = "Simple, modern file watching and code reload in python." 719 | category = "main" 720 | optional = false 721 | python-versions = ">=3.5" 722 | 723 | [[package]] 724 | name = "websocket-client" 725 | version = "0.58.0" 726 | description = "WebSocket client for Python with low level API options" 727 | category = "dev" 728 | optional = false 729 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 730 | 731 | [package.dependencies] 732 | six = "*" 733 | 734 | [[package]] 735 | name = "websockets" 736 | version = "8.1" 737 | description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" 738 | category = "main" 739 | optional = false 740 | python-versions = ">=3.6.1" 741 | 742 | [[package]] 743 | name = "wrapt" 744 | version = "1.12.1" 745 | description = "Module for decorators, wrappers and monkey patching." 746 | category = "dev" 747 | optional = false 748 | python-versions = "*" 749 | 750 | [[package]] 751 | name = "zipp" 752 | version = "3.4.0" 753 | description = "Backport of pathlib-compatible object wrapper for zip files" 754 | category = "dev" 755 | optional = false 756 | python-versions = ">=3.6" 757 | 758 | [package.extras] 759 | docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] 760 | testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] 761 | 762 | [metadata] 763 | lock-version = "1.1" 764 | python-versions = "^3.7" 765 | content-hash = "2526f915c45a42c10faec5531b1aebe3e79e9e63d04ab66f8dee381dbe6876d6" 766 | 767 | [metadata.files] 768 | appdirs = [ 769 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 770 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 771 | ] 772 | astroid = [ 773 | {file = "astroid-2.4.2-py3-none-any.whl", hash = "sha256:bc58d83eb610252fd8de6363e39d4f1d0619c894b0ed24603b881c02e64c7386"}, 774 | {file = "astroid-2.4.2.tar.gz", hash = "sha256:2f4078c2a41bf377eea06d71c9d2ba4eb8f6b1af2135bec27bbbb7d8f12bb703"}, 775 | ] 776 | atomicwrites = [ 777 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 778 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 779 | ] 780 | attrs = [ 781 | {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, 782 | {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, 783 | ] 784 | bcrypt = [ 785 | {file = "bcrypt-3.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6"}, 786 | {file = "bcrypt-3.2.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7"}, 787 | {file = "bcrypt-3.2.0-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1"}, 788 | {file = "bcrypt-3.2.0-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d"}, 789 | {file = "bcrypt-3.2.0-cp36-abi3-win32.whl", hash = "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55"}, 790 | {file = "bcrypt-3.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34"}, 791 | {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, 792 | ] 793 | black = [ 794 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 795 | ] 796 | cached-property = [ 797 | {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, 798 | {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, 799 | ] 800 | certifi = [ 801 | {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, 802 | {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, 803 | ] 804 | cffi = [ 805 | {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, 806 | {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, 807 | {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, 808 | {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, 809 | {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, 810 | {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, 811 | {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, 812 | {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, 813 | {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, 814 | {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, 815 | {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, 816 | {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, 817 | {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, 818 | {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, 819 | {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, 820 | {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, 821 | {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, 822 | {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, 823 | {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, 824 | {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, 825 | {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, 826 | {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, 827 | {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, 828 | {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, 829 | {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, 830 | {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, 831 | {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, 832 | {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, 833 | {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, 834 | {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, 835 | {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, 836 | {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, 837 | {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, 838 | {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, 839 | {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, 840 | {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, 841 | {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, 842 | ] 843 | chardet = [ 844 | {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, 845 | {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, 846 | ] 847 | click = [ 848 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 849 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 850 | ] 851 | colorama = [ 852 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 853 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 854 | ] 855 | cryptography = [ 856 | {file = "cryptography-3.4.6-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:57ad77d32917bc55299b16d3b996ffa42a1c73c6cfa829b14043c561288d2799"}, 857 | {file = "cryptography-3.4.6-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:4169a27b818de4a1860720108b55a2801f32b6ae79e7f99c00d79f2a2822eeb7"}, 858 | {file = "cryptography-3.4.6-cp36-abi3-manylinux2010_x86_64.whl", hash = "sha256:93cfe5b7ff006de13e1e89830810ecbd014791b042cbe5eec253be11ac2b28f3"}, 859 | {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_aarch64.whl", hash = "sha256:5ecf2bcb34d17415e89b546dbb44e73080f747e504273e4d4987630493cded1b"}, 860 | {file = "cryptography-3.4.6-cp36-abi3-manylinux2014_x86_64.whl", hash = "sha256:fec7fb46b10da10d9e1d078d1ff8ed9e05ae14f431fdbd11145edd0550b9a964"}, 861 | {file = "cryptography-3.4.6-cp36-abi3-win32.whl", hash = "sha256:df186fcbf86dc1ce56305becb8434e4b6b7504bc724b71ad7a3239e0c9d14ef2"}, 862 | {file = "cryptography-3.4.6-cp36-abi3-win_amd64.whl", hash = "sha256:66b57a9ca4b3221d51b237094b0303843b914b7d5afd4349970bb26518e350b0"}, 863 | {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:066bc53f052dfeda2f2d7c195cf16fb3e5ff13e1b6b7415b468514b40b381a5b"}, 864 | {file = "cryptography-3.4.6-pp36-pypy36_pp73-manylinux2014_x86_64.whl", hash = "sha256:600cf9bfe75e96d965509a4c0b2b183f74a4fa6f5331dcb40fb7b77b7c2484df"}, 865 | {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2010_x86_64.whl", hash = "sha256:0923ba600d00718d63a3976f23cab19aef10c1765038945628cd9be047ad0336"}, 866 | {file = "cryptography-3.4.6-pp37-pypy37_pp73-manylinux2014_x86_64.whl", hash = "sha256:9e98b452132963678e3ac6c73f7010fe53adf72209a32854d55690acac3f6724"}, 867 | {file = "cryptography-3.4.6.tar.gz", hash = "sha256:2d32223e5b0ee02943f32b19245b61a62db83a882f0e76cc564e1cec60d48f87"}, 868 | ] 869 | distro = [ 870 | {file = "distro-1.5.0-py2.py3-none-any.whl", hash = "sha256:df74eed763e18d10d0da624258524ae80486432cd17392d9c3d96f5e83cd2799"}, 871 | {file = "distro-1.5.0.tar.gz", hash = "sha256:0e58756ae38fbd8fc3020d54badb8eae17c5b9dcbed388b17bb55b8a5928df92"}, 872 | ] 873 | docker = [ 874 | {file = "docker-4.4.4-py2.py3-none-any.whl", hash = "sha256:f3607d5695be025fa405a12aca2e5df702a57db63790c73b927eb6a94aac60af"}, 875 | {file = "docker-4.4.4.tar.gz", hash = "sha256:d3393c878f575d3a9ca3b94471a3c89a6d960b35feb92f033c0de36cc9d934db"}, 876 | ] 877 | docker-compose = [ 878 | {file = "docker-compose-1.28.5.tar.gz", hash = "sha256:b3ff8f0352eb4055c4c483cb498aeff7c90195fa679f3caf7098a2d6fa6030e5"}, 879 | {file = "docker_compose-1.28.5-py2.py3-none-any.whl", hash = "sha256:2c09c6a7d320f1191d14ae6e7d93190d459313c8393cc5c74cb15f9205a8f23f"}, 880 | ] 881 | dockerpty = [ 882 | {file = "dockerpty-0.4.1.tar.gz", hash = "sha256:69a9d69d573a0daa31bcd1c0774eeed5c15c295fe719c61aca550ed1393156ce"}, 883 | ] 884 | docopt = [ 885 | {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, 886 | ] 887 | fastapi = [ 888 | {file = "fastapi-0.63.0-py3-none-any.whl", hash = "sha256:98d8ea9591d8512fdadf255d2a8fa56515cdd8624dca4af369da73727409508e"}, 889 | {file = "fastapi-0.63.0.tar.gz", hash = "sha256:63c4592f5ef3edf30afa9a44fa7c6b7ccb20e0d3f68cd9eba07b44d552058dcb"}, 890 | ] 891 | h11 = [ 892 | {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, 893 | {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, 894 | ] 895 | httptools = [ 896 | {file = "httptools-0.1.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce"}, 897 | {file = "httptools-0.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4"}, 898 | {file = "httptools-0.1.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6"}, 899 | {file = "httptools-0.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c"}, 900 | {file = "httptools-0.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a"}, 901 | {file = "httptools-0.1.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f"}, 902 | {file = "httptools-0.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2"}, 903 | {file = "httptools-0.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009"}, 904 | {file = "httptools-0.1.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"}, 905 | {file = "httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d"}, 906 | {file = "httptools-0.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be"}, 907 | {file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"}, 908 | ] 909 | idna = [ 910 | {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, 911 | {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, 912 | ] 913 | importlib-metadata = [ 914 | {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, 915 | {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, 916 | ] 917 | iniconfig = [ 918 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 919 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 920 | ] 921 | isort = [ 922 | {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"}, 923 | {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"}, 924 | ] 925 | jsonschema = [ 926 | {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, 927 | {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, 928 | ] 929 | lazy-object-proxy = [ 930 | {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"}, 931 | {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"}, 932 | {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"}, 933 | {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"}, 934 | {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"}, 935 | {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"}, 936 | {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"}, 937 | {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"}, 938 | {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"}, 939 | {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"}, 940 | {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"}, 941 | {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"}, 942 | {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"}, 943 | {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"}, 944 | {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"}, 945 | {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"}, 946 | {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"}, 947 | {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"}, 948 | {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"}, 949 | {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"}, 950 | {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"}, 951 | ] 952 | mccabe = [ 953 | {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, 954 | {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, 955 | ] 956 | mypy-extensions = [ 957 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 958 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 959 | ] 960 | names = [ 961 | {file = "names-0.3.0.tar.gz", hash = "sha256:726e46254f2ed03f1ffb5d941dae3bc67c35123941c29becd02d48d0caa2a671"}, 962 | ] 963 | packaging = [ 964 | {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, 965 | {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, 966 | ] 967 | paramiko = [ 968 | {file = "paramiko-2.7.2-py2.py3-none-any.whl", hash = "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898"}, 969 | {file = "paramiko-2.7.2.tar.gz", hash = "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035"}, 970 | ] 971 | pathspec = [ 972 | {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, 973 | {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, 974 | ] 975 | pluggy = [ 976 | {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, 977 | {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, 978 | ] 979 | py = [ 980 | {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, 981 | {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, 982 | ] 983 | pycparser = [ 984 | {file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"}, 985 | {file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"}, 986 | ] 987 | pydantic = [ 988 | {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"}, 989 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"}, 990 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"}, 991 | {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"}, 992 | {file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"}, 993 | {file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"}, 994 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"}, 995 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"}, 996 | {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"}, 997 | {file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"}, 998 | {file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"}, 999 | {file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"}, 1000 | {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"}, 1001 | {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"}, 1002 | {file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"}, 1003 | {file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"}, 1004 | {file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"}, 1005 | {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"}, 1006 | {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"}, 1007 | {file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"}, 1008 | {file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"}, 1009 | {file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"}, 1010 | ] 1011 | pydocstyle = [ 1012 | {file = "pydocstyle-5.1.1-py3-none-any.whl", hash = "sha256:aca749e190a01726a4fb472dd4ef23b5c9da7b9205c0a7857c06533de13fd678"}, 1013 | {file = "pydocstyle-5.1.1.tar.gz", hash = "sha256:19b86fa8617ed916776a11cd8bc0197e5b9856d5433b777f51a3defe13075325"}, 1014 | ] 1015 | pylint = [ 1016 | {file = "pylint-2.6.0-py3-none-any.whl", hash = "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f"}, 1017 | {file = "pylint-2.6.0.tar.gz", hash = "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210"}, 1018 | ] 1019 | pynacl = [ 1020 | {file = "PyNaCl-1.4.0-cp27-cp27m-macosx_10_10_x86_64.whl", hash = "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff"}, 1021 | {file = "PyNaCl-1.4.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514"}, 1022 | {file = "PyNaCl-1.4.0-cp27-cp27m-win32.whl", hash = "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574"}, 1023 | {file = "PyNaCl-1.4.0-cp27-cp27m-win_amd64.whl", hash = "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"}, 1024 | {file = "PyNaCl-1.4.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7"}, 1025 | {file = "PyNaCl-1.4.0-cp35-abi3-macosx_10_10_x86_64.whl", hash = "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122"}, 1026 | {file = "PyNaCl-1.4.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d"}, 1027 | {file = "PyNaCl-1.4.0-cp35-abi3-win32.whl", hash = "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634"}, 1028 | {file = "PyNaCl-1.4.0-cp35-abi3-win_amd64.whl", hash = "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6"}, 1029 | {file = "PyNaCl-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4"}, 1030 | {file = "PyNaCl-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25"}, 1031 | {file = "PyNaCl-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4"}, 1032 | {file = "PyNaCl-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6"}, 1033 | {file = "PyNaCl-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f"}, 1034 | {file = "PyNaCl-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f"}, 1035 | {file = "PyNaCl-1.4.0-cp38-cp38-win32.whl", hash = "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96"}, 1036 | {file = "PyNaCl-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420"}, 1037 | {file = "PyNaCl-1.4.0.tar.gz", hash = "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505"}, 1038 | ] 1039 | pyparsing = [ 1040 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 1041 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 1042 | ] 1043 | pyrsistent = [ 1044 | {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, 1045 | ] 1046 | pytest = [ 1047 | {file = "pytest-6.2.2-py3-none-any.whl", hash = "sha256:b574b57423e818210672e07ca1fa90aaf194a4f63f3ab909a2c67ebb22913839"}, 1048 | {file = "pytest-6.2.2.tar.gz", hash = "sha256:9d1edf9e7d0b84d72ea3dbcdfd22b35fb543a5e8f2a60092dd578936bf63d7f9"}, 1049 | ] 1050 | pytest-dependency = [ 1051 | {file = "pytest-dependency-0.5.1.tar.gz", hash = "sha256:c2a892906192663f85030a6ab91304e508e546cddfe557d692d61ec57a1d946b"}, 1052 | ] 1053 | pytest-docker = [ 1054 | {file = "pytest-docker-0.10.1.tar.gz", hash = "sha256:7a0544dc00c83fd7808907a55835b1b7c07e3ea2d22ee558b5a233247e462735"}, 1055 | {file = "pytest_docker-0.10.1-py3-none-any.whl", hash = "sha256:9faa9c87e6e0920612005c8d187c58b3d336f3af49a878f358578de125963858"}, 1056 | ] 1057 | pytest-mock = [ 1058 | {file = "pytest-mock-3.5.1.tar.gz", hash = "sha256:a1e2aba6af9560d313c642dae7e00a2a12b022b80301d9d7fc8ec6858e1dd9fc"}, 1059 | {file = "pytest_mock-3.5.1-py3-none-any.whl", hash = "sha256:379b391cfad22422ea2e252bdfc008edd08509029bcde3c25b2c0bd741e0424e"}, 1060 | ] 1061 | python-dotenv = [ 1062 | {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"}, 1063 | {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"}, 1064 | ] 1065 | pywin32 = [ 1066 | {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, 1067 | {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, 1068 | {file = "pywin32-227-cp35-cp35m-win32.whl", hash = "sha256:f4c5be1a293bae0076d93c88f37ee8da68136744588bc5e2be2f299a34ceb7aa"}, 1069 | {file = "pywin32-227-cp35-cp35m-win_amd64.whl", hash = "sha256:a929a4af626e530383a579431b70e512e736e9588106715215bf685a3ea508d4"}, 1070 | {file = "pywin32-227-cp36-cp36m-win32.whl", hash = "sha256:300a2db938e98c3e7e2093e4491439e62287d0d493fe07cce110db070b54c0be"}, 1071 | {file = "pywin32-227-cp36-cp36m-win_amd64.whl", hash = "sha256:9b31e009564fb95db160f154e2aa195ed66bcc4c058ed72850d047141b36f3a2"}, 1072 | {file = "pywin32-227-cp37-cp37m-win32.whl", hash = "sha256:47a3c7551376a865dd8d095a98deba954a98f326c6fe3c72d8726ca6e6b15507"}, 1073 | {file = "pywin32-227-cp37-cp37m-win_amd64.whl", hash = "sha256:31f88a89139cb2adc40f8f0e65ee56a8c585f629974f9e07622ba80199057511"}, 1074 | {file = "pywin32-227-cp38-cp38-win32.whl", hash = "sha256:7f18199fbf29ca99dff10e1f09451582ae9e372a892ff03a28528a24d55875bc"}, 1075 | {file = "pywin32-227-cp38-cp38-win_amd64.whl", hash = "sha256:7c1ae32c489dc012930787f06244426f8356e129184a02c25aef163917ce158e"}, 1076 | {file = "pywin32-227-cp39-cp39-win32.whl", hash = "sha256:c054c52ba46e7eb6b7d7dfae4dbd987a1bb48ee86debe3f245a2884ece46e295"}, 1077 | {file = "pywin32-227-cp39-cp39-win_amd64.whl", hash = "sha256:f27cec5e7f588c3d1051651830ecc00294f90728d19c3bf6916e6dba93ea357c"}, 1078 | ] 1079 | pyyaml = [ 1080 | {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, 1081 | {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, 1082 | {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, 1083 | {file = "PyYAML-5.4.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bb4191dfc9306777bc594117aee052446b3fa88737cd13b7188d0e7aa8162185"}, 1084 | {file = "PyYAML-5.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6c78645d400265a062508ae399b60b8c167bf003db364ecb26dcab2bda048253"}, 1085 | {file = "PyYAML-5.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4e0583d24c881e14342eaf4ec5fbc97f934b999a6828693a99157fde912540cc"}, 1086 | {file = "PyYAML-5.4.1-cp36-cp36m-win32.whl", hash = "sha256:3bd0e463264cf257d1ffd2e40223b197271046d09dadf73a0fe82b9c1fc385a5"}, 1087 | {file = "PyYAML-5.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:e4fac90784481d221a8e4b1162afa7c47ed953be40d31ab4629ae917510051df"}, 1088 | {file = "PyYAML-5.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5accb17103e43963b80e6f837831f38d314a0495500067cb25afab2e8d7a4018"}, 1089 | {file = "PyYAML-5.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e1d4970ea66be07ae37a3c2e48b5ec63f7ba6804bdddfdbd3cfd954d25a82e63"}, 1090 | {file = "PyYAML-5.4.1-cp37-cp37m-win32.whl", hash = "sha256:dd5de0646207f053eb0d6c74ae45ba98c3395a571a2891858e87df7c9b9bd51b"}, 1091 | {file = "PyYAML-5.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:08682f6b72c722394747bddaf0aa62277e02557c0fd1c42cb853016a38f8dedf"}, 1092 | {file = "PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2d9808ea7b4af864f35ea216be506ecec180628aced0704e34aca0b040ffe46"}, 1093 | {file = "PyYAML-5.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:8c1be557ee92a20f184922c7b6424e8ab6691788e6d86137c5d93c1a6ec1b8fb"}, 1094 | {file = "PyYAML-5.4.1-cp38-cp38-win32.whl", hash = "sha256:fa5ae20527d8e831e8230cbffd9f8fe952815b2b7dae6ffec25318803a7528fc"}, 1095 | {file = "PyYAML-5.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:0f5f5786c0e09baddcd8b4b45f20a7b5d61a7e7e99846e3c799b05c7c53fa696"}, 1096 | {file = "PyYAML-5.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:294db365efa064d00b8d1ef65d8ea2c3426ac366c0c4368d930bf1c5fb497f77"}, 1097 | {file = "PyYAML-5.4.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:74c1485f7707cf707a7aef42ef6322b8f97921bd89be2ab6317fd782c2d53183"}, 1098 | {file = "PyYAML-5.4.1-cp39-cp39-win32.whl", hash = "sha256:49d4cdd9065b9b6e206d0595fee27a96b5dd22618e7520c33204a4a3239d5b10"}, 1099 | {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, 1100 | {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, 1101 | ] 1102 | regex = [ 1103 | {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, 1104 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, 1105 | {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, 1106 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, 1107 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, 1108 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, 1109 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, 1110 | {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, 1111 | {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, 1112 | {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, 1113 | {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, 1114 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, 1115 | {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, 1116 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, 1117 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, 1118 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, 1119 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, 1120 | {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, 1121 | {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, 1122 | {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, 1123 | {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, 1124 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, 1125 | {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, 1126 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, 1127 | {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, 1128 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, 1129 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, 1130 | {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, 1131 | {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, 1132 | {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, 1133 | {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, 1134 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, 1135 | {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, 1136 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, 1137 | {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, 1138 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, 1139 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, 1140 | {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, 1141 | {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, 1142 | {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, 1143 | {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, 1144 | ] 1145 | requests = [ 1146 | {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, 1147 | {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, 1148 | ] 1149 | six = [ 1150 | {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, 1151 | {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, 1152 | ] 1153 | snowballstemmer = [ 1154 | {file = "snowballstemmer-2.1.0-py2.py3-none-any.whl", hash = "sha256:b51b447bea85f9968c13b650126a888aabd4cb4463fca868ec596826325dedc2"}, 1155 | {file = "snowballstemmer-2.1.0.tar.gz", hash = "sha256:e997baa4f2e9139951b6f4c631bad912dfd3c792467e2f03d7239464af90e914"}, 1156 | ] 1157 | starlette = [ 1158 | {file = "starlette-0.13.6-py3-none-any.whl", hash = "sha256:bd2ffe5e37fb75d014728511f8e68ebf2c80b0fa3d04ca1479f4dc752ae31ac9"}, 1159 | {file = "starlette-0.13.6.tar.gz", hash = "sha256:ebe8ee08d9be96a3c9f31b2cb2a24dbdf845247b745664bd8a3f9bd0c977fdbc"}, 1160 | ] 1161 | texttable = [ 1162 | {file = "texttable-1.6.3-py2.py3-none-any.whl", hash = "sha256:f802f2ef8459058736264210f716c757cbf85007a30886d8541aa8c3404f1dda"}, 1163 | {file = "texttable-1.6.3.tar.gz", hash = "sha256:ce0faf21aa77d806bbff22b107cc22cce68dc9438f97a2df32c93e9afa4ce436"}, 1164 | ] 1165 | toml = [ 1166 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 1167 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1168 | ] 1169 | typed-ast = [ 1170 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, 1171 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, 1172 | {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, 1173 | {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, 1174 | {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, 1175 | {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, 1176 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, 1177 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, 1178 | {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, 1179 | {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, 1180 | {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, 1181 | {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, 1182 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, 1183 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, 1184 | {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, 1185 | {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, 1186 | {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, 1187 | {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, 1188 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, 1189 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, 1190 | {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, 1191 | {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, 1192 | {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, 1193 | {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, 1194 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, 1195 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, 1196 | {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, 1197 | {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, 1198 | {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, 1199 | {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, 1200 | ] 1201 | typing-extensions = [ 1202 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 1203 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 1204 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 1205 | ] 1206 | urllib3 = [ 1207 | {file = "urllib3-1.26.3-py2.py3-none-any.whl", hash = "sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80"}, 1208 | {file = "urllib3-1.26.3.tar.gz", hash = "sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73"}, 1209 | ] 1210 | uvicorn = [ 1211 | {file = "uvicorn-0.13.4-py3-none-any.whl", hash = "sha256:7587f7b08bd1efd2b9bad809a3d333e972f1d11af8a5e52a9371ee3a5de71524"}, 1212 | {file = "uvicorn-0.13.4.tar.gz", hash = "sha256:3292251b3c7978e8e4a7868f4baf7f7f7bb7e40c759ecc125c37e99cdea34202"}, 1213 | ] 1214 | uvloop = [ 1215 | {file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"}, 1216 | {file = "uvloop-0.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726"}, 1217 | {file = "uvloop-0.14.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7"}, 1218 | {file = "uvloop-0.14.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"}, 1219 | {file = "uvloop-0.14.0-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891"}, 1220 | {file = "uvloop-0.14.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95"}, 1221 | {file = "uvloop-0.14.0-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5"}, 1222 | {file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"}, 1223 | {file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"}, 1224 | ] 1225 | watchgod = [ 1226 | {file = "watchgod-0.6-py35.py36.py37-none-any.whl", hash = "sha256:59700dab7445aa8e6067a5b94f37bae90fc367554549b1ed2e9d0f4f38a90d2a"}, 1227 | {file = "watchgod-0.6.tar.gz", hash = "sha256:e9cca0ab9c63f17fc85df9fd8bd18156ff00aff04ebe5976cee473f4968c6858"}, 1228 | ] 1229 | websocket-client = [ 1230 | {file = "websocket_client-0.58.0-py2.py3-none-any.whl", hash = "sha256:44b5df8f08c74c3d82d28100fdc81f4536809ce98a17f0757557813275fbb663"}, 1231 | {file = "websocket_client-0.58.0.tar.gz", hash = "sha256:63509b41d158ae5b7f67eb4ad20fecbb4eee99434e73e140354dc3ff8e09716f"}, 1232 | ] 1233 | websockets = [ 1234 | {file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"}, 1235 | {file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"}, 1236 | {file = "websockets-8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8"}, 1237 | {file = "websockets-8.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb"}, 1238 | {file = "websockets-8.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5"}, 1239 | {file = "websockets-8.1-cp36-cp36m-win32.whl", hash = "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a"}, 1240 | {file = "websockets-8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5"}, 1241 | {file = "websockets-8.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989"}, 1242 | {file = "websockets-8.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d"}, 1243 | {file = "websockets-8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779"}, 1244 | {file = "websockets-8.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8"}, 1245 | {file = "websockets-8.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422"}, 1246 | {file = "websockets-8.1-cp37-cp37m-win32.whl", hash = "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc"}, 1247 | {file = "websockets-8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308"}, 1248 | {file = "websockets-8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092"}, 1249 | {file = "websockets-8.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485"}, 1250 | {file = "websockets-8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1"}, 1251 | {file = "websockets-8.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55"}, 1252 | {file = "websockets-8.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824"}, 1253 | {file = "websockets-8.1-cp38-cp38-win32.whl", hash = "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36"}, 1254 | {file = "websockets-8.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"}, 1255 | {file = "websockets-8.1.tar.gz", hash = "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f"}, 1256 | ] 1257 | wrapt = [ 1258 | {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"}, 1259 | ] 1260 | zipp = [ 1261 | {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, 1262 | {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, 1263 | ] 1264 | -------------------------------------------------------------------------------- /poetry.toml: -------------------------------------------------------------------------------- 1 | [virtualenvs] 2 | create = true 3 | in-project = true -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "apyr" 3 | version = "1.1.0" 4 | description = "Mock that API" 5 | license = "MIT" 6 | readme = "README.md" 7 | homepage = "https://github.com/umutseven92/apyr" 8 | repository = "https://github.com/umutseven92/apyr" 9 | keywords = ["api", "mock", "fastapi"] 10 | authors = ["Umut SevenGhostbusters, whaddya want.
69 | 70 | 71 | """ 72 | 73 | response = requests.get(apyr_service + path) 74 | 75 | assert response.status_code == 200 76 | assert response.headers.get("content-type") == "text/html; charset=utf-8" 77 | 78 | body = response.text 79 | 80 | assert strip_whitespace_html(expected_body) == strip_whitespace_html(body) 81 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umutseven92/apyr/5b73482db03b273443d0d67dcf03d50ab74f0205/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_functions.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from apyr.exceptions import FunctionException 4 | from apyr.function_handler import FunctionHandler 5 | 6 | 7 | class TestFunctions: 8 | def test_can_parse_single_line_content(self): 9 | content = """%random_last_name(first, second)%""" 10 | functions = FunctionHandler.parse_content(content) 11 | 12 | assert len(functions) == 1 13 | function = functions[0] 14 | 15 | assert function.full == "%random_last_name(first, second)%" 16 | assert function.name == "random_last_name" 17 | assert function.params == ["first", "second"] 18 | 19 | def test_can_parse_multi_line_content(self): 20 | content = """ 21 | %random_last_name(first, second)% 22 | %random_first_name(third, fourth)% 23 | """ 24 | functions = FunctionHandler.parse_content(content) 25 | 26 | assert len(functions) == 2 27 | 28 | assert functions[0].full == "%random_last_name(first, second)%" 29 | assert functions[0].name == "random_last_name" 30 | assert functions[0].params == ["first", "second"] 31 | 32 | assert functions[1].full == "%random_first_name(third, fourth)%" 33 | assert functions[1].name == "random_first_name" 34 | assert functions[1].params == ["third", "fourth"] 35 | 36 | def test_wont_parse_incorrect_functions(self): 37 | content = """ 38 | %% 39 | %random_first_name% 40 | %random_first_name()% 41 | %random_first_%name()% 42 | %random_first_name(first)% 43 | %random_first_name%(first, second)% 44 | %random_first_name(first, second)% 45 | %random_first_name%(first,second)% 46 | %random_first_name(first,second)% 47 | 48 | { "first_name": "%random_first_name()%", "last_name": "%random_last_name(abc)%" } 49 | """ 50 | 51 | functions = FunctionHandler.parse_content(content) 52 | 53 | assert len(functions) == 7 54 | 55 | assert functions[0].full == "%random_first_name()%" 56 | assert functions[0].name == "random_first_name" 57 | assert functions[0].params == [] 58 | 59 | assert functions[1].full == "%name()%" 60 | assert functions[1].name == "name" 61 | assert functions[1].params == [] 62 | 63 | assert functions[2].full == "%random_first_name(first)%" 64 | assert functions[2].name == "random_first_name" 65 | assert functions[2].params == ["first"] 66 | 67 | assert functions[3].full == "%random_first_name(first, second)%" # Space 68 | assert functions[3].name == "random_first_name" 69 | assert functions[3].params == ["first", "second"] 70 | 71 | assert functions[4].full == "%random_first_name(first,second)%" # No space 72 | assert functions[4].name == "random_first_name" 73 | assert functions[4].params == ["first", "second"] 74 | 75 | assert functions[5].full == "%random_first_name()%" 76 | assert functions[5].name == "random_first_name" 77 | assert functions[5].params == [] 78 | 79 | assert functions[6].full == "%random_last_name(abc)%" 80 | assert functions[6].name == "random_last_name" 81 | assert functions[6].params == ["abc"] 82 | 83 | def test_can_execute_functions(self): 84 | content = """ 85 | { 86 | "first_name": "%random_first_name(m)%", 87 | "last_name": "%random_last_name()%", 88 | "age": %random_int(0, 50)% 89 | } 90 | """ 91 | 92 | mock_functions = { 93 | "random_first_name": lambda x: "Harry", 94 | "random_last_name": lambda: "Canyon", 95 | "random_int": lambda x, y: 42, 96 | } 97 | 98 | exec_content = FunctionHandler.run(content, mock_functions) 99 | 100 | assert ( 101 | exec_content 102 | == """ 103 | { 104 | "first_name": "Harry", 105 | "last_name": "Canyon", 106 | "age": 42 107 | } 108 | """ 109 | ) 110 | 111 | def test_will_raise_function_exception(self): 112 | content = """ 113 | { 114 | "age": "%random_int(5, abc)%", 115 | } 116 | """ 117 | 118 | def add_two(x, y): 119 | val = int(x) + int(y) 120 | return val 121 | 122 | mock_functions = {"random_int": add_two} # Should fail 123 | 124 | with pytest.raises(FunctionException): 125 | FunctionHandler.run(content, mock_functions) 126 | -------------------------------------------------------------------------------- /tests/unit/test_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | 5 | from apyr.utils import get_digest, get_project_root 6 | 7 | 8 | class TestUtils: 9 | @pytest.mark.dependency(name="project_root") 10 | def test_can_get_project_root(self): 11 | base_dir = get_project_root() 12 | existing_path = base_dir.joinpath("pyproject.toml") 13 | 14 | assert os.path.isfile(existing_path) 15 | 16 | @pytest.mark.dependency(depends=["project_root"]) 17 | def test_hash_same_file(self): 18 | string1_path = str(get_project_root().joinpath("tests/data/string1.txt")) 19 | 20 | initial_hash = get_digest(string1_path) 21 | duplicate_hash = get_digest(string1_path) 22 | 23 | assert initial_hash == duplicate_hash 24 | 25 | @pytest.mark.dependency(depends=["project_root"]) 26 | def test_hash_diff_file(self): 27 | string1_path = str(get_project_root().joinpath("tests/data/string1.txt")) 28 | string2_path = str(get_project_root().joinpath("tests/data/string2.txt")) 29 | 30 | first_hash = get_digest(string1_path) 31 | second_hash = get_digest(string2_path) 32 | 33 | assert first_hash != second_hash 34 | -------------------------------------------------------------------------------- /tests/unit/test_validators.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from apyr.models import Endpoint 4 | 5 | 6 | class TestValidators: 7 | def test_setting_both_content_and_content_path_raises_value_error(self): 8 | endpoint_json = { 9 | "method": "POST", 10 | "path": "test/employee", 11 | "media_type": "text", 12 | "status_code": 500, 13 | "content": "Test", 14 | "content_path": "Test2", 15 | } 16 | 17 | with pytest.raises(ValueError): 18 | Endpoint(**endpoint_json) 19 | 20 | def test_setting_only_content_is_successful(self): 21 | endpoint_json = { 22 | "method": "POST", 23 | "path": "test/employee", 24 | "media_type": "text", 25 | "status_code": 500, 26 | "content": "Test", 27 | } 28 | 29 | endpoint = Endpoint(**endpoint_json) 30 | 31 | assert endpoint.content == "Test" 32 | assert endpoint.content_path is None 33 | 34 | def test_setting_only_content_path_is_successful(self): 35 | endpoint_json = { 36 | "method": "POST", 37 | "path": "test/employee", 38 | "media_type": "text", 39 | "status_code": 500, 40 | "content_path": "Test", 41 | } 42 | 43 | endpoint = Endpoint(**endpoint_json) 44 | 45 | assert endpoint.content_path == "Test" 46 | assert endpoint.content is None 47 | 48 | def test_setting_none_is_successful(self): 49 | endpoint_json = { 50 | "method": "POST", 51 | "path": "test/employee", 52 | "media_type": "text", 53 | "status_code": 500, 54 | } 55 | 56 | endpoint = Endpoint(**endpoint_json) 57 | 58 | assert endpoint.content_path is None 59 | assert endpoint.content is None 60 | --------------------------------------------------------------------------------