From 4f6750f857c438c120eabe2d3f6cbb1af081dc87 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Fri, 27 Aug 2021 00:43:28 -0300 Subject: [PATCH 01/61] Add base to test for routes --- {image => app/image}/image-classification.svg | 0 {image => app/image}/machine-translation.svg | 0 .../image}/named-entity-recognition.svg | 0 {image => app/image}/object-detection.svg | 0 {image => app/image}/pose-estimation.svg | 0 {image => app/image}/question-answering.svg | 0 main.py => app/main.py | 2 +- app/test/route_test.py | 14 ++ app/test/test_route.py | 44 +++++ docker-compose.yml | 4 +- poetry.lock | 152 +++++++++++++++++- pyproject.toml | 2 + 12 files changed, 214 insertions(+), 4 deletions(-) rename {image => app/image}/image-classification.svg (100%) rename {image => app/image}/machine-translation.svg (100%) rename {image => app/image}/named-entity-recognition.svg (100%) rename {image => app/image}/object-detection.svg (100%) rename {image => app/image}/pose-estimation.svg (100%) rename {image => app/image}/question-answering.svg (100%) rename main.py => app/main.py (91%) create mode 100644 app/test/route_test.py create mode 100644 app/test/test_route.py diff --git a/image/image-classification.svg b/app/image/image-classification.svg similarity index 100% rename from image/image-classification.svg rename to app/image/image-classification.svg diff --git a/image/machine-translation.svg b/app/image/machine-translation.svg similarity index 100% rename from image/machine-translation.svg rename to app/image/machine-translation.svg diff --git a/image/named-entity-recognition.svg b/app/image/named-entity-recognition.svg similarity index 100% rename from image/named-entity-recognition.svg rename to app/image/named-entity-recognition.svg diff --git a/image/object-detection.svg b/app/image/object-detection.svg similarity index 100% rename from image/object-detection.svg rename to app/image/object-detection.svg diff --git a/image/pose-estimation.svg b/app/image/pose-estimation.svg similarity index 100% rename from image/pose-estimation.svg rename to app/image/pose-estimation.svg diff --git a/image/question-answering.svg b/app/image/question-answering.svg similarity index 100% rename from image/question-answering.svg rename to app/image/question-answering.svg diff --git a/main.py b/app/main.py similarity index 91% rename from main.py rename to app/main.py index 1928715..fde7ee6 100644 --- a/main.py +++ b/app/main.py @@ -25,4 +25,4 @@ app.include_router(api_router, prefix=settings.API_V1_STR) -app.mount("/image", StaticFiles(directory="image"), name="image") +app.mount("/image", StaticFiles(directory="app/image"), name="image") diff --git a/app/test/route_test.py b/app/test/route_test.py new file mode 100644 index 0000000..4b23261 --- /dev/null +++ b/app/test/route_test.py @@ -0,0 +1,14 @@ +#from fastapi import FastAPI +#from fastapi.testclient import TestClient +#import pytest + +#from api.main import app + +#from os.path import dirname, basename, isfile, join +#import glob + +#modules = glob.glob(join(dirname(__file__), "*.py")) +#__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')] + + +#client = TestClient(routes) diff --git a/app/test/test_route.py b/app/test/test_route.py new file mode 100644 index 0000000..1b446b5 --- /dev/null +++ b/app/test/test_route.py @@ -0,0 +1,44 @@ +import pytest +from typing import Any +from fastapi.testclient import TestClient +from httpx import AsyncClient + +from app.routes.user import router +from app.main import app + + +client = TestClient(router) + +base_url='http://localhost:8000/api/v1' + +user_id = [] + +@pytest.mark.asyncio +async def test_user_creation(): + body = { + "email": "barbar@foofoo.com", + "first_name": "Foo", + "last_name": "bar", + "password": "foobar" + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post('/users/open', json=body) + print(response.json()) + user_id = response.json() + assert response.status_code == 200 + assert list(response.json().keys()) == [ + 'email', + 'is_active', + 'role', + 'first_name', + 'last_name', + 'id' + ] + +@pytest.mark.asyncio +async def test_user_get(): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f'/users/{user_id.id}') + print(user_id) + assert response.status_code == 200 + assert response.json() == user_id diff --git a/docker-compose.yml b/docker-compose.yml index f531c7d..b4da737 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,7 +17,7 @@ services: retries: 5 backend: - command: bash -c "alembic upgrade head && poetry run python initial_data.py && poetry run uvicorn main:app --reload --host 0.0.0.0" + command: bash -c "alembic upgrade head && poetry run python initial_data.py && poetry run uvicorn app.main:app --reload --host 0.0.0.0" image: "computerprogres-api:latest" volumes: - .:/app @@ -32,7 +32,7 @@ services: context: . dockerfile: Dockerfile args: - INSTALL_DEV: ${INSTALL_DEV-false} + INSTALL_DEV: ${INSTALL_DEV-true} volumes: app-db-data: diff --git a/poetry.lock b/poetry.lock index cc368ec..c248731 100644 --- a/poetry.lock +++ b/poetry.lock @@ -20,6 +20,24 @@ python-dateutil = "*" python-editor = ">=0.3" SQLAlchemy = ">=1.3.0" +[[package]] +name = "anyio" +version = "3.3.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16)"] + [[package]] name = "asgiref" version = "3.3.4" @@ -107,6 +125,17 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "charset-normalizer" +version = "2.0.4" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "dev" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" version = "8.0.1" @@ -245,6 +274,41 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "httpcore" +version = "0.13.6" +description = "A minimal low-level HTTP client." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +anyio = ">=3.0.0,<4.0.0" +h11 = ">=0.11,<0.13" +sniffio = ">=1.0.0,<2.0.0" + +[package.extras] +http2 = ["h2 (>=3,<5)"] + +[[package]] +name = "httpx" +version = "0.19.0" +description = "The next generation HTTP client." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +certifi = "*" +charset-normalizer = "*" +httpcore = ">=0.13.3,<0.14.0" +rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} +sniffio = "*" + +[package.extras] +brotli = ["brotlicffi", "brotli"] +http2 = ["h2 (>=3,<5)"] + [[package]] name = "idna" version = "2.10" @@ -490,6 +554,20 @@ wcwidth = "*" checkqa-mypy = ["mypy (==v0.761)"] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "pytest-asyncio" +version = "0.15.1" +description = "Pytest support for asyncio." +category = "dev" +optional = false +python-versions = ">= 3.6" + +[package.dependencies] +pytest = ">=5.4.0" + +[package.extras] +testing = ["coverage", "hypothesis (>=5.7.1)"] + [[package]] name = "python-dateutil" version = "2.8.1" @@ -589,6 +667,20 @@ urllib3 = ">=1.21.1,<1.27" security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +[[package]] +name = "rfc3986" +version = "1.5.0" +description = "Validating URI References per RFC 3986" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} + +[package.extras] +idna2008 = ["idna"] + [[package]] name = "rsa" version = "4.7.2" @@ -608,6 +700,14 @@ category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +[[package]] +name = "sniffio" +version = "1.2.0" +description = "Sniff out which async library your code is running under" +category = "dev" +optional = false +python-versions = ">=3.5" + [[package]] name = "sqlalchemy" version = "1.4.17" @@ -720,7 +820,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "15b24a5caddedf68823f793cf0b1bf157d87c42c7a4955142b67412e187cd97f" +content-hash = "caa9a24d68f5116e64d81bb1820045bf99dcc1733c24092483cd14d795c956d3" [metadata.files] aiofiles = [ @@ -731,6 +831,10 @@ alembic = [ {file = "alembic-1.6.5-py2.py3-none-any.whl", hash = "sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c"}, {file = "alembic-1.6.5.tar.gz", hash = "sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51"}, ] +anyio = [ + {file = "anyio-3.3.0-py3-none-any.whl", hash = "sha256:929a6852074397afe1d989002aa96d457e3e1e5441357c60d03e7eea0e65e1b0"}, + {file = "anyio-3.3.0.tar.gz", hash = "sha256:ae57a67583e5ff8b4af47666ff5651c3732d45fd26c929253748e796af860374"}, +] asgiref = [ {file = "asgiref-3.3.4-py3-none-any.whl", hash = "sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee"}, {file = "asgiref-3.3.4.tar.gz", hash = "sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"}, @@ -815,6 +919,10 @@ chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] +charset-normalizer = [ + {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, + {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, +] click = [ {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, @@ -906,6 +1014,14 @@ h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, ] +httpcore = [ + {file = "httpcore-0.13.6-py3-none-any.whl", hash = "sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff"}, + {file = "httpcore-0.13.6.tar.gz", hash = "sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e"}, +] +httpx = [ + {file = "httpx-0.19.0-py3-none-any.whl", hash = "sha256:9bd728a6c5ec0a9e243932a9983d57d3cc4a87bb4f554e1360fce407f78f9435"}, + {file = "httpx-0.19.0.tar.gz", hash = "sha256:92ecd2c00c688b529eda11cedb15161eaf02dee9116712f621c70d9a40b2cdd0"}, +] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, @@ -926,6 +1042,8 @@ lxml = [ {file = "lxml-4.6.3-cp27-cp27m-win_amd64.whl", hash = "sha256:8157dadbb09a34a6bd95a50690595e1fa0af1a99445e2744110e3dca7831c4ee"}, {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:7728e05c35412ba36d3e9795ae8995e3c86958179c9770e65558ec3fdfd3724f"}, {file = "lxml-4.6.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:4bff24dfeea62f2e56f5bab929b4428ae6caba2d1eea0c2d6eb618e30a71e6d4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:64812391546a18896adaa86c77c59a4998f33c24788cadc35789e55b727a37f4"}, + {file = "lxml-4.6.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c1a40c06fd5ba37ad39caa0b3144eb3772e813b5fb5b084198a985431c2f1e8d"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:74f7d8d439b18fa4c385f3f5dfd11144bb87c1da034a466c5b5577d23a1d9b51"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:f90ba11136bfdd25cae3951af8da2e95121c9b9b93727b1b896e3fa105b2f586"}, {file = "lxml-4.6.3-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:4c61b3a0db43a1607d6264166b230438f85bfed02e8cff20c22e564d0faff354"}, @@ -971,12 +1089,22 @@ mako = [ {file = "Mako-1.1.4.tar.gz", hash = "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab"}, ] markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -985,14 +1113,21 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1002,6 +1137,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, @@ -1148,6 +1286,10 @@ pytest = [ {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, ] +pytest-asyncio = [ + {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, + {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, +] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, @@ -1182,6 +1324,10 @@ requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, ] +rfc3986 = [ + {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, +] rsa = [ {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, {file = "rsa-4.7.2.tar.gz", hash = "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9"}, @@ -1190,6 +1336,10 @@ six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +sniffio = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] sqlalchemy = [ {file = "SQLAlchemy-1.4.17-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c367ed95d41df584f412a9419b5ece85b0d6c2a08a51ae13ae47ef74ff9a9349"}, {file = "SQLAlchemy-1.4.17-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fdad4a33140b77df61d456922b7974c1f1bb2c35238f6809f078003a620c4734"}, diff --git a/pyproject.toml b/pyproject.toml index ef2ebb5..354e2f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,8 @@ python-slugify = "^5.0.2" [tool.poetry.dev-dependencies] pytest = "^5.2" +httpx = "^0.19.0" +pytest-asyncio = "^0.15.1" [build-system] requires = ["poetry-core>=1.0.0"] From 18a326d06d03c8ca097dd54ef36671791dc276f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Fri, 3 Sep 2021 17:44:10 -0300 Subject: [PATCH 02/61] try to set test database - install sqlalchemy-utils to create and drop database - try to override the get-db, this is popping a lot of errors,we need to fix that --- app/test/conftest.py | 28 ++++++++++++++++++++++++++++ app/test/utils/overrides.py | 8 ++++++++ app/test/utils/test_db.py | 14 ++++++++++++++ pyproject.toml | 1 + 4 files changed, 51 insertions(+) create mode 100644 app/test/conftest.py create mode 100644 app/test/utils/overrides.py create mode 100644 app/test/utils/test_db.py diff --git a/app/test/conftest.py b/app/test/conftest.py new file mode 100644 index 0000000..878ebda --- /dev/null +++ b/app/test/conftest.py @@ -0,0 +1,28 @@ +import pytest +# import alembic.config +from typing import Generator +from sqlalchemy_utils import create_database, database_exists + +from app.database.base import Base +from app.database.init_db import init_db +from app.main import app +from app.deps import get_db +from app.test.utils.overrides import override_get_db +from app.test.utils.test_db import TestSessionLocal, engine, SQLALCHEMY_TEST_DATABASE_URI + +app.dependency_overrides[get_db] = override_get_db + +@pytest.fixture(scope="session") +def set_test_database() -> Generator: + if not database_exists(SQLALCHEMY_TEST_DATABASE_URI): + create_database(SQLALCHEMY_TEST_DATABASE_URI) + Base.metadata.drop_all(bind=engine) + Base.metadata.create_all(bind=engine) + + # alembic.config.main(argv=['--autogenerate','revision']) + # alembic.config.main(argv=['upgrade','head']) + init_db(TestSessionLocal) + yield TestSessionLocal + if database_exists(SQLALCHEMY_TEST_DATABASE_URI): + drop_database(SQLALCHEMY_TEST_DATABASE_URI) + diff --git a/app/test/utils/overrides.py b/app/test/utils/overrides.py new file mode 100644 index 0000000..c971747 --- /dev/null +++ b/app/test/utils/overrides.py @@ -0,0 +1,8 @@ +from .test_db import TestSessionLocal + +def override_get_db() : + try: + db = TestSessionLocal() + yield db + finally: + db.close() \ No newline at end of file diff --git a/app/test/utils/test_db.py b/app/test/utils/test_db.py new file mode 100644 index 0000000..25172f9 --- /dev/null +++ b/app/test/utils/test_db.py @@ -0,0 +1,14 @@ +from pydantic import PostgresDsn +from sqlalchemy.engine import create_engine +from sqlalchemy.orm.session import sessionmaker +from app.settings import settings + +SQLALCHEMY_TEST_DATABASE_URI = PostgresDsn.build( + scheme="postgresql", + user=settings.POSTGRES_USER, + password=settings.POSTGRES_PASSWORD, + host=settings.POSTGRES_SERVER, + path=f"/{settings.POSTGRES_DB}_test", + ) +engine = create_engine(SQLALCHEMY_TEST_DATABASE_URI, pool_pre_ping=True) +TestSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 354e2f3..060d495 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ Jinja2 = "^3.0.1" pandas = "^1.2.5" aiofiles = "^0.7.0" python-slugify = "^5.0.2" +SQLAlchemy-Utils = "^0.37.8" [tool.poetry.dev-dependencies] pytest = "^5.2" From 58d024553f811443f6cf1cf021177abc4f35c762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sat, 4 Sep 2021 15:45:07 -0300 Subject: [PATCH 03/61] make test database work in test enviroment Co-authored-by: Gabriel Tiveron --- app/test/conftest.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/app/test/conftest.py b/app/test/conftest.py index 878ebda..14d7a02 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -11,18 +11,7 @@ from app.test.utils.test_db import TestSessionLocal, engine, SQLALCHEMY_TEST_DATABASE_URI app.dependency_overrides[get_db] = override_get_db - -@pytest.fixture(scope="session") -def set_test_database() -> Generator: - if not database_exists(SQLALCHEMY_TEST_DATABASE_URI): - create_database(SQLALCHEMY_TEST_DATABASE_URI) - Base.metadata.drop_all(bind=engine) - Base.metadata.create_all(bind=engine) - - # alembic.config.main(argv=['--autogenerate','revision']) - # alembic.config.main(argv=['upgrade','head']) - init_db(TestSessionLocal) - yield TestSessionLocal - if database_exists(SQLALCHEMY_TEST_DATABASE_URI): - drop_database(SQLALCHEMY_TEST_DATABASE_URI) - +if not database_exists(SQLALCHEMY_TEST_DATABASE_URI): + create_database(SQLALCHEMY_TEST_DATABASE_URI) +Base.metadata.drop_all(bind=engine) +Base.metadata.create_all(bind=engine) From 883b6209e2439d77415f3cf58ca69d924aa1a78f Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 7 Sep 2021 16:33:57 -0300 Subject: [PATCH 04/61] Add sqlalchemy to poetry lock file --- poetry.lock | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index c248731..7b19f99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -740,6 +740,33 @@ postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] sqlcipher = ["sqlcipher3-binary"] +[[package]] +name = "sqlalchemy-utils" +version = "0.37.8" +description = "Various utility functions for SQLAlchemy." +category = "main" +optional = false +python-versions = "~=3.4" + +[package.dependencies] +six = "*" +SQLAlchemy = ">=1.0" + +[package.extras] +anyjson = ["anyjson (>=0.3.3)"] +arrow = ["arrow (>=0.3.4)"] +babel = ["Babel (>=1.3)"] +color = ["colour (>=0.0.4)"] +encrypted = ["cryptography (>=0.6)"] +intervals = ["intervals (>=0.7.1)"] +password = ["passlib (>=1.6,<2.0)"] +pendulum = ["pendulum (>=2.0.5)"] +phone = ["phonenumbers (>=5.9.2)"] +test = ["pytest (>=2.7.1)", "Pygments (>=1.2)", "Jinja2 (>=2.3)", "docutils (>=0.10)", "flexmock (>=0.9.7)", "mock (==2.0.0)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pg8000 (>=1.12.4)", "pytz (>=2014.2)", "python-dateutil (>=2.6)", "pymysql", "flake8 (>=2.4.0)", "isort (>=4.2.2)", "pyodbc", "backports.zoneinfo"] +test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "anyjson (>=0.3.3)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)", "backports.zoneinfo"] +timezone = ["python-dateutil"] +url = ["furl (>=0.4.1)"] + [[package]] name = "starlette" version = "0.14.2" @@ -820,7 +847,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "caa9a24d68f5116e64d81bb1820045bf99dcc1733c24092483cd14d795c956d3" +content-hash = "4e49d058f548e2ea583afe81cd06c61f31f6ffb0417ddcc243eeedde50a81429" [metadata.files] aiofiles = [ @@ -1372,6 +1399,10 @@ sqlalchemy = [ {file = "SQLAlchemy-1.4.17-cp39-cp39-win_amd64.whl", hash = "sha256:7eb55d5583076c03aaf1510473fad2a61288490809049cb31028af56af7068ee"}, {file = "SQLAlchemy-1.4.17.tar.gz", hash = "sha256:651cdb3adcee13624ba22d5ff3e96f91e16a115d2ca489ddc16a8e4c217e8509"}, ] +sqlalchemy-utils = [ + {file = "SQLAlchemy-Utils-0.37.8.tar.gz", hash = "sha256:a6aaee154f798be4e479af0ceffaa5034d35fcf6f40707c0947d21bde64e05e5"}, + {file = "SQLAlchemy_Utils-0.37.8-py3-none-any.whl", hash = "sha256:b1bf67d904fed16b16ef1dc07f03e5e93a6b23899f920f6b41c09be45fbb85f2"}, +] starlette = [ {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, {file = "starlette-0.14.2.tar.gz", hash = "sha256:7d49f4a27f8742262ef1470608c59ddbc66baf37c148e938c7038e6bc7a998aa"}, From 2885b1ee27cd3f3042d43e7021f47a48df4c0f32 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 7 Sep 2021 16:33:57 -0300 Subject: [PATCH 05/61] Add sqlalchemy to poetry lock file --- .../test_user_route.py} | 9 ++--- poetry.lock | 33 ++++++++++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) rename app/test/{test_route.py => route_tests/test_user_route.py} (87%) diff --git a/app/test/test_route.py b/app/test/route_tests/test_user_route.py similarity index 87% rename from app/test/test_route.py rename to app/test/route_tests/test_user_route.py index 1b446b5..6cde730 100644 --- a/app/test/test_route.py +++ b/app/test/route_tests/test_user_route.py @@ -11,10 +11,10 @@ base_url='http://localhost:8000/api/v1' -user_id = [] @pytest.mark.asyncio -async def test_user_creation(): +async def test_user_route(): + user_id = [] body = { "email": "barbar@foofoo.com", "first_name": "Foo", @@ -34,11 +34,8 @@ async def test_user_creation(): 'last_name', 'id' ] - -@pytest.mark.asyncio -async def test_user_get(): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f'/users/{user_id.id}') + response = await ac.get(f'/users/{user_id["id"]}') print(user_id) assert response.status_code == 200 assert response.json() == user_id diff --git a/poetry.lock b/poetry.lock index c248731..7b19f99 100644 --- a/poetry.lock +++ b/poetry.lock @@ -740,6 +740,33 @@ postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] sqlcipher = ["sqlcipher3-binary"] +[[package]] +name = "sqlalchemy-utils" +version = "0.37.8" +description = "Various utility functions for SQLAlchemy." +category = "main" +optional = false +python-versions = "~=3.4" + +[package.dependencies] +six = "*" +SQLAlchemy = ">=1.0" + +[package.extras] +anyjson = ["anyjson (>=0.3.3)"] +arrow = ["arrow (>=0.3.4)"] +babel = ["Babel (>=1.3)"] +color = ["colour (>=0.0.4)"] +encrypted = ["cryptography (>=0.6)"] +intervals = ["intervals (>=0.7.1)"] +password = ["passlib (>=1.6,<2.0)"] +pendulum = ["pendulum (>=2.0.5)"] +phone = ["phonenumbers (>=5.9.2)"] +test = ["pytest (>=2.7.1)", "Pygments (>=1.2)", "Jinja2 (>=2.3)", "docutils (>=0.10)", "flexmock (>=0.9.7)", "mock (==2.0.0)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pg8000 (>=1.12.4)", "pytz (>=2014.2)", "python-dateutil (>=2.6)", "pymysql", "flake8 (>=2.4.0)", "isort (>=4.2.2)", "pyodbc", "backports.zoneinfo"] +test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "anyjson (>=0.3.3)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)", "backports.zoneinfo"] +timezone = ["python-dateutil"] +url = ["furl (>=0.4.1)"] + [[package]] name = "starlette" version = "0.14.2" @@ -820,7 +847,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "caa9a24d68f5116e64d81bb1820045bf99dcc1733c24092483cd14d795c956d3" +content-hash = "4e49d058f548e2ea583afe81cd06c61f31f6ffb0417ddcc243eeedde50a81429" [metadata.files] aiofiles = [ @@ -1372,6 +1399,10 @@ sqlalchemy = [ {file = "SQLAlchemy-1.4.17-cp39-cp39-win_amd64.whl", hash = "sha256:7eb55d5583076c03aaf1510473fad2a61288490809049cb31028af56af7068ee"}, {file = "SQLAlchemy-1.4.17.tar.gz", hash = "sha256:651cdb3adcee13624ba22d5ff3e96f91e16a115d2ca489ddc16a8e4c217e8509"}, ] +sqlalchemy-utils = [ + {file = "SQLAlchemy-Utils-0.37.8.tar.gz", hash = "sha256:a6aaee154f798be4e479af0ceffaa5034d35fcf6f40707c0947d21bde64e05e5"}, + {file = "SQLAlchemy_Utils-0.37.8-py3-none-any.whl", hash = "sha256:b1bf67d904fed16b16ef1dc07f03e5e93a6b23899f920f6b41c09be45fbb85f2"}, +] starlette = [ {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, {file = "starlette-0.14.2.tar.gz", hash = "sha256:7d49f4a27f8742262ef1470608c59ddbc66baf37c148e938c7038e6bc7a998aa"}, From 0094c2d98890b899570a49f77fdde6886f57024e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Tue, 7 Sep 2021 20:48:15 -0300 Subject: [PATCH 06/61] make autentications on tests --- app/test/__init__.py | 1 + app/test/conftest.py | 29 ++++++++++++++++++++++++- app/test/route_tests/test_user_route.py | 7 ++---- app/test/utils/__init__.py | 1 + 4 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 app/test/__init__.py create mode 100644 app/test/utils/__init__.py diff --git a/app/test/__init__.py b/app/test/__init__.py new file mode 100644 index 0000000..b794fd4 --- /dev/null +++ b/app/test/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1.0' diff --git a/app/test/conftest.py b/app/test/conftest.py index 14d7a02..aefd306 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -1,17 +1,44 @@ import pytest + # import alembic.config +from httpx import AsyncClient from typing import Generator from sqlalchemy_utils import create_database, database_exists from app.database.base import Base +from app.settings import settings from app.database.init_db import init_db from app.main import app from app.deps import get_db from app.test.utils.overrides import override_get_db -from app.test.utils.test_db import TestSessionLocal, engine, SQLALCHEMY_TEST_DATABASE_URI +from app.test.utils.test_db import ( + TestSessionLocal, + engine, + SQLALCHEMY_TEST_DATABASE_URI, +) +from .utils.test_db import TestSessionLocal app.dependency_overrides[get_db] = override_get_db if not database_exists(SQLALCHEMY_TEST_DATABASE_URI): create_database(SQLALCHEMY_TEST_DATABASE_URI) Base.metadata.drop_all(bind=engine) Base.metadata.create_all(bind=engine) +init_db(TestSessionLocal()) + + +@pytest.fixture +def base_url(): + return "http://localhost:8000/api/v1" + + +@pytest.fixture +async def headers(base_url): + body = { + "username": settings.FIRST_SUPERUSER, + "password": settings.FIRST_SUPERUSER_PASSWORD, + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post("/login/access-token", data=body) + json = response.json() + assert json == {"token_type": "bearer", **json } + return {"Authorization": f"{json['token_type']} {json['access_token']}"} diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 6cde730..e2d0abe 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -9,11 +9,10 @@ client = TestClient(router) -base_url='http://localhost:8000/api/v1' @pytest.mark.asyncio -async def test_user_route(): +async def test_user_route(headers, base_url): user_id = [] body = { "email": "barbar@foofoo.com", @@ -23,7 +22,6 @@ async def test_user_route(): } async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post('/users/open', json=body) - print(response.json()) user_id = response.json() assert response.status_code == 200 assert list(response.json().keys()) == [ @@ -35,7 +33,6 @@ async def test_user_route(): 'id' ] async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f'/users/{user_id["id"]}') - print(user_id) + response = await ac.get(f'/users/{user_id["id"]}', headers=headers) assert response.status_code == 200 assert response.json() == user_id diff --git a/app/test/utils/__init__.py b/app/test/utils/__init__.py new file mode 100644 index 0000000..b794fd4 --- /dev/null +++ b/app/test/utils/__init__.py @@ -0,0 +1 @@ +__version__ = '0.1.0' From 95f2cc048166c2a06c87eb5c72fa6e54f766a312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Tue, 7 Sep 2021 22:10:37 -0300 Subject: [PATCH 07/61] use fixtures to separate get and post tests --- app/test/conftest.py | 20 ++++++++++++-------- app/test/route_tests/test_user_route.py | 21 ++++++++++++++------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/app/test/conftest.py b/app/test/conftest.py index aefd306..4e5cbd6 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -1,6 +1,5 @@ import pytest - -# import alembic.config +import asyncio from httpx import AsyncClient from typing import Generator from sqlalchemy_utils import create_database, database_exists @@ -26,13 +25,18 @@ init_db(TestSessionLocal()) -@pytest.fixture -def base_url(): +@pytest.fixture(scope="session") +def event_loop(): + return asyncio.get_event_loop() + + +@pytest.fixture(scope="session") +def base_url() -> str: return "http://localhost:8000/api/v1" -@pytest.fixture -async def headers(base_url): +@pytest.fixture(scope="session") +async def headers(base_url) -> dict: body = { "username": settings.FIRST_SUPERUSER, "password": settings.FIRST_SUPERUSER_PASSWORD, @@ -40,5 +44,5 @@ async def headers(base_url): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post("/login/access-token", data=body) json = response.json() - assert json == {"token_type": "bearer", **json } - return {"Authorization": f"{json['token_type']} {json['access_token']}"} + assert json == {"token_type": "bearer", **json} + return {"Authorization": f"{json['token_type']} {json['access_token']}"} diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index e2d0abe..57cb100 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -11,8 +11,8 @@ -@pytest.mark.asyncio -async def test_user_route(headers, base_url): +@pytest.fixture(scope="module") +async def user_created(base_url): user_id = [] body = { "email": "barbar@foofoo.com", @@ -22,9 +22,11 @@ async def test_user_route(headers, base_url): } async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post('/users/open', json=body) - user_id = response.json() - assert response.status_code == 200 - assert list(response.json().keys()) == [ + return response + +def test_user_create(user_created): + assert user_created.status_code == 200 + assert list(user_created.json().keys()) == [ 'email', 'is_active', 'role', @@ -32,7 +34,12 @@ async def test_user_route(headers, base_url): 'last_name', 'id' ] + +@pytest.mark.asyncio +async def test_user_get(user_created, headers, base_url): + user_json = user_created.json() + user_id = user_json["id"] async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f'/users/{user_id["id"]}', headers=headers) + response = await ac.get(f'/users/{user_id}', headers=headers) assert response.status_code == 200 - assert response.json() == user_id + assert response.json() == user_json From 77256b07981b0c781809b52165aff2b55badd549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 16:06:06 -0300 Subject: [PATCH 08/61] test create user with auth required --- app/test/route_tests/test_user_route.py | 26 +++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 57cb100..ac197d9 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -5,10 +5,7 @@ from app.routes.user import router from app.main import app - - -client = TestClient(router) - +from app.settings import settings @pytest.fixture(scope="module") @@ -35,6 +32,27 @@ def test_user_create(user_created): 'id' ] +@pytest.mark.asyncio +async def test_user_create_auth(base_url, headers): + settings.EMAILS_ENABLED = False + body = { + "email": "user@example.com", + "first_name": "string", + "last_name": "string", + "password": "string" + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post(f'/users/', headers=headers, json=body) + assert response.status_code == 200 + assert list(response.json().keys()) == [ + 'email', + 'is_active', + 'role', + 'first_name', + 'last_name', + 'id' + ] + @pytest.mark.asyncio async def test_user_get(user_created, headers, base_url): user_json = user_created.json() From e5962660ee0b383472b2d8e8a6b773dc30c340dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 17:38:24 -0300 Subject: [PATCH 09/61] create test user get me --- app/test/route_tests/test_user_route.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index ac197d9..410b196 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -61,3 +61,22 @@ async def test_user_get(user_created, headers, base_url): response = await ac.get(f'/users/{user_id}', headers=headers) assert response.status_code == 200 assert response.json() == user_json + +@pytest.mark.asyncio +async def test_user_get_me(headers, base_url): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f'/users/me', headers=headers) + json = response.json() + assert response.status_code == 200 + assert { + "email":settings.FIRST_SUPERUSER, + "role":'super_admin' + }.items() <= json.items() + assert list(json.keys()) == [ + 'email', + 'is_active', + 'role', + 'first_name', + 'last_name', + 'id' + ] \ No newline at end of file From 7973cbd15cf89518258c8d749d4f51799d758aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 17:39:26 -0300 Subject: [PATCH 10/61] apply black formatter --- app/test/route_tests/test_user_route.py | 122 ++++++++++++------------ 1 file changed, 63 insertions(+), 59 deletions(-) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 410b196..22aa2a9 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -10,73 +10,77 @@ @pytest.fixture(scope="module") async def user_created(base_url): - user_id = [] - body = { - "email": "barbar@foofoo.com", - "first_name": "Foo", - "last_name": "bar", - "password": "foobar" - } - async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.post('/users/open', json=body) - return response + user_id = [] + body = { + "email": "barbar@foofoo.com", + "first_name": "Foo", + "last_name": "bar", + "password": "foobar", + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post("/users/open", json=body) + return response + def test_user_create(user_created): - assert user_created.status_code == 200 - assert list(user_created.json().keys()) == [ - 'email', - 'is_active', - 'role', - 'first_name', - 'last_name', - 'id' - ] + assert user_created.status_code == 200 + assert list(user_created.json().keys()) == [ + "email", + "is_active", + "role", + "first_name", + "last_name", + "id", + ] + @pytest.mark.asyncio async def test_user_create_auth(base_url, headers): - settings.EMAILS_ENABLED = False - body = { - "email": "user@example.com", - "first_name": "string", - "last_name": "string", - "password": "string" - } - async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.post(f'/users/', headers=headers, json=body) - assert response.status_code == 200 - assert list(response.json().keys()) == [ - 'email', - 'is_active', - 'role', - 'first_name', - 'last_name', - 'id' - ] + settings.EMAILS_ENABLED = False + body = { + "email": "user@example.com", + "first_name": "string", + "last_name": "string", + "password": "string", + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post(f"/users/", headers=headers, json=body) + assert response.status_code == 200 + assert list(response.json().keys()) == [ + "email", + "is_active", + "role", + "first_name", + "last_name", + "id", + ] + @pytest.mark.asyncio async def test_user_get(user_created, headers, base_url): - user_json = user_created.json() - user_id = user_json["id"] - async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f'/users/{user_id}', headers=headers) - assert response.status_code == 200 - assert response.json() == user_json + user_json = user_created.json() + user_id = user_json["id"] + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/users/{user_id}", headers=headers) + assert response.status_code == 200 + assert response.json() == user_json + @pytest.mark.asyncio async def test_user_get_me(headers, base_url): - async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f'/users/me', headers=headers) - json = response.json() - assert response.status_code == 200 - assert { - "email":settings.FIRST_SUPERUSER, - "role":'super_admin' - }.items() <= json.items() - assert list(json.keys()) == [ - 'email', - 'is_active', - 'role', - 'first_name', - 'last_name', - 'id' - ] \ No newline at end of file + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/users/me", headers=headers) + json = response.json() + assert response.status_code == 200 + assert { + "email": settings.FIRST_SUPERUSER, + "role": "super_admin", + }.items() <= json.items() + assert list(json.keys()) == [ + "email", + "is_active", + "role", + "first_name", + "last_name", + "id", + ] From 37499e4fd8f0b971f869faf06c00d07ed6da4feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 18:22:06 -0300 Subject: [PATCH 11/61] test user put --- app/test/route_tests/test_user_route.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 22aa2a9..3f4f3fb 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -84,3 +84,26 @@ async def test_user_get_me(headers, base_url): "last_name", "id", ] + + +@pytest.mark.asyncio +async def test_user_put(base_url, headers, user_created): + user_json = user_created.json() + user_id = user_json["id"] + body = { + "email": user_json["email"], + "first_name": "bazbazbaz", + "last_name": "foooooo", + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.put(f"/users/{user_id}", headers=headers, json=body) + assert response.status_code == 200 + assert body.items() <= response.json().items() + assert list(response.json().keys()) == [ + "email", + "is_active", + "role", + "first_name", + "last_name", + "id", + ] From cbcbb3f3920e7709948c01f581e0e05bbb311d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 18:28:09 -0300 Subject: [PATCH 12/61] add one more assert --- app/test/route_tests/test_user_route.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 3f4f3fb..98498f2 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -46,6 +46,8 @@ async def test_user_create_auth(base_url, headers): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post(f"/users/", headers=headers, json=body) assert response.status_code == 200 + del body["password"] + assert body.items() <= response.json().items() assert list(response.json().keys()) == [ "email", "is_active", From 4932311ec72d86f25489d71bb504d033310bf46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 18:31:49 -0300 Subject: [PATCH 13/61] test 'user put me' route --- app/test/route_tests/test_user_route.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 98498f2..bb5c8ae 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -109,3 +109,23 @@ async def test_user_put(base_url, headers, user_created): "last_name", "id", ] + +@pytest.mark.asyncio +async def test_user_put_me(base_url, headers): + body = { + "email": settings.FIRST_SUPERUSER, + "first_name": "administrator", + "last_name": "big boss", + } + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.put(f"/users/me", headers=headers, json=body) + assert response.status_code == 200 + assert body.items() <= response.json().items() + assert list(response.json().keys()) == [ + "email", + "is_active", + "role", + "first_name", + "last_name", + "id", + ] \ No newline at end of file From 65446d895ce0cd05d7a604d9af51392e0a534871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 22:46:58 -0300 Subject: [PATCH 14/61] remove unused import --- app/test/route_tests/test_user_route.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index bb5c8ae..91a539b 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -1,9 +1,6 @@ import pytest -from typing import Any -from fastapi.testclient import TestClient from httpx import AsyncClient -from app.routes.user import router from app.main import app from app.settings import settings From e106cae35907eac6c63965983dbf8f97e289e882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 23:00:47 -0300 Subject: [PATCH 15/61] remove unused var --- app/test/route_tests/test_user_route.py | 1 - 1 file changed, 1 deletion(-) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 91a539b..182e7cd 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -7,7 +7,6 @@ @pytest.fixture(scope="module") async def user_created(base_url): - user_id = [] body = { "email": "barbar@foofoo.com", "first_name": "Foo", From f2d5ae17cc6522deccb9d56c61be85d9c3b35f44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 23:26:59 -0300 Subject: [PATCH 16/61] test accuraccy post and test accuracy get --- .../route_tests/test_accuracy_type_route.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/test/route_tests/test_accuracy_type_route.py diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py new file mode 100644 index 0000000..4db53db --- /dev/null +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -0,0 +1,33 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.settings import settings + +keys = ["updated_at", "name", "created_at", "id", "description"] +post_body = { + "name": "Foo", + "description": "foobar", +} + + +@pytest.fixture(scope="module") +async def accuracy_created(base_url: str, headers: dict) -> Response: + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/accuracy_types", json=post_body) + return response + + +def test_accuracy_post(accuracy_created: Response): + assert accuracy_created.status_code == 200 + assert accuracy_created.json().items() >= post_body.items() + assert list(accuracy_created.json().keys()) == ["name", "description", "id"] + + +@pytest.mark.asyncio +async def test_accuracy_get(headers: dict, base_url: str): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/accuracy_types/?skip=0&limit=1", headers=headers) + assert response.status_code == 200 + assert response.json()[0].items() >= post_body.items() + assert list(response.json()[0].keys()) == keys From 11d6e3b6874b31c12936c149f7d8f9fb7702eed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Wed, 8 Sep 2021 23:52:43 -0300 Subject: [PATCH 17/61] test accuracy get id --- .../route_tests/test_accuracy_type_route.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 4db53db..eab62cc 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -4,11 +4,12 @@ from app.main import app from app.settings import settings -keys = ["updated_at", "name", "created_at", "id", "description"] +keys_get = ["updated_at", "name", "created_at", "id", "description"] post_body = { "name": "Foo", "description": "foobar", } +keys = ["name", "description", "id"] @pytest.fixture(scope="module") @@ -21,13 +22,25 @@ async def accuracy_created(base_url: str, headers: dict) -> Response: def test_accuracy_post(accuracy_created: Response): assert accuracy_created.status_code == 200 assert accuracy_created.json().items() >= post_body.items() - assert list(accuracy_created.json().keys()) == ["name", "description", "id"] + assert list(accuracy_created.json().keys()) == keys @pytest.mark.asyncio -async def test_accuracy_get(headers: dict, base_url: str): +async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get(f"/accuracy_types/?skip=0&limit=1", headers=headers) assert response.status_code == 200 assert response.json()[0].items() >= post_body.items() - assert list(response.json()[0].keys()) == keys + assert list(response.json()[0].keys()) == keys_get + + +@pytest.mark.asyncio +async def test_accuracy_get_id( + base_url: str, headers: dict, accuracy_created: Response +): + accuracy_json = accuracy_created.json() + accuracy_id = accuracy_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/accuracy_types/{accuracy_id}") + assert response.status_code == 200 + assert accuracy_json == response.json() From 5692d589b7e33ff0baf89cecd1de56009ab3d504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Thu, 9 Sep 2021 00:03:16 -0300 Subject: [PATCH 18/61] test accuracy put --- app/test/route_tests/test_accuracy_type_route.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index eab62cc..44b09fd 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -2,7 +2,6 @@ from httpx import AsyncClient, Response from app.main import app -from app.settings import settings keys_get = ["updated_at", "name", "created_at", "id", "description"] post_body = { @@ -44,3 +43,17 @@ async def test_accuracy_get_id( response = await ac.get(f"/accuracy_types/{accuracy_id}") assert response.status_code == 200 assert accuracy_json == response.json() + + +@pytest.mark.asyncio +async def test_accuracy_put(base_url: str, headers: dict, accuracy_created: Response): + accuracy_json = accuracy_created.json() + accuracy_id = accuracy_json["id"] + put_json = { + "name": "bazz", + "description": "jazz", + } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/accuracy_types/{accuracy_id}", json=put_json) + assert response.status_code == 200 + assert {**put_json, "id": accuracy_id} == response.json() From e03bea0eb20dbba4d195461c7bb77d30bb64678e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Thu, 9 Sep 2021 00:25:22 -0300 Subject: [PATCH 19/61] use teardown to test delete endpoint --- app/test/route_tests/test_accuracy_type_route.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 44b09fd..1eef25c 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -12,10 +12,15 @@ @pytest.fixture(scope="module") -async def accuracy_created(base_url: str, headers: dict) -> Response: +async def accuracy_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post("/accuracy_types", json=post_body) - return response + yield response + accuracy_id = response.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/accuracy_types/{accuracy_id}") + assert response.status_code == 200 + assert keys == list(response.json().keys()) def test_accuracy_post(accuracy_created: Response): @@ -29,7 +34,6 @@ async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get(f"/accuracy_types/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert response.json()[0].items() >= post_body.items() assert list(response.json()[0].keys()) == keys_get From 315dc96404c61c802c302d721f7262abac8c99ee Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 9 Sep 2021 14:13:42 -0300 Subject: [PATCH 20/61] Change flake8 settings --- .flake8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.flake8 b/.flake8 index e872590..9ea07d0 100644 --- a/.flake8 +++ b/.flake8 @@ -1,3 +1,3 @@ [flake8] max-line-length = 88 -exclude = .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache \ No newline at end of file +exclude = .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache,alembic/versions \ No newline at end of file From bd0d356e23e8e0445ceae025abecee3e0608cdb0 Mon Sep 17 00:00:00 2001 From: Matheus Date: Thu, 9 Sep 2021 14:21:47 -0300 Subject: [PATCH 21/61] Fix code style --- app/crud/base.py | 1 - app/crud/paper.py | 3 +-- app/crud/paper_with_code.py | 10 ++++++++-- app/crud/task.py | 10 ++++++++-- app/database.py | 2 +- app/models/cpu.py | 2 +- app/models/gpu.py | 2 +- app/models/task_dataset.py | 13 +++++++------ app/routes/model.py | 4 +++- app/schemas/msg.py | 2 +- app/schemas/task.py | 2 -- 11 files changed, 31 insertions(+), 20 deletions(-) diff --git a/app/crud/base.py b/app/crud/base.py index 86903fa..f15c916 100644 --- a/app/crud/base.py +++ b/app/crud/base.py @@ -3,7 +3,6 @@ from fastapi.encoders import jsonable_encoder from pydantic import BaseModel from sqlalchemy.orm import Session -import logging from app.database.base import Base diff --git a/app/crud/paper.py b/app/crud/paper.py index 544de1e..a3e90a6 100644 --- a/app/crud/paper.py +++ b/app/crud/paper.py @@ -4,8 +4,7 @@ class CRUDPaper(CRUDBase[Paper, PaperCreate, PaperUpdate]): - pass - + pass paper = CRUDPaper(Paper) diff --git a/app/crud/paper_with_code.py b/app/crud/paper_with_code.py index a51556b..476c22a 100644 --- a/app/crud/paper_with_code.py +++ b/app/crud/paper_with_code.py @@ -41,7 +41,10 @@ def get_multi_model_metrics_by_identifier( 'model_identifier': row.model_identifier, 'model_name': row.model_name, 'model_hardware_burden': row.model_hardware_burden, - 'model_operation_per_network_pass': row.model_gflops if row.model_gflops else row.model_multiply_adds, + 'model_operation_per_network_pass': ( + row.model_gflops + if row.model_gflops else row.model_multiply_adds + ), 'paper_identifier': row.paper_identifier, }) @@ -83,7 +86,10 @@ def get_model_metrics_by_identifier( 'model_identifier': response[0].model_identifier, 'model_name': response[0].model_name, 'model_hardware_burden': response[0].model_hardware_burden, - 'model_operation_per_network_pass': response[0].model_gflops if response[0].model_gflops else response[0].model_multiply_adds, + 'model_operation_per_network_pass': ( + response[0].model_gflops + if response[0].model_gflops else response[0].model_multiply_adds + ), 'paper_identifier': response[0].paper_identifier, } diff --git a/app/crud/task.py b/app/crud/task.py index 1354011..117b623 100644 --- a/app/crud/task.py +++ b/app/crud/task.py @@ -357,7 +357,10 @@ def get_models( 'gflops': row.model_gflops, 'number_of_parameters': row.model_number_of_parameters, 'multiply_adds': row.model_multiply_adds, - 'operation_per_network_pass': row.model_gflops if row.model_gflops else row.model_multiply_adds, + 'operation_per_network_pass': ( + row.model_gflops + if row.model_gflops else row.model_multiply_adds + ), 'hardware_burden': row.model_hardware_burden, 'paper_title': row.paper_title, 'paper_code_link': row.paper_code_link, @@ -443,7 +446,10 @@ def get_models_csv( row.accuracy_type: row.accuracy_value, 'model_gflops': row.model_gflops, 'model_multiply_adds': row.model_multiply_adds, - 'model_operation_per_network_pass': row.model_gflops if row.model_gflops else row.model_multiply_adds, + 'model_operation_per_network_pass': ( + row.model_gflops + if row.model_gflops else row.model_multiply_adds + ), 'model_extra_training_time': row.model_extra_training_time, 'model_number_of_cpus': row.model_number_of_cpus, 'model_cpu': row.model_cpu, diff --git a/app/database.py b/app/database.py index 8c5312d..75f723a 100644 --- a/app/database.py +++ b/app/database.py @@ -10,4 +10,4 @@ ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) -Base = declarative_base() \ No newline at end of file +Base = declarative_base() diff --git a/app/models/cpu.py b/app/models/cpu.py index cf61aaf..4738195 100644 --- a/app/models/cpu.py +++ b/app/models/cpu.py @@ -14,4 +14,4 @@ class Cpu(Base): tdp = Column(Float(precision=3)) gflops = Column(Float(precision=3)) die_size = Column(Integer) - year = Column(Integer) \ No newline at end of file + year = Column(Integer) diff --git a/app/models/gpu.py b/app/models/gpu.py index 9844649..e4a9cd3 100644 --- a/app/models/gpu.py +++ b/app/models/gpu.py @@ -11,4 +11,4 @@ class Gpu(Base): tdp = Column(Float(precision=3)) gflops = Column(Float(precision=3)) die_size = Column(Integer) - year = Column(Integer) \ No newline at end of file + year = Column(Integer) diff --git a/app/models/task_dataset.py b/app/models/task_dataset.py index 310851f..e3b6e57 100644 --- a/app/models/task_dataset.py +++ b/app/models/task_dataset.py @@ -1,8 +1,6 @@ from sqlalchemy import event -import logging -from sqlalchemy.sql.expression import bindparam, select, text -from app.models import Dataset, Task -from sqlalchemy.sql.functions import func + +from sqlalchemy.sql.expression import text from app.database.base import Base from sqlalchemy import Column, Integer, ForeignKey, String from sqlalchemy.orm import relationship @@ -25,8 +23,11 @@ class TaskDataset(Base): def my_before_insert_listener(mapper, connection, target): target.identifier = connection.execute( - text("select concat(task.identifier,'-on-', dataset.identifier) from task, dataset where task.id = %d and dataset.id = %d" % - (target.task_id, target.dataset_id)) + text( + "select concat(task.identifier,'-on-', dataset.identifier) from task, " + "dataset where task.id = %d and dataset.id = %d" % + (target.task_id, target.dataset_id) + ) ).scalar() diff --git a/app/routes/model.py b/app/routes/model.py index 6405ba2..da536c6 100644 --- a/app/routes/model.py +++ b/app/routes/model.py @@ -74,7 +74,9 @@ def get_models_csv( media_type="text/csv" ) - response.headers["Content-Disposition"] = f"attachment; filename={task_id}-{dataset_id}.csv" + response.headers[ + "Content-Disposition" + ] = f"attachment; filename={task_id}-{dataset_id}.csv" return response diff --git a/app/schemas/msg.py b/app/schemas/msg.py index 860e9f3..945e0c6 100644 --- a/app/schemas/msg.py +++ b/app/schemas/msg.py @@ -2,4 +2,4 @@ class Msg(BaseModel): - msg: str \ No newline at end of file + msg: str diff --git a/app/schemas/task.py b/app/schemas/task.py index ba3576d..0ae2b3c 100644 --- a/app/schemas/task.py +++ b/app/schemas/task.py @@ -1,8 +1,6 @@ -from app import models from pydantic.main import BaseModel from typing import List, Optional -from .dataset import Dataset from .model import Model # Shared properties From ceaff1e4f2e0f4c39d31d67bd0d18d47d8563c69 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 9 Sep 2021 16:08:31 -0300 Subject: [PATCH 22/61] Add tpu post test --- app/test/route_tests/test_tpu_route.py | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 app/test/route_tests/test_tpu_route.py diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py new file mode 100644 index 0000000..54bd8fc --- /dev/null +++ b/app/test/route_tests/test_tpu_route.py @@ -0,0 +1,27 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app + +tpu_creation_body = { + "name": "foobar", + "transistors": 10, + "tdp": 20, + "gflops": 5 +} + +@pytest.fixture(scope="module") +async def tpu_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/tpus", json=tpu_creation_body) + yield response + res_body = response.json() + +def test_tpu_post(tpu_created: Response): + json = tpu_created.json() + body_keys = list(tpu_creation_body.keys()) + body_keys.append('id') + assert tpu_created.status_code == 200 + assert json.pop('id', None) == 1 + assert json.items() == tpu_creation_body.items() + assert list(tpu_created.json().keys()) == body_keys From 81637a35e99d0443623e18167c921c9139c5119e Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 9 Sep 2021 19:28:29 -0300 Subject: [PATCH 23/61] Add tpu tests --- app/test/route_tests/test_tpu_route.py | 40 +++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py index 54bd8fc..b5e92b6 100644 --- a/app/test/route_tests/test_tpu_route.py +++ b/app/test/route_tests/test_tpu_route.py @@ -15,7 +15,12 @@ async def tpu_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post("/tpus", json=tpu_creation_body) yield response - res_body = response.json() + json = response.json() + tpu_id = json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/tpus/{tpu_id}") + assert response.status_code == 200 + assert response.json().keys() == json.keys() def test_tpu_post(tpu_created: Response): json = tpu_created.json() @@ -25,3 +30,36 @@ def test_tpu_post(tpu_created: Response): assert json.pop('id', None) == 1 assert json.items() == tpu_creation_body.items() assert list(tpu_created.json().keys()) == body_keys + +@pytest.mark.asyncio +async def test_tpu_get_id(headers: dict, base_url: str, tpu_created: Response): + json = tpu_created.json() + tpu_id = json["id"] + + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/tpus/{tpu_id}") + assert response.status_code == 200 + assert response.json() == json + +@pytest.mark.asyncio +async def test_tpu_get(headers: dict, base_url: str, tpu_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get("/tpus") + assert response.status_code == 200 + + for item in response.json(): + assert list(item.keys()) == list(tpu_created.json().keys()) + +@pytest.mark.asyncio +async def test_tpu_put(headers: dict, base_url: str, tpu_created: Response): + id = tpu_created.json()["id"] + new_json = { + "name": "barfoo", + "transistors": 50, + "tdp": 21, + "gflops": 3 + } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/tpus/{id}", json=new_json) + assert response.status_code == 200 + assert {**new_json, "id": id} == response.json() From 00ae67088933464c897e4633aa16cf9ae50d60bb Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 9 Sep 2021 20:12:04 -0300 Subject: [PATCH 24/61] Add task route tests --- app/test/route_tests/test_task_route.py | 57 +++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 app/test/route_tests/test_task_route.py diff --git a/app/test/route_tests/test_task_route.py b/app/test/route_tests/test_task_route.py new file mode 100644 index 0000000..317528b --- /dev/null +++ b/app/test/route_tests/test_task_route.py @@ -0,0 +1,57 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app + +task = { + "name": "bar", + "image": "foo", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." +} + +task_keys = {**task, "id":0, "number_of_benchmarks":0} + +new_task = { + "name": "foo", + "image": "bar", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit" +} + +@pytest.fixture(scope="module") +async def task_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/tasks", json=task) + yield response + a = response.json() + assert response.status_code == 200 + assert response.json().keys() == a.keys() + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/tasks/{a['id']}") + assert response.status_code == 200 + assert response.json().keys() == task_keys.keys() + +def test_task_creation(task_created: Response): + json = task_created.json() + assert json.keys() == task_keys.keys() + for key in task: + assert json[key] == task[key] + +@pytest.mark.asyncio +async def test_task_get(base_url: str, headers:dict, task_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get("/tasks") + res_json = response.json() + assert response.status_code == 200 + assert isinstance(res_json, list) + +@pytest.mark.asyncio +async def test_task_put(base_url: str, headers: dict, task_created: Response): + res = task_created.json() + + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/tasks/{res['id']}", json=new_task) + json = response.json() + assert response.status_code == 200 + for key in new_task.keys(): + assert new_task[key] == json[key] + assert json.keys() == task_keys.keys() From da59ee6041e3be25a4b99802e11d0af178d3a9ea Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Mon, 13 Sep 2021 17:04:28 -0300 Subject: [PATCH 25/61] Add submission route test --- app/test/route_tests/test_submission_route.py | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 app/test/route_tests/test_submission_route.py diff --git a/app/test/route_tests/test_submission_route.py b/app/test/route_tests/test_submission_route.py new file mode 100644 index 0000000..c2aee14 --- /dev/null +++ b/app/test/route_tests/test_submission_route.py @@ -0,0 +1,174 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app + +submission_body = { + "title": "foo", + "link": "bar", + "code_link": "foobar", + "publication_date": "2021-09-09", + "authors": [ + "bar foo" + ], + "models": [ + { + "name": "foo", + "task": "foofoo", + "dataset": "foobar", + "cpu": "bar foo", + "gpu": "bar bar", + "tpu": "bar", + "gflops": 3, + "multiply_adds": 2, + "number_of_parameters": 20, + "training_time": 30, + "epochs": 5, + "extra_training_data": True, + "accuracies": [ + { + "accuracy_type": "foo", + "value": 0.1 + } + ], + "number_of_gpus": 3, + "number_of_cpus": 1, + "number_of_tpus": 2, + "extra_training_time": False + } + ] +} + +submission_new = { + "title": "foo", + "link": "bar", + "code_link": "foobar", + "publication_date": "2021-09-09", + "authors": [ + "bar foo" + ], + "models": [ + { + "name": "foo", + "task": "foofoo", + "dataset": "foobar", + "cpu": "bar foo", + "gpu": "bar bar", + "tpu": "bar", + "gflops": 3, + "multiply_adds": 2, + "number_of_parameters": 20, + "training_time": 30, + "epochs": 5, + "extra_training_data": True, + "accuracies": [ + { + "accuracy_type": "foo", + "value": 0.1 + } + ], + "number_of_gpus": 3, + "number_of_cpus": 1, + "number_of_tpus": 2, + "extra_training_time": False + } + ] +} + +submission_keys = { + "data": {**submission_body}, + "paper_id": 0, + "owner_id": 0, + "reviewer_id": 0, + "status": "pending", + "id": 0, + "created_at": "2021-09-09T23:17:57.529Z", + "updated_at": "2021-09-09T23:17:57.529Z" + } + +msg_res = { + "body": "test foo bar", + "id": 0, + "author_id": 0, + "submission_id": 0, + "author": { + "email": "user@example.com", + "is_active": True, + "role": "default", + "first_name": "string", + "last_name": "string", + "id": 0 + }, + "type": "string" +} + +@pytest.fixture(scope='module') +async def submission_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post('/submissions', json=submission_body) + yield response.json() + + assert response.status_code == 200 + assert response.json().keys() == submission_keys.keys() + + async with AsyncClient(app=app,base_url=base_url, headers=headers) as ac: + response = await ac.delete(f'/submissions/{response.json()["id"]}') + + assert response.status_code == 200 + assert response.json().keys() == submission_keys.keys() + +def test_submission_post(submission_created: Response): + created = submission_created['data'] + for key in submission_body.keys(): + assert submission_body[key] == created[key] + +@pytest.mark.asyncio +async def test_submission_get_id(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f'/submissions/{submission_created["id"]}') + assert response.status_code == 200 + assert response.json().keys() == submission_keys.keys() + assert response.json()['data'] == submission_body + +@pytest.mark.asyncio +async def test_submission_get(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f'/submissions') + assert response.status_code == 200 + assert response.json()[0].keys() == submission_keys.keys() + assert response.json()[0]['data'] == submission_body + +@pytest.mark.asyncio +async def test_submission_status_put(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f'/submissions/{submission_created["id"]}/status', json={"status": "declined"}) + assert response.status_code == 200 + assert response.json().keys() == submission_keys.keys() + assert response.json()['data'] == submission_body + assert response.json()['status'] == 'declined' + +@pytest.mark.asyncio +async def test_submission_put(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f'/submissions/{submission_created["id"]}', json=submission_new) + assert response.status_code == 200 + assert response.json().keys() == submission_keys.keys() + assert response.json()['data'] == submission_new + +@pytest.mark.asyncio +async def test_submission_message_post(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post(f'/submissions/{submission_created["id"]}/messages', json={'message': msg_res['body']}) + assert response.status_code == 200 + assert response.json().keys() == msg_res.keys() + assert response.json()['body'] == msg_res['body'] + assert response.json()['author'].keys() == msg_res['author'].keys() + +@pytest.mark.asyncio +async def test_submission_message_get(base_url: str, headers: dict, submission_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f'/submissions/{submission_created["id"]}/messages') + assert response.status_code == 200 + assert response.json()[0].keys() == msg_res.keys() + assert response.json()[0]['body'] == msg_res['body'] + assert response.json()[0]['author'].keys() == msg_res['author'].keys() From 94eddc0ff906e9875ae534819a9f8104131a8166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 16:52:36 -0300 Subject: [PATCH 26/61] test cpu post and delete --- app/test/route_tests/test_cpu_route.py | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 app/test/route_tests/test_cpu_route.py diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py new file mode 100644 index 0000000..544d182 --- /dev/null +++ b/app/test/route_tests/test_cpu_route.py @@ -0,0 +1,37 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app + +post_body = { + "name": "string", + "number_of_cores": 0, + "frequency": 0, + "fp32_per_cycle": 0, + "transistors": 0, + "tdp": 0, + "gflops": 0, + "year": 0, + "die_size": 0, +} +keys = {*post_body, "id"} + + +@pytest.fixture(scope="module") +async def cpu_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/cpus", json=post_body) + yield response + cpu_id = response.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/cpus/{cpu_id}") + assert response.status_code == 200 + assert keys == set(response.json().keys()) + + +def test_cpu_post(cpu_created: Response): + assert cpu_created.status_code == 200 + assert cpu_created.json().items() >= post_body.items() + assert set(cpu_created.json().keys()) == keys + + From bc2c2d93ad734a7fb727ffec57efcdf607d7d9eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 16:58:01 -0300 Subject: [PATCH 27/61] change list to set in test_accuracy_type --- app/test/route_tests/test_accuracy_type_route.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 1eef25c..a1de965 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -3,12 +3,13 @@ from app.main import app -keys_get = ["updated_at", "name", "created_at", "id", "description"] + post_body = { "name": "Foo", "description": "foobar", } -keys = ["name", "description", "id"] +keys = {*post_body ,"id"} +keys_get = {*keys ,"updated_at", "created_at"} @pytest.fixture(scope="module") @@ -20,13 +21,13 @@ async def accuracy_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/accuracy_types/{accuracy_id}") assert response.status_code == 200 - assert keys == list(response.json().keys()) + assert keys == set(response.json().keys()) def test_accuracy_post(accuracy_created: Response): assert accuracy_created.status_code == 200 assert accuracy_created.json().items() >= post_body.items() - assert list(accuracy_created.json().keys()) == keys + assert set(accuracy_created.json().keys()) == keys @pytest.mark.asyncio @@ -34,7 +35,7 @@ async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get(f"/accuracy_types/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert list(response.json()[0].keys()) == keys_get + assert set(response.json()[0].keys()) == keys_get @pytest.mark.asyncio From 9835d9f521914e23ddeedbb27cc648dbd8f6cf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 17:00:53 -0300 Subject: [PATCH 28/61] change list to set in test user route --- app/test/route_tests/test_user_route.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 182e7cd..2e86482 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -20,14 +20,14 @@ async def user_created(base_url): def test_user_create(user_created): assert user_created.status_code == 200 - assert list(user_created.json().keys()) == [ + assert set(user_created.json().keys()) == { "email", "is_active", "role", "first_name", "last_name", "id", - ] + } @pytest.mark.asyncio @@ -44,14 +44,14 @@ async def test_user_create_auth(base_url, headers): assert response.status_code == 200 del body["password"] assert body.items() <= response.json().items() - assert list(response.json().keys()) == [ + assert set(response.json().keys()) == { "email", "is_active", "role", "first_name", "last_name", "id", - ] + } @pytest.mark.asyncio @@ -74,14 +74,14 @@ async def test_user_get_me(headers, base_url): "email": settings.FIRST_SUPERUSER, "role": "super_admin", }.items() <= json.items() - assert list(json.keys()) == [ + assert set(json.keys()) == { "email", "is_active", "role", "first_name", "last_name", "id", - ] + } @pytest.mark.asyncio @@ -97,14 +97,14 @@ async def test_user_put(base_url, headers, user_created): response = await ac.put(f"/users/{user_id}", headers=headers, json=body) assert response.status_code == 200 assert body.items() <= response.json().items() - assert list(response.json().keys()) == [ + assert set(response.json().keys()) == { "email", "is_active", "role", "first_name", "last_name", "id", - ] + } @pytest.mark.asyncio async def test_user_put_me(base_url, headers): @@ -117,11 +117,11 @@ async def test_user_put_me(base_url, headers): response = await ac.put(f"/users/me", headers=headers, json=body) assert response.status_code == 200 assert body.items() <= response.json().items() - assert list(response.json().keys()) == [ + assert set(response.json().keys()) == { "email", "is_active", "role", "first_name", "last_name", "id", - ] \ No newline at end of file + } \ No newline at end of file From 7bb3981fccd50d5dcdd850831f6cbe11c0b186df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 17:08:10 -0300 Subject: [PATCH 29/61] test put, get and get_id in cpu route tests --- app/test/route_tests/test_cpu_route.py | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index 544d182..aee0b5b 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -35,3 +35,37 @@ def test_cpu_post(cpu_created: Response): assert set(cpu_created.json().keys()) == keys + +@pytest.mark.asyncio +async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/cpus/?skip=0&limit=1", headers=headers) + assert response.status_code == 200 + assert set(response.json()[0].keys()) == keys + + +@pytest.mark.asyncio +async def test_cpu_get_id( + base_url: str, headers: dict, cpu_created: Response +): + cpu_json = cpu_created.json() + cpu_id = cpu_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/cpus/{cpu_id}") + assert response.status_code == 200 + assert cpu_json == response.json() + + +@pytest.mark.asyncio +async def test_cpu_put(base_url: str, headers: dict, cpu_created: Response): + cpu_json = cpu_created.json() + cpu_id = cpu_json["id"] + put_json = { + **post_body, + "year": 2020, + "transistors": 3333 + } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/cpus/{cpu_id}", json=put_json) + assert response.status_code == 200 + assert {**put_json, "id": cpu_id} == response.json() From 0d4e9dc601373f381cc042207b83adab02db928f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 17:16:23 -0300 Subject: [PATCH 30/61] format cpu route tests with black --- app/test/route_tests/test_cpu_route.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index aee0b5b..ca24163 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -35,7 +35,6 @@ def test_cpu_post(cpu_created: Response): assert set(cpu_created.json().keys()) == keys - @pytest.mark.asyncio async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: @@ -45,9 +44,7 @@ async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): @pytest.mark.asyncio -async def test_cpu_get_id( - base_url: str, headers: dict, cpu_created: Response -): +async def test_cpu_get_id(base_url: str, headers: dict, cpu_created: Response): cpu_json = cpu_created.json() cpu_id = cpu_json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: @@ -60,11 +57,7 @@ async def test_cpu_get_id( async def test_cpu_put(base_url: str, headers: dict, cpu_created: Response): cpu_json = cpu_created.json() cpu_id = cpu_json["id"] - put_json = { - **post_body, - "year": 2020, - "transistors": 3333 - } + put_json = {**post_body, "year": 2020, "transistors": 3333} async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/cpus/{cpu_id}", json=put_json) assert response.status_code == 200 From 1259e177c7e88feae5784bf8826a1bfb622285d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 17:54:55 -0300 Subject: [PATCH 31/61] dataset route tests, with put test not working. --- app/test/route_tests/test_datasets_route.py | 67 +++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 app/test/route_tests/test_datasets_route.py diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py new file mode 100644 index 0000000..5b6426c --- /dev/null +++ b/app/test/route_tests/test_datasets_route.py @@ -0,0 +1,67 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app + +post_body = { + "name": "string", + "image": "string", + "description": "string", + "source": "string", + "identifier": "string" +} +keys = {*post_body, "id"} + + +@pytest.fixture(scope="module") +async def datasets_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/datasets", json=post_body) + yield response + datasets_id = response.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/datasets/{datasets_id}") + assert response.status_code == 200 + assert keys == set(response.json().keys()) + + +def test_datasets_post(datasets_created: Response): + assert datasets_created.status_code == 200 + assert datasets_created.json().items() >= post_body.items() + assert set(datasets_created.json().keys()) == keys + + + +@pytest.mark.asyncio +async def test_datasets_get(headers: dict, base_url: str, datasets_created: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/datasets/?skip=0&limit=1", headers=headers) + assert response.status_code == 200 + assert set(response.json()[0].keys()) == keys + + +@pytest.mark.asyncio +async def test_datasets_get_id( + base_url: str, headers: dict, datasets_created: Response +): + datasets_json = datasets_created.json() + datasets_id = datasets_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/datasets/{datasets_id}") + assert response.status_code == 200 + assert datasets_json == response.json() + + +@pytest.mark.asyncio +async def test_datasets_put(base_url: str, headers: dict, datasets_created: Response): + datasets_json = datasets_created.json() + datasets_id = datasets_json["id"] + put_json = { + **post_body, + "description": "i changed my description because i want", + "source": "example" + } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/datasets/{datasets_id}", json=put_json) + assert response.status_code == 200 + assert {**put_json, "id": datasets_id} == response.json() From 88bfae78a3c2c0f9837901fa4f3b296919c77c09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 19:12:02 -0300 Subject: [PATCH 32/61] test test_token route --- app/test/route_tests/test_login_route.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 app/test/route_tests/test_login_route.py diff --git a/app/test/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py new file mode 100644 index 0000000..b480a3a --- /dev/null +++ b/app/test/route_tests/test_login_route.py @@ -0,0 +1,21 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.settings import settings + +@pytest.mark.asyncio +async def test_test_token_route(headers, base_url): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post("/login/test-token", headers=headers) + assert response.status_code == 200 + json = response.json() + expected_json = { + "email": settings.FIRST_SUPERUSER, + "is_active": True, + "role": "super_admin", + "first_name": None, + "last_name": None, + } + assert json.items() >= expected_json.items() + assert set(json.keys()) == {*expected_json, "id"} \ No newline at end of file From 8e8d2a0e8365f34cdcc0447c419cd702feb6a3a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 19:36:09 -0300 Subject: [PATCH 33/61] add comment on why not test reset password --- app/test/route_tests/test_login_route.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/test/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py index b480a3a..790d870 100644 --- a/app/test/route_tests/test_login_route.py +++ b/app/test/route_tests/test_login_route.py @@ -4,6 +4,7 @@ from app.main import app from app.settings import settings + @pytest.mark.asyncio async def test_test_token_route(headers, base_url): async with AsyncClient(app=app, base_url=base_url) as ac: @@ -18,4 +19,7 @@ async def test_test_token_route(headers, base_url): "last_name": None, } assert json.items() >= expected_json.items() - assert set(json.keys()) == {*expected_json, "id"} \ No newline at end of file + assert set(json.keys()) == {*expected_json, "id"} + + +# password-recovery and reset-password routes depends on sending email. From 1e0fed85544625e900f02028fc539b95559a73cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 21:31:03 -0300 Subject: [PATCH 34/61] remove my email from CODE_OF_CONDUCT --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5d1ce9a..380792f 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at jjoseaquiless@gmail.com. All +reported by contacting the project team at gmanso@mit.edu. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. From ea0cf00b3ab8dffc1ee4671be028042e3e738b04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 22:31:53 -0300 Subject: [PATCH 35/61] remove useless file --- app/test/route_test.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 app/test/route_test.py diff --git a/app/test/route_test.py b/app/test/route_test.py deleted file mode 100644 index 4b23261..0000000 --- a/app/test/route_test.py +++ /dev/null @@ -1,14 +0,0 @@ -#from fastapi import FastAPI -#from fastapi.testclient import TestClient -#import pytest - -#from api.main import app - -#from os.path import dirname, basename, isfile, join -#import glob - -#modules = glob.glob(join(dirname(__file__), "*.py")) -#__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')] - - -#client = TestClient(routes) From fc2b1c38b256c03b45447a2edaba2d59e9d814c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 19 Sep 2021 22:33:33 -0300 Subject: [PATCH 36/61] make creation of dataset and task global. other tests will need them. --- app/test/route_tests/__init__.py | 0 app/test/route_tests/conftest.py | 47 +++++++++++++++++++++ app/test/route_tests/test_datasets_route.py | 33 +++------------ app/test/route_tests/test_task_route.py | 31 +++----------- 4 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 app/test/route_tests/__init__.py create mode 100644 app/test/route_tests/conftest.py diff --git a/app/test/route_tests/__init__.py b/app/test/route_tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py new file mode 100644 index 0000000..2827f56 --- /dev/null +++ b/app/test/route_tests/conftest.py @@ -0,0 +1,47 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +datasets_body = { + "name": "string", + "image": "string", + "description": "string", + "source": "string", + "identifier": "string", +} +datasets_keys = {*datasets_body, "id"} + + +@pytest.fixture(scope="session") +async def datasets_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/datasets", json=datasets_body) + yield response + datasets_id = response.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/datasets/{datasets_id}") + assert response.status_code == 200 + assert dataset_keys == set(response.json().keys()) + + +task = { + "name": "bar", + "image": "foo", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", +} + +task_keys = {**task, "id": 0, "number_of_benchmarks": 0} + + +@pytest.fixture(scope="session") +async def task_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/tasks", json=task) + a = response.json() + assert response.status_code == 200 + assert response.json().keys() == a.keys() + yield response + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/tasks/{a['id']}") + assert response.status_code == 200 + assert response.json().keys() == task_keys.keys() diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index 5b6426c..4dc7efb 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -2,34 +2,13 @@ from httpx import AsyncClient, Response from app.main import app - -post_body = { - "name": "string", - "image": "string", - "description": "string", - "source": "string", - "identifier": "string" -} -keys = {*post_body, "id"} - - -@pytest.fixture(scope="module") -async def datasets_created(base_url: str, headers: dict): - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/datasets", json=post_body) - yield response - datasets_id = response.json()["id"] - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.delete(f"/datasets/{datasets_id}") - assert response.status_code == 200 - assert keys == set(response.json().keys()) +from .conftest import datasets_body, datasets_keys def test_datasets_post(datasets_created: Response): assert datasets_created.status_code == 200 - assert datasets_created.json().items() >= post_body.items() - assert set(datasets_created.json().keys()) == keys - + assert datasets_created.json().items() >= datasets_body.items() + assert set(datasets_created.json().keys()) == datasets_keys @pytest.mark.asyncio @@ -37,7 +16,7 @@ async def test_datasets_get(headers: dict, base_url: str, datasets_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get(f"/datasets/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert set(response.json()[0].keys()) == keys + assert set(response.json()[0].keys()) == datasets_keys @pytest.mark.asyncio @@ -57,9 +36,9 @@ async def test_datasets_put(base_url: str, headers: dict, datasets_created: Resp datasets_json = datasets_created.json() datasets_id = datasets_json["id"] put_json = { - **post_body, + **datasets_body, "description": "i changed my description because i want", - "source": "example" + "source": "example", } async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/datasets/{datasets_id}", json=put_json) diff --git a/app/test/route_tests/test_task_route.py b/app/test/route_tests/test_task_route.py index 317528b..76697bb 100644 --- a/app/test/route_tests/test_task_route.py +++ b/app/test/route_tests/test_task_route.py @@ -2,33 +2,14 @@ from httpx import AsyncClient, Response from app.main import app - -task = { - "name": "bar", - "image": "foo", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." -} - -task_keys = {**task, "id":0, "number_of_benchmarks":0} +from .conftest import task, task_keys new_task = { - "name": "foo", - "image": "bar", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit" + "name": "foo", + "image": "bar", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", } -@pytest.fixture(scope="module") -async def task_created(base_url: str, headers: dict): - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/tasks", json=task) - yield response - a = response.json() - assert response.status_code == 200 - assert response.json().keys() == a.keys() - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.delete(f"/tasks/{a['id']}") - assert response.status_code == 200 - assert response.json().keys() == task_keys.keys() def test_task_creation(task_created: Response): json = task_created.json() @@ -36,14 +17,16 @@ def test_task_creation(task_created: Response): for key in task: assert json[key] == task[key] + @pytest.mark.asyncio -async def test_task_get(base_url: str, headers:dict, task_created: Response): +async def test_task_get(base_url: str, headers: dict, task_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get("/tasks") res_json = response.json() assert response.status_code == 200 assert isinstance(res_json, list) + @pytest.mark.asyncio async def test_task_put(base_url: str, headers: dict, task_created: Response): res = task_created.json() From 04eaf80ac643d2e439019020f3b345243d1ee454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Thu, 23 Sep 2021 15:56:09 -0300 Subject: [PATCH 37/61] fix error change dataset to datasets --- app/test/route_tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index 2827f56..d353d89 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -21,7 +21,7 @@ async def datasets_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/datasets/{datasets_id}") assert response.status_code == 200 - assert dataset_keys == set(response.json().keys()) + assert datasets_keys == set(response.json().keys()) task = { From c75badf877e8c7cdc16af4260b72297b8ffad74e Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Wed, 6 Oct 2021 23:06:34 -0300 Subject: [PATCH 38/61] Add style sheet to route tests files --- app/test/conftest.py | 2 - app/test/route_tests/conftest.py | 10 ++++- .../route_tests/test_accuracy_type_route.py | 6 +-- app/test/route_tests/test_cpu_route.py | 2 +- app/test/route_tests/test_datasets_route.py | 2 +- app/test/route_tests/test_login_route.py | 2 +- app/test/route_tests/test_submission_route.py | 45 ++++++++++++++----- app/test/route_tests/test_tpu_route.py | 5 +++ app/test/route_tests/test_user_route.py | 9 ++-- app/test/utils/overrides.py | 13 +++--- app/test/utils/test_db.py | 2 +- 11 files changed, 66 insertions(+), 32 deletions(-) diff --git a/app/test/conftest.py b/app/test/conftest.py index 4e5cbd6..d2a8769 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -1,7 +1,6 @@ import pytest import asyncio from httpx import AsyncClient -from typing import Generator from sqlalchemy_utils import create_database, database_exists from app.database.base import Base @@ -11,7 +10,6 @@ from app.deps import get_db from app.test.utils.overrides import override_get_db from app.test.utils.test_db import ( - TestSessionLocal, engine, SQLALCHEMY_TEST_DATABASE_URI, ) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index d353d89..7a126cc 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -1,5 +1,5 @@ import pytest -from httpx import AsyncClient, Response +from httpx import AsyncClient from app.main import app datasets_body = { @@ -27,7 +27,13 @@ async def datasets_created(base_url: str, headers: dict): task = { "name": "bar", "image": "foo", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed \ + do eiusmod tempor incididunt ut labore et dolore magna aliqua. \ + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris\ + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in \ + reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in \ + culpa qui officia deserunt mollit anim id est laborum.", } task_keys = {**task, "id": 0, "number_of_benchmarks": 0} diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index a1de965..8807318 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -8,8 +8,8 @@ "name": "Foo", "description": "foobar", } -keys = {*post_body ,"id"} -keys_get = {*keys ,"updated_at", "created_at"} +keys = {*post_body, "id"} +keys_get = {*keys, "updated_at", "created_at"} @pytest.fixture(scope="module") @@ -33,7 +33,7 @@ def test_accuracy_post(accuracy_created: Response): @pytest.mark.asyncio async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f"/accuracy_types/?skip=0&limit=1", headers=headers) + response = await ac.get("/accuracy_types/?skip=0&limit=1", headers=headers) assert response.status_code == 200 assert set(response.json()[0].keys()) == keys_get diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index ca24163..b8ab81c 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -38,7 +38,7 @@ def test_cpu_post(cpu_created: Response): @pytest.mark.asyncio async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f"/cpus/?skip=0&limit=1", headers=headers) + response = await ac.get("/cpus/?skip=0&limit=1", headers=headers) assert response.status_code == 200 assert set(response.json()[0].keys()) == keys diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index 4dc7efb..87f3ba9 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -14,7 +14,7 @@ def test_datasets_post(datasets_created: Response): @pytest.mark.asyncio async def test_datasets_get(headers: dict, base_url: str, datasets_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f"/datasets/?skip=0&limit=1", headers=headers) + response = await ac.get("/datasets/?skip=0&limit=1", headers=headers) assert response.status_code == 200 assert set(response.json()[0].keys()) == datasets_keys diff --git a/app/test/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py index 790d870..99d598b 100644 --- a/app/test/route_tests/test_login_route.py +++ b/app/test/route_tests/test_login_route.py @@ -1,5 +1,5 @@ import pytest -from httpx import AsyncClient, Response +from httpx import AsyncClient from app.main import app from app.settings import settings diff --git a/app/test/route_tests/test_submission_route.py b/app/test/route_tests/test_submission_route.py index c2aee14..8694f71 100644 --- a/app/test/route_tests/test_submission_route.py +++ b/app/test/route_tests/test_submission_route.py @@ -102,6 +102,7 @@ "type": "string" } + @pytest.fixture(scope='module') async def submission_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: @@ -111,61 +112,83 @@ async def submission_created(base_url: str, headers: dict): assert response.status_code == 200 assert response.json().keys() == submission_keys.keys() - async with AsyncClient(app=app,base_url=base_url, headers=headers) as ac: + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f'/submissions/{response.json()["id"]}') assert response.status_code == 200 assert response.json().keys() == submission_keys.keys() + def test_submission_post(submission_created: Response): created = submission_created['data'] for key in submission_body.keys(): assert submission_body[key] == created[key] + @pytest.mark.asyncio -async def test_submission_get_id(base_url: str, headers: dict, submission_created: Response): +async def test_submission_get_id(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}') assert response.status_code == 200 assert response.json().keys() == submission_keys.keys() assert response.json()['data'] == submission_body + @pytest.mark.asyncio -async def test_submission_get(base_url: str, headers: dict, submission_created: Response): +async def test_submission_get(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.get(f'/submissions') + response = await ac.get('/submissions') assert response.status_code == 200 assert response.json()[0].keys() == submission_keys.keys() assert response.json()[0]['data'] == submission_body + @pytest.mark.asyncio -async def test_submission_status_put(base_url: str, headers: dict, submission_created: Response): +async def test_submission_status_put(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.put(f'/submissions/{submission_created["id"]}/status', json={"status": "declined"}) + response = await ac.put(f'/submissions/{submission_created["id"]}/status', + json={"status": "declined"}) assert response.status_code == 200 assert response.json().keys() == submission_keys.keys() assert response.json()['data'] == submission_body assert response.json()['status'] == 'declined' + @pytest.mark.asyncio -async def test_submission_put(base_url: str, headers: dict, submission_created: Response): +async def test_submission_put(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.put(f'/submissions/{submission_created["id"]}', json=submission_new) + response = await ac.put(f'/submissions/{submission_created["id"]}', + json=submission_new) assert response.status_code == 200 assert response.json().keys() == submission_keys.keys() assert response.json()['data'] == submission_new + @pytest.mark.asyncio -async def test_submission_message_post(base_url: str, headers: dict, submission_created: Response): +async def test_submission_message_post(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post(f'/submissions/{submission_created["id"]}/messages', json={'message': msg_res['body']}) + response = await ac.post(f'/submissions/{submission_created["id"]}/messages', + json={'message': msg_res['body']}) assert response.status_code == 200 assert response.json().keys() == msg_res.keys() assert response.json()['body'] == msg_res['body'] assert response.json()['author'].keys() == msg_res['author'].keys() + @pytest.mark.asyncio -async def test_submission_message_get(base_url: str, headers: dict, submission_created: Response): +async def test_submission_message_get(base_url: str, + headers: dict, + submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}/messages') assert response.status_code == 200 diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py index b5e92b6..dd24816 100644 --- a/app/test/route_tests/test_tpu_route.py +++ b/app/test/route_tests/test_tpu_route.py @@ -10,6 +10,7 @@ "gflops": 5 } + @pytest.fixture(scope="module") async def tpu_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: @@ -22,6 +23,7 @@ async def tpu_created(base_url: str, headers: dict): assert response.status_code == 200 assert response.json().keys() == json.keys() + def test_tpu_post(tpu_created: Response): json = tpu_created.json() body_keys = list(tpu_creation_body.keys()) @@ -31,6 +33,7 @@ def test_tpu_post(tpu_created: Response): assert json.items() == tpu_creation_body.items() assert list(tpu_created.json().keys()) == body_keys + @pytest.mark.asyncio async def test_tpu_get_id(headers: dict, base_url: str, tpu_created: Response): json = tpu_created.json() @@ -41,6 +44,7 @@ async def test_tpu_get_id(headers: dict, base_url: str, tpu_created: Response): assert response.status_code == 200 assert response.json() == json + @pytest.mark.asyncio async def test_tpu_get(headers: dict, base_url: str, tpu_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: @@ -50,6 +54,7 @@ async def test_tpu_get(headers: dict, base_url: str, tpu_created: Response): for item in response.json(): assert list(item.keys()) == list(tpu_created.json().keys()) + @pytest.mark.asyncio async def test_tpu_put(headers: dict, base_url: str, tpu_created: Response): id = tpu_created.json()["id"] diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 2e86482..9335ab1 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -40,7 +40,7 @@ async def test_user_create_auth(base_url, headers): "password": "string", } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.post(f"/users/", headers=headers, json=body) + response = await ac.post("/users/", headers=headers, json=body) assert response.status_code == 200 del body["password"] assert body.items() <= response.json().items() @@ -67,7 +67,7 @@ async def test_user_get(user_created, headers, base_url): @pytest.mark.asyncio async def test_user_get_me(headers, base_url): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f"/users/me", headers=headers) + response = await ac.get("/users/me", headers=headers) json = response.json() assert response.status_code == 200 assert { @@ -106,6 +106,7 @@ async def test_user_put(base_url, headers, user_created): "id", } + @pytest.mark.asyncio async def test_user_put_me(base_url, headers): body = { @@ -114,7 +115,7 @@ async def test_user_put_me(base_url, headers): "last_name": "big boss", } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.put(f"/users/me", headers=headers, json=body) + response = await ac.put("/users/me", headers=headers, json=body) assert response.status_code == 200 assert body.items() <= response.json().items() assert set(response.json().keys()) == { @@ -124,4 +125,4 @@ async def test_user_put_me(base_url, headers): "first_name", "last_name", "id", - } \ No newline at end of file + } diff --git a/app/test/utils/overrides.py b/app/test/utils/overrides.py index c971747..5c0e0e6 100644 --- a/app/test/utils/overrides.py +++ b/app/test/utils/overrides.py @@ -1,8 +1,9 @@ from .test_db import TestSessionLocal -def override_get_db() : - try: - db = TestSessionLocal() - yield db - finally: - db.close() \ No newline at end of file + +def override_get_db(): + try: + db = TestSessionLocal() + yield db + finally: + db.close() diff --git a/app/test/utils/test_db.py b/app/test/utils/test_db.py index 25172f9..dc37c85 100644 --- a/app/test/utils/test_db.py +++ b/app/test/utils/test_db.py @@ -11,4 +11,4 @@ path=f"/{settings.POSTGRES_DB}_test", ) engine = create_engine(SQLALCHEMY_TEST_DATABASE_URI, pool_pre_ping=True) -TestSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) \ No newline at end of file +TestSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) From 2e1ae4a37a2d62a2b19b894729f076a6c2465d5c Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 7 Oct 2021 12:31:16 -0300 Subject: [PATCH 39/61] Applying clean code to test routes --- app/test/route_tests/conftest.py | 32 +-- .../route_tests/test_accuracy_type_route.py | 19 +- app/test/route_tests/test_cpu_route.py | 29 +- app/test/route_tests/test_datasets_route.py | 11 +- app/test/route_tests/test_login_route.py | 14 +- app/test/route_tests/test_submission_route.py | 145 ++-------- app/test/route_tests/test_task_route.py | 22 +- app/test/route_tests/test_tpu_route.py | 25 +- app/test/route_tests/test_user_route.py | 94 ++----- app/test/utils/constants.py | 266 ++++++++++++++++++ 10 files changed, 355 insertions(+), 302 deletions(-) create mode 100644 app/test/utils/constants.py diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index 7a126cc..02e7dc5 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -2,47 +2,25 @@ from httpx import AsyncClient from app.main import app -datasets_body = { - "name": "string", - "image": "string", - "description": "string", - "source": "string", - "identifier": "string", -} -datasets_keys = {*datasets_body, "id"} +from app.test.utils.constants import DATASETS_KEYS, DATASETS_BODY, TASK_KEYS, TASK @pytest.fixture(scope="session") async def datasets_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/datasets", json=datasets_body) + response = await ac.post("/datasets", json=DATASETS_BODY) yield response datasets_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/datasets/{datasets_id}") assert response.status_code == 200 - assert datasets_keys == set(response.json().keys()) - - -task = { - "name": "bar", - "image": "foo", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed \ - do eiusmod tempor incididunt ut labore et dolore magna aliqua. \ - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris\ - nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in \ - reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ - pariatur. Excepteur sint occaecat cupidatat non proident, sunt in \ - culpa qui officia deserunt mollit anim id est laborum.", -} - -task_keys = {**task, "id": 0, "number_of_benchmarks": 0} + assert DATASETS_KEYS == set(response.json().keys()) @pytest.fixture(scope="session") async def task_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/tasks", json=task) + response = await ac.post("/tasks", json=TASK) a = response.json() assert response.status_code == 200 assert response.json().keys() == a.keys() @@ -50,4 +28,4 @@ async def task_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/tasks/{a['id']}") assert response.status_code == 200 - assert response.json().keys() == task_keys.keys() + assert response.json().keys() == TASK_KEYS.keys() diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 8807318..8085c9c 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -2,32 +2,25 @@ from httpx import AsyncClient, Response from app.main import app - - -post_body = { - "name": "Foo", - "description": "foobar", -} -keys = {*post_body, "id"} -keys_get = {*keys, "updated_at", "created_at"} +from app.test.utils.constants import ACCURACY_BODY, ACCURACY_KEYS_GET, ACCURACY_KEYS @pytest.fixture(scope="module") async def accuracy_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/accuracy_types", json=post_body) + response = await ac.post("/accuracy_types", json=ACCURACY_BODY) yield response accuracy_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/accuracy_types/{accuracy_id}") assert response.status_code == 200 - assert keys == set(response.json().keys()) + assert ACCURACY_KEYS == set(response.json().keys()) def test_accuracy_post(accuracy_created: Response): assert accuracy_created.status_code == 200 - assert accuracy_created.json().items() >= post_body.items() - assert set(accuracy_created.json().keys()) == keys + assert accuracy_created.json().items() >= ACCURACY_BODY.items() + assert set(accuracy_created.json().keys()) == ACCURACY_KEYS @pytest.mark.asyncio @@ -35,7 +28,7 @@ async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/accuracy_types/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert set(response.json()[0].keys()) == keys_get + assert set(response.json()[0].keys()) == ACCURACY_KEYS_GET @pytest.mark.asyncio diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index b8ab81c..fcc5c92 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -2,37 +2,25 @@ from httpx import AsyncClient, Response from app.main import app - -post_body = { - "name": "string", - "number_of_cores": 0, - "frequency": 0, - "fp32_per_cycle": 0, - "transistors": 0, - "tdp": 0, - "gflops": 0, - "year": 0, - "die_size": 0, -} -keys = {*post_body, "id"} +from app.test.utils.constants import CPU_BODY, CPU_KEYS, CPU_NEW @pytest.fixture(scope="module") async def cpu_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/cpus", json=post_body) + response = await ac.post("/cpus", json=CPU_BODY) yield response cpu_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/cpus/{cpu_id}") assert response.status_code == 200 - assert keys == set(response.json().keys()) + assert CPU_KEYS == set(response.json().keys()) def test_cpu_post(cpu_created: Response): assert cpu_created.status_code == 200 - assert cpu_created.json().items() >= post_body.items() - assert set(cpu_created.json().keys()) == keys + assert cpu_created.json().items() >= CPU_BODY.items() + assert set(cpu_created.json().keys()) == CPU_KEYS @pytest.mark.asyncio @@ -40,7 +28,7 @@ async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/cpus/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert set(response.json()[0].keys()) == keys + assert set(response.json()[0].keys()) == CPU_KEYS @pytest.mark.asyncio @@ -57,8 +45,7 @@ async def test_cpu_get_id(base_url: str, headers: dict, cpu_created: Response): async def test_cpu_put(base_url: str, headers: dict, cpu_created: Response): cpu_json = cpu_created.json() cpu_id = cpu_json["id"] - put_json = {**post_body, "year": 2020, "transistors": 3333} async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.put(f"/cpus/{cpu_id}", json=put_json) + response = await ac.put(f"/cpus/{cpu_id}", json=CPU_NEW) assert response.status_code == 200 - assert {**put_json, "id": cpu_id} == response.json() + assert {**CPU_NEW, "id": cpu_id} == response.json() diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index 87f3ba9..afad21b 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -2,13 +2,13 @@ from httpx import AsyncClient, Response from app.main import app -from .conftest import datasets_body, datasets_keys +from app.test.utils.constants import DATASETS_BODY, DATASETS_KEYS def test_datasets_post(datasets_created: Response): assert datasets_created.status_code == 200 - assert datasets_created.json().items() >= datasets_body.items() - assert set(datasets_created.json().keys()) == datasets_keys + assert datasets_created.json().items() >= DATASETS_BODY.items() + assert set(datasets_created.json().keys()) == DATASETS_KEYS @pytest.mark.asyncio @@ -16,7 +16,7 @@ async def test_datasets_get(headers: dict, base_url: str, datasets_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/datasets/?skip=0&limit=1", headers=headers) assert response.status_code == 200 - assert set(response.json()[0].keys()) == datasets_keys + assert set(response.json()[0].keys()) == DATASETS_KEYS @pytest.mark.asyncio @@ -36,10 +36,11 @@ async def test_datasets_put(base_url: str, headers: dict, datasets_created: Resp datasets_json = datasets_created.json() datasets_id = datasets_json["id"] put_json = { - **datasets_body, + **DATASETS_BODY, "description": "i changed my description because i want", "source": "example", } + print(put_json) async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/datasets/{datasets_id}", json=put_json) assert response.status_code == 200 diff --git a/app/test/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py index 99d598b..c8f4199 100644 --- a/app/test/route_tests/test_login_route.py +++ b/app/test/route_tests/test_login_route.py @@ -2,7 +2,7 @@ from httpx import AsyncClient from app.main import app -from app.settings import settings +from app.test.utils.constants import LOGIN_EXPECTED_JSON @pytest.mark.asyncio @@ -11,15 +11,9 @@ async def test_test_token_route(headers, base_url): response = await ac.post("/login/test-token", headers=headers) assert response.status_code == 200 json = response.json() - expected_json = { - "email": settings.FIRST_SUPERUSER, - "is_active": True, - "role": "super_admin", - "first_name": None, - "last_name": None, - } - assert json.items() >= expected_json.items() - assert set(json.keys()) == {*expected_json, "id"} + + assert json.items() >= LOGIN_EXPECTED_JSON.items() + assert set(json.keys()) == {*LOGIN_EXPECTED_JSON, "id"} # password-recovery and reset-password routes depends on sending email. diff --git a/app/test/route_tests/test_submission_route.py b/app/test/route_tests/test_submission_route.py index 8694f71..b07e477 100644 --- a/app/test/route_tests/test_submission_route.py +++ b/app/test/route_tests/test_submission_route.py @@ -2,127 +2,32 @@ from httpx import AsyncClient, Response from app.main import app - -submission_body = { - "title": "foo", - "link": "bar", - "code_link": "foobar", - "publication_date": "2021-09-09", - "authors": [ - "bar foo" - ], - "models": [ - { - "name": "foo", - "task": "foofoo", - "dataset": "foobar", - "cpu": "bar foo", - "gpu": "bar bar", - "tpu": "bar", - "gflops": 3, - "multiply_adds": 2, - "number_of_parameters": 20, - "training_time": 30, - "epochs": 5, - "extra_training_data": True, - "accuracies": [ - { - "accuracy_type": "foo", - "value": 0.1 - } - ], - "number_of_gpus": 3, - "number_of_cpus": 1, - "number_of_tpus": 2, - "extra_training_time": False - } - ] -} - -submission_new = { - "title": "foo", - "link": "bar", - "code_link": "foobar", - "publication_date": "2021-09-09", - "authors": [ - "bar foo" - ], - "models": [ - { - "name": "foo", - "task": "foofoo", - "dataset": "foobar", - "cpu": "bar foo", - "gpu": "bar bar", - "tpu": "bar", - "gflops": 3, - "multiply_adds": 2, - "number_of_parameters": 20, - "training_time": 30, - "epochs": 5, - "extra_training_data": True, - "accuracies": [ - { - "accuracy_type": "foo", - "value": 0.1 - } - ], - "number_of_gpus": 3, - "number_of_cpus": 1, - "number_of_tpus": 2, - "extra_training_time": False - } - ] -} - -submission_keys = { - "data": {**submission_body}, - "paper_id": 0, - "owner_id": 0, - "reviewer_id": 0, - "status": "pending", - "id": 0, - "created_at": "2021-09-09T23:17:57.529Z", - "updated_at": "2021-09-09T23:17:57.529Z" - } - -msg_res = { - "body": "test foo bar", - "id": 0, - "author_id": 0, - "submission_id": 0, - "author": { - "email": "user@example.com", - "is_active": True, - "role": "default", - "first_name": "string", - "last_name": "string", - "id": 0 - }, - "type": "string" -} +from app.test.utils.constants import SUBMISSION_NEW, \ + SUBMISSION_BODY, \ + SUBMISSION_KEYS, \ + SUBMISSION_MSG_RES @pytest.fixture(scope='module') async def submission_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post('/submissions', json=submission_body) + response = await ac.post('/submissions', json=SUBMISSION_BODY) yield response.json() assert response.status_code == 200 - assert response.json().keys() == submission_keys.keys() + assert response.json().keys() == SUBMISSION_KEYS.keys() async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f'/submissions/{response.json()["id"]}') assert response.status_code == 200 - assert response.json().keys() == submission_keys.keys() + assert response.json().keys() == SUBMISSION_KEYS.keys() def test_submission_post(submission_created: Response): created = submission_created['data'] - for key in submission_body.keys(): - assert submission_body[key] == created[key] + for key in SUBMISSION_BODY.keys(): + assert SUBMISSION_BODY[key] == created[key] @pytest.mark.asyncio @@ -132,8 +37,8 @@ async def test_submission_get_id(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}') assert response.status_code == 200 - assert response.json().keys() == submission_keys.keys() - assert response.json()['data'] == submission_body + assert response.json().keys() == SUBMISSION_KEYS.keys() + assert response.json()['data'] == SUBMISSION_BODY @pytest.mark.asyncio @@ -143,8 +48,8 @@ async def test_submission_get(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get('/submissions') assert response.status_code == 200 - assert response.json()[0].keys() == submission_keys.keys() - assert response.json()[0]['data'] == submission_body + assert response.json()[0].keys() == SUBMISSION_KEYS.keys() + assert response.json()[0]['data'] == SUBMISSION_BODY @pytest.mark.asyncio @@ -155,8 +60,8 @@ async def test_submission_status_put(base_url: str, response = await ac.put(f'/submissions/{submission_created["id"]}/status', json={"status": "declined"}) assert response.status_code == 200 - assert response.json().keys() == submission_keys.keys() - assert response.json()['data'] == submission_body + assert response.json().keys() == SUBMISSION_KEYS.keys() + assert response.json()['data'] == SUBMISSION_BODY assert response.json()['status'] == 'declined' @@ -166,10 +71,10 @@ async def test_submission_put(base_url: str, submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f'/submissions/{submission_created["id"]}', - json=submission_new) + json=SUBMISSION_NEW) assert response.status_code == 200 - assert response.json().keys() == submission_keys.keys() - assert response.json()['data'] == submission_new + assert response.json().keys() == SUBMISSION_KEYS.keys() + assert response.json()['data'] == SUBMISSION_NEW @pytest.mark.asyncio @@ -178,11 +83,11 @@ async def test_submission_message_post(base_url: str, submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post(f'/submissions/{submission_created["id"]}/messages', - json={'message': msg_res['body']}) + json={'message': SUBMISSION_MSG_RES['body']}) assert response.status_code == 200 - assert response.json().keys() == msg_res.keys() - assert response.json()['body'] == msg_res['body'] - assert response.json()['author'].keys() == msg_res['author'].keys() + assert response.json().keys() == SUBMISSION_MSG_RES.keys() + assert response.json()['body'] == SUBMISSION_MSG_RES['body'] + assert response.json()['author'].keys() == SUBMISSION_MSG_RES['author'].keys() @pytest.mark.asyncio @@ -192,6 +97,6 @@ async def test_submission_message_get(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}/messages') assert response.status_code == 200 - assert response.json()[0].keys() == msg_res.keys() - assert response.json()[0]['body'] == msg_res['body'] - assert response.json()[0]['author'].keys() == msg_res['author'].keys() + assert response.json()[0].keys() == SUBMISSION_MSG_RES.keys() + assert response.json()[0]['body'] == SUBMISSION_MSG_RES['body'] + assert response.json()[0]['author'].keys() == SUBMISSION_MSG_RES['author'].keys() diff --git a/app/test/route_tests/test_task_route.py b/app/test/route_tests/test_task_route.py index 76697bb..cb31d45 100644 --- a/app/test/route_tests/test_task_route.py +++ b/app/test/route_tests/test_task_route.py @@ -2,20 +2,14 @@ from httpx import AsyncClient, Response from app.main import app -from .conftest import task, task_keys - -new_task = { - "name": "foo", - "image": "bar", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", -} +from app.test.utils.constants import TASK_KEYS, TASK, NEW_TASK def test_task_creation(task_created: Response): json = task_created.json() - assert json.keys() == task_keys.keys() - for key in task: - assert json[key] == task[key] + assert json.keys() == TASK_KEYS.keys() + for key in TASK: + assert json[key] == TASK[key] @pytest.mark.asyncio @@ -32,9 +26,9 @@ async def test_task_put(base_url: str, headers: dict, task_created: Response): res = task_created.json() async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.put(f"/tasks/{res['id']}", json=new_task) + response = await ac.put(f"/tasks/{res['id']}", json=NEW_TASK) json = response.json() assert response.status_code == 200 - for key in new_task.keys(): - assert new_task[key] == json[key] - assert json.keys() == task_keys.keys() + for key in NEW_TASK.keys(): + assert NEW_TASK[key] == json[key] + assert json.keys() == TASK_KEYS.keys() diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py index dd24816..521fb30 100644 --- a/app/test/route_tests/test_tpu_route.py +++ b/app/test/route_tests/test_tpu_route.py @@ -2,19 +2,13 @@ from httpx import AsyncClient, Response from app.main import app - -tpu_creation_body = { - "name": "foobar", - "transistors": 10, - "tdp": 20, - "gflops": 5 -} +from app.test.utils.constants import TPU_BODY, TPU_NEW @pytest.fixture(scope="module") async def tpu_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/tpus", json=tpu_creation_body) + response = await ac.post("/tpus", json=TPU_BODY) yield response json = response.json() tpu_id = json["id"] @@ -26,11 +20,11 @@ async def tpu_created(base_url: str, headers: dict): def test_tpu_post(tpu_created: Response): json = tpu_created.json() - body_keys = list(tpu_creation_body.keys()) + body_keys = list(TPU_BODY.keys()) body_keys.append('id') assert tpu_created.status_code == 200 assert json.pop('id', None) == 1 - assert json.items() == tpu_creation_body.items() + assert json.items() == TPU_BODY.items() assert list(tpu_created.json().keys()) == body_keys @@ -58,13 +52,8 @@ async def test_tpu_get(headers: dict, base_url: str, tpu_created: Response): @pytest.mark.asyncio async def test_tpu_put(headers: dict, base_url: str, tpu_created: Response): id = tpu_created.json()["id"] - new_json = { - "name": "barfoo", - "transistors": 50, - "tdp": 21, - "gflops": 3 - } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.put(f"/tpus/{id}", json=new_json) + response = await ac.put(f"/tpus/{id}", json=TPU_NEW) assert response.status_code == 200 - assert {**new_json, "id": id} == response.json() + assert {**TPU_NEW, "id": id} == response.json() diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 9335ab1..9ffad95 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -3,55 +3,35 @@ from app.main import app from app.settings import settings +from app.test.utils.constants import USER_BODY, \ + USER_KEYS, \ + USER_NEW, \ + USER_BODY_AUTH, \ + USER_SUPERUSER_BODY,\ + USER_SUPERUSER_NEW @pytest.fixture(scope="module") async def user_created(base_url): - body = { - "email": "barbar@foofoo.com", - "first_name": "Foo", - "last_name": "bar", - "password": "foobar", - } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.post("/users/open", json=body) + response = await ac.post("/users/open", json=USER_BODY) return response def test_user_create(user_created): assert user_created.status_code == 200 - assert set(user_created.json().keys()) == { - "email", - "is_active", - "role", - "first_name", - "last_name", - "id", - } + assert set(user_created.json().keys()) == USER_KEYS @pytest.mark.asyncio async def test_user_create_auth(base_url, headers): settings.EMAILS_ENABLED = False - body = { - "email": "user@example.com", - "first_name": "string", - "last_name": "string", - "password": "string", - } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.post("/users/", headers=headers, json=body) + response = await ac.post("/users/", headers=headers, json=USER_BODY_AUTH) assert response.status_code == 200 - del body["password"] - assert body.items() <= response.json().items() - assert set(response.json().keys()) == { - "email", - "is_active", - "role", - "first_name", - "last_name", - "id", - } + del USER_BODY_AUTH["password"] + assert USER_BODY_AUTH.items() <= response.json().items() + assert set(response.json().keys()) == USER_KEYS @pytest.mark.asyncio @@ -70,59 +50,25 @@ async def test_user_get_me(headers, base_url): response = await ac.get("/users/me", headers=headers) json = response.json() assert response.status_code == 200 - assert { - "email": settings.FIRST_SUPERUSER, - "role": "super_admin", - }.items() <= json.items() - assert set(json.keys()) == { - "email", - "is_active", - "role", - "first_name", - "last_name", - "id", - } + assert USER_SUPERUSER_BODY.items() <= json.items() + assert set(json.keys()) == USER_KEYS @pytest.mark.asyncio async def test_user_put(base_url, headers, user_created): user_json = user_created.json() user_id = user_json["id"] - body = { - "email": user_json["email"], - "first_name": "bazbazbaz", - "last_name": "foooooo", - } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.put(f"/users/{user_id}", headers=headers, json=body) + response = await ac.put(f"/users/{user_id}", headers=headers, json=USER_NEW) assert response.status_code == 200 - assert body.items() <= response.json().items() - assert set(response.json().keys()) == { - "email", - "is_active", - "role", - "first_name", - "last_name", - "id", - } + assert USER_NEW.items() <= response.json().items() + assert set(response.json().keys()) == USER_KEYS @pytest.mark.asyncio async def test_user_put_me(base_url, headers): - body = { - "email": settings.FIRST_SUPERUSER, - "first_name": "administrator", - "last_name": "big boss", - } async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.put("/users/me", headers=headers, json=body) + response = await ac.put("/users/me", headers=headers, json=USER_SUPERUSER_NEW) assert response.status_code == 200 - assert body.items() <= response.json().items() - assert set(response.json().keys()) == { - "email", - "is_active", - "role", - "first_name", - "last_name", - "id", - } + assert USER_SUPERUSER_NEW.items() <= response.json().items() + assert set(response.json().keys()) == USER_KEYS diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py new file mode 100644 index 0000000..533e673 --- /dev/null +++ b/app/test/utils/constants.py @@ -0,0 +1,266 @@ +from app.settings import settings + +''' +Test constants +''' +# ================================ +# BEGIN DATASETS CONSTANTS + +DATASETS_BODY = { + "name": "string", + "image": "string", + "description": "string", + "source": "string", + "identifier": "string", +} +DATASETS_KEYS = {*DATASETS_BODY, "id"} + +# END DATASETS CONSTANTS +# ================================ + +# ================================ +# BEGIN TASK CONSTANTS + +TASK = { + "name": "bar", + "image": "foo", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed \ + do eiusmod tempor incididunt ut labore et dolore magna aliqua. \ + Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris\ + nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in \ + reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ + pariatur. Excepteur sint occaecat cupidatat non proident, sunt in \ + culpa qui officia deserunt mollit anim id est laborum.", +} + +TASK_KEYS = {**TASK, "id": 0, "number_of_benchmarks": 0} + +NEW_TASK = { + "name": "foo", + "image": "bar", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", +} + +# END TASK CONSTANTS +# ================================ + +# ================================ +# BEGIN ACCURACY CONSTANTS + +ACCURACY_BODY = { + "name": "Foo", + "description": "foobar", +} +ACCURACY_KEYS = {*ACCURACY_BODY, "id"} + +ACCURACY_KEYS_GET = {*ACCURACY_KEYS, "updated_at", "created_at"} + +# END ACCURACY CONSTANTS +# ================================ + +# ================================ +# BEGIN CPU CONSTANTS + +CPU_BODY = { + "name": "string", + "number_of_cores": 0, + "frequency": 0, + "fp32_per_cycle": 0, + "transistors": 0, + "tdp": 0, + "gflops": 0, + "year": 0, + "die_size": 0, +} + +CPU_NEW = {**CPU_BODY, "year": 2020, "transistors": 3333} + +CPU_KEYS = {*CPU_BODY, "id"} + +# END CPU CONSTANTS +# ================================ + +# ================================ +# BEGIN LOGIN CONSTANTS + +LOGIN_EXPECTED_JSON = { + "email": settings.FIRST_SUPERUSER, + "is_active": True, + "role": "super_admin", + "first_name": None, + "last_name": None, +} + +# END LOGIN CONSTANTS +# ================================ + +# ================================ +# BEGIN SUBMISSION CONSTANTS + +SUBMISSION_BODY = { + "title": "foo", + "link": "bar", + "code_link": "foobar", + "publication_date": "2021-09-09", + "authors": [ + "bar foo" + ], + "models": [ + { + "name": "foo", + "task": "foofoo", + "dataset": "foobar", + "cpu": "bar foo", + "gpu": "bar bar", + "tpu": "bar", + "gflops": 3, + "multiply_adds": 2, + "number_of_parameters": 20, + "training_time": 30, + "epochs": 5, + "extra_training_data": True, + "accuracies": [ + { + "accuracy_type": "foo", + "value": 0.1 + } + ], + "number_of_gpus": 3, + "number_of_cpus": 1, + "number_of_tpus": 2, + "extra_training_time": False + } + ] +} + +SUBMISSION_NEW = { + "title": "foo", + "link": "bar", + "code_link": "foobar", + "publication_date": "2021-09-09", + "authors": [ + "bar foo" + ], + "models": [ + { + "name": "foo", + "task": "foofoo", + "dataset": "foobar", + "cpu": "bar foo", + "gpu": "bar bar", + "tpu": "bar", + "gflops": 3, + "multiply_adds": 2, + "number_of_parameters": 20, + "training_time": 30, + "epochs": 5, + "extra_training_data": True, + "accuracies": [ + { + "accuracy_type": "foo", + "value": 0.1 + } + ], + "number_of_gpus": 3, + "number_of_cpus": 1, + "number_of_tpus": 2, + "extra_training_time": False + } + ] +} + +SUBMISSION_KEYS = { + "data": {**SUBMISSION_BODY}, + "paper_id": 0, + "owner_id": 0, + "reviewer_id": 0, + "status": "pending", + "id": 0, + "created_at": "2021-09-09T23:17:57.529Z", + "updated_at": "2021-09-09T23:17:57.529Z" + } + +SUBMISSION_MSG_RES = { + "body": "test foo bar", + "id": 0, + "author_id": 0, + "submission_id": 0, + "author": { + "email": "user@example.com", + "is_active": True, + "role": "default", + "first_name": "string", + "last_name": "string", + "id": 0 + }, + "type": "string" +} + +# END SUBMISSION CONSTANTS +# ================================ + +# ================================ +# BEGIN TPU CONSTANTS + +TPU_BODY = { + "name": "foobar", + "transistors": 10, + "tdp": 20, + "gflops": 5 +} + +TPU_NEW = { + "name": "barfoo", + "transistors": 50, + "tdp": 21, + "gflops": 3 +} + +# END TPU CONSTANTS +# ================================ + +# ================================ +# BEGIN USER CONSTANTS + +USER_BODY = { + "email": "barbar@foofoo.com", + "first_name": "Foo", + "last_name": "bar", + "password": "foobar", +} + +USER_BODY_AUTH = { + "email": "user@example.com", + "first_name": "string", + "last_name": "string", + "password": "string", + } + +USER_SUPERUSER_BODY = { + "email": settings.FIRST_SUPERUSER, + "role": "super_admin", + } + +USER_KEYS = { + "email", + "is_active", + "role", + "first_name", + "last_name", + "id" + } + +USER_NEW = { + "email": USER_BODY["email"], + "first_name": "bazbazbaz", + "last_name": "foooooo", +} + +USER_SUPERUSER_NEW = { + "email": settings.FIRST_SUPERUSER, + "first_name": "administrator", + "last_name": "big boss", +} + +# END USER CONSTANTS +# ================================ From 296571f27b584508d0588d8bfbb85672b679cebe Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 7 Oct 2021 12:49:13 -0300 Subject: [PATCH 40/61] Add status constants to test files --- app/test/route_tests/conftest.py | 12 ++++++--- .../route_tests/test_accuracy_type_route.py | 15 ++++++----- app/test/route_tests/test_cpu_route.py | 12 ++++----- app/test/route_tests/test_datasets_route.py | 10 ++++---- app/test/route_tests/test_login_route.py | 4 +-- app/test/route_tests/test_submission_route.py | 25 ++++++++++--------- app/test/route_tests/test_task_route.py | 6 ++--- app/test/route_tests/test_tpu_route.py | 12 ++++----- app/test/route_tests/test_user_route.py | 15 +++++------ app/test/utils/constants.py | 16 ++++++++++++ 10 files changed, 76 insertions(+), 51 deletions(-) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index 02e7dc5..fbf27b6 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -2,7 +2,11 @@ from httpx import AsyncClient from app.main import app -from app.test.utils.constants import DATASETS_KEYS, DATASETS_BODY, TASK_KEYS, TASK +from app.test.utils.constants import DATASETS_KEYS,\ + DATASETS_BODY,\ + TASK_KEYS, \ + TASK, \ + SUCCESS @pytest.fixture(scope="session") @@ -13,7 +17,7 @@ async def datasets_created(base_url: str, headers: dict): datasets_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/datasets/{datasets_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert DATASETS_KEYS == set(response.json().keys()) @@ -22,10 +26,10 @@ async def task_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post("/tasks", json=TASK) a = response.json() - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == a.keys() yield response async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/tasks/{a['id']}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == TASK_KEYS.keys() diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 8085c9c..6ef0734 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -2,7 +2,10 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import ACCURACY_BODY, ACCURACY_KEYS_GET, ACCURACY_KEYS +from app.test.utils.constants import ACCURACY_BODY, \ + ACCURACY_KEYS_GET,\ + ACCURACY_KEYS, \ + SUCCESS @pytest.fixture(scope="module") @@ -13,12 +16,12 @@ async def accuracy_created(base_url: str, headers: dict): accuracy_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/accuracy_types/{accuracy_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert ACCURACY_KEYS == set(response.json().keys()) def test_accuracy_post(accuracy_created: Response): - assert accuracy_created.status_code == 200 + assert accuracy_created.status_code == SUCCESS assert accuracy_created.json().items() >= ACCURACY_BODY.items() assert set(accuracy_created.json().keys()) == ACCURACY_KEYS @@ -27,7 +30,7 @@ def test_accuracy_post(accuracy_created: Response): async def test_accuracy_get(headers: dict, base_url: str, accuracy_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/accuracy_types/?skip=0&limit=1", headers=headers) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == ACCURACY_KEYS_GET @@ -39,7 +42,7 @@ async def test_accuracy_get_id( accuracy_id = accuracy_json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/accuracy_types/{accuracy_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert accuracy_json == response.json() @@ -53,5 +56,5 @@ async def test_accuracy_put(base_url: str, headers: dict, accuracy_created: Resp } async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/accuracy_types/{accuracy_id}", json=put_json) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert {**put_json, "id": accuracy_id} == response.json() diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index fcc5c92..3b875cb 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -2,7 +2,7 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import CPU_BODY, CPU_KEYS, CPU_NEW +from app.test.utils.constants import CPU_BODY, CPU_KEYS, CPU_NEW, SUCCESS @pytest.fixture(scope="module") @@ -13,12 +13,12 @@ async def cpu_created(base_url: str, headers: dict): cpu_id = response.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/cpus/{cpu_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert CPU_KEYS == set(response.json().keys()) def test_cpu_post(cpu_created: Response): - assert cpu_created.status_code == 200 + assert cpu_created.status_code == SUCCESS assert cpu_created.json().items() >= CPU_BODY.items() assert set(cpu_created.json().keys()) == CPU_KEYS @@ -27,7 +27,7 @@ def test_cpu_post(cpu_created: Response): async def test_cpu_get(headers: dict, base_url: str, cpu_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/cpus/?skip=0&limit=1", headers=headers) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == CPU_KEYS @@ -37,7 +37,7 @@ async def test_cpu_get_id(base_url: str, headers: dict, cpu_created: Response): cpu_id = cpu_json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/cpus/{cpu_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert cpu_json == response.json() @@ -47,5 +47,5 @@ async def test_cpu_put(base_url: str, headers: dict, cpu_created: Response): cpu_id = cpu_json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/cpus/{cpu_id}", json=CPU_NEW) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert {**CPU_NEW, "id": cpu_id} == response.json() diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index afad21b..a0ed824 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -2,11 +2,11 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import DATASETS_BODY, DATASETS_KEYS +from app.test.utils.constants import DATASETS_BODY, DATASETS_KEYS, SUCCESS def test_datasets_post(datasets_created: Response): - assert datasets_created.status_code == 200 + assert datasets_created.status_code == SUCCESS assert datasets_created.json().items() >= DATASETS_BODY.items() assert set(datasets_created.json().keys()) == DATASETS_KEYS @@ -15,7 +15,7 @@ def test_datasets_post(datasets_created: Response): async def test_datasets_get(headers: dict, base_url: str, datasets_created: Response): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/datasets/?skip=0&limit=1", headers=headers) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == DATASETS_KEYS @@ -27,7 +27,7 @@ async def test_datasets_get_id( datasets_id = datasets_json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/datasets/{datasets_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert datasets_json == response.json() @@ -43,5 +43,5 @@ async def test_datasets_put(base_url: str, headers: dict, datasets_created: Resp print(put_json) async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/datasets/{datasets_id}", json=put_json) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert {**put_json, "id": datasets_id} == response.json() diff --git a/app/test/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py index c8f4199..55a441b 100644 --- a/app/test/route_tests/test_login_route.py +++ b/app/test/route_tests/test_login_route.py @@ -2,14 +2,14 @@ from httpx import AsyncClient from app.main import app -from app.test.utils.constants import LOGIN_EXPECTED_JSON +from app.test.utils.constants import LOGIN_EXPECTED_JSON, SUCCESS @pytest.mark.asyncio async def test_test_token_route(headers, base_url): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post("/login/test-token", headers=headers) - assert response.status_code == 200 + assert response.status_code == SUCCESS json = response.json() assert json.items() >= LOGIN_EXPECTED_JSON.items() diff --git a/app/test/route_tests/test_submission_route.py b/app/test/route_tests/test_submission_route.py index b07e477..9c84c52 100644 --- a/app/test/route_tests/test_submission_route.py +++ b/app/test/route_tests/test_submission_route.py @@ -2,10 +2,11 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import SUBMISSION_NEW, \ - SUBMISSION_BODY, \ - SUBMISSION_KEYS, \ - SUBMISSION_MSG_RES +from app.test.utils.constants import SUBMISSION_NEW, \ + SUBMISSION_BODY, \ + SUBMISSION_KEYS, \ + SUBMISSION_MSG_RES,\ + SUCCESS @pytest.fixture(scope='module') @@ -14,13 +15,13 @@ async def submission_created(base_url: str, headers: dict): response = await ac.post('/submissions', json=SUBMISSION_BODY) yield response.json() - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_KEYS.keys() async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f'/submissions/{response.json()["id"]}') - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_KEYS.keys() @@ -36,7 +37,7 @@ async def test_submission_get_id(base_url: str, submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}') - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_KEYS.keys() assert response.json()['data'] == SUBMISSION_BODY @@ -47,7 +48,7 @@ async def test_submission_get(base_url: str, submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get('/submissions') - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json()[0].keys() == SUBMISSION_KEYS.keys() assert response.json()[0]['data'] == SUBMISSION_BODY @@ -59,7 +60,7 @@ async def test_submission_status_put(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f'/submissions/{submission_created["id"]}/status', json={"status": "declined"}) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_KEYS.keys() assert response.json()['data'] == SUBMISSION_BODY assert response.json()['status'] == 'declined' @@ -72,7 +73,7 @@ async def test_submission_put(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f'/submissions/{submission_created["id"]}', json=SUBMISSION_NEW) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_KEYS.keys() assert response.json()['data'] == SUBMISSION_NEW @@ -84,7 +85,7 @@ async def test_submission_message_post(base_url: str, async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post(f'/submissions/{submission_created["id"]}/messages', json={'message': SUBMISSION_MSG_RES['body']}) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == SUBMISSION_MSG_RES.keys() assert response.json()['body'] == SUBMISSION_MSG_RES['body'] assert response.json()['author'].keys() == SUBMISSION_MSG_RES['author'].keys() @@ -96,7 +97,7 @@ async def test_submission_message_get(base_url: str, submission_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f'/submissions/{submission_created["id"]}/messages') - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json()[0].keys() == SUBMISSION_MSG_RES.keys() assert response.json()[0]['body'] == SUBMISSION_MSG_RES['body'] assert response.json()[0]['author'].keys() == SUBMISSION_MSG_RES['author'].keys() diff --git a/app/test/route_tests/test_task_route.py b/app/test/route_tests/test_task_route.py index cb31d45..065b9cc 100644 --- a/app/test/route_tests/test_task_route.py +++ b/app/test/route_tests/test_task_route.py @@ -2,7 +2,7 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import TASK_KEYS, TASK, NEW_TASK +from app.test.utils.constants import TASK_KEYS, TASK, NEW_TASK, SUCCESS def test_task_creation(task_created: Response): @@ -17,7 +17,7 @@ async def test_task_get(base_url: str, headers: dict, task_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get("/tasks") res_json = response.json() - assert response.status_code == 200 + assert response.status_code == SUCCESS assert isinstance(res_json, list) @@ -28,7 +28,7 @@ async def test_task_put(base_url: str, headers: dict, task_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/tasks/{res['id']}", json=NEW_TASK) json = response.json() - assert response.status_code == 200 + assert response.status_code == SUCCESS for key in NEW_TASK.keys(): assert NEW_TASK[key] == json[key] assert json.keys() == TASK_KEYS.keys() diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py index 521fb30..0dc21df 100644 --- a/app/test/route_tests/test_tpu_route.py +++ b/app/test/route_tests/test_tpu_route.py @@ -2,7 +2,7 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import TPU_BODY, TPU_NEW +from app.test.utils.constants import TPU_BODY, TPU_NEW, SUCCESS @pytest.fixture(scope="module") @@ -14,7 +14,7 @@ async def tpu_created(base_url: str, headers: dict): tpu_id = json["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.delete(f"/tpus/{tpu_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json().keys() == json.keys() @@ -22,7 +22,7 @@ def test_tpu_post(tpu_created: Response): json = tpu_created.json() body_keys = list(TPU_BODY.keys()) body_keys.append('id') - assert tpu_created.status_code == 200 + assert tpu_created.status_code == SUCCESS assert json.pop('id', None) == 1 assert json.items() == TPU_BODY.items() assert list(tpu_created.json().keys()) == body_keys @@ -35,7 +35,7 @@ async def test_tpu_get_id(headers: dict, base_url: str, tpu_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/tpus/{tpu_id}") - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json() == json @@ -43,7 +43,7 @@ async def test_tpu_get_id(headers: dict, base_url: str, tpu_created: Response): async def test_tpu_get(headers: dict, base_url: str, tpu_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get("/tpus") - assert response.status_code == 200 + assert response.status_code == SUCCESS for item in response.json(): assert list(item.keys()) == list(tpu_created.json().keys()) @@ -55,5 +55,5 @@ async def test_tpu_put(headers: dict, base_url: str, tpu_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/tpus/{id}", json=TPU_NEW) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert {**TPU_NEW, "id": id} == response.json() diff --git a/app/test/route_tests/test_user_route.py b/app/test/route_tests/test_user_route.py index 9ffad95..8bfdb3f 100644 --- a/app/test/route_tests/test_user_route.py +++ b/app/test/route_tests/test_user_route.py @@ -8,7 +8,8 @@ USER_NEW, \ USER_BODY_AUTH, \ USER_SUPERUSER_BODY,\ - USER_SUPERUSER_NEW + USER_SUPERUSER_NEW, \ + SUCCESS @pytest.fixture(scope="module") @@ -19,7 +20,7 @@ async def user_created(base_url): def test_user_create(user_created): - assert user_created.status_code == 200 + assert user_created.status_code == SUCCESS assert set(user_created.json().keys()) == USER_KEYS @@ -28,7 +29,7 @@ async def test_user_create_auth(base_url, headers): settings.EMAILS_ENABLED = False async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.post("/users/", headers=headers, json=USER_BODY_AUTH) - assert response.status_code == 200 + assert response.status_code == SUCCESS del USER_BODY_AUTH["password"] assert USER_BODY_AUTH.items() <= response.json().items() assert set(response.json().keys()) == USER_KEYS @@ -40,7 +41,7 @@ async def test_user_get(user_created, headers, base_url): user_id = user_json["id"] async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get(f"/users/{user_id}", headers=headers) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert response.json() == user_json @@ -49,7 +50,7 @@ async def test_user_get_me(headers, base_url): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/users/me", headers=headers) json = response.json() - assert response.status_code == 200 + assert response.status_code == SUCCESS assert USER_SUPERUSER_BODY.items() <= json.items() assert set(json.keys()) == USER_KEYS @@ -60,7 +61,7 @@ async def test_user_put(base_url, headers, user_created): user_id = user_json["id"] async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.put(f"/users/{user_id}", headers=headers, json=USER_NEW) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert USER_NEW.items() <= response.json().items() assert set(response.json().keys()) == USER_KEYS @@ -69,6 +70,6 @@ async def test_user_put(base_url, headers, user_created): async def test_user_put_me(base_url, headers): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.put("/users/me", headers=headers, json=USER_SUPERUSER_NEW) - assert response.status_code == 200 + assert response.status_code == SUCCESS assert USER_SUPERUSER_NEW.items() <= response.json().items() assert set(response.json().keys()) == USER_KEYS diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 533e673..124a9bb 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -3,6 +3,22 @@ ''' Test constants ''' + +# ================================ +# BEGIN STATUS_CODE CONSTANTS + +SUCCESS = 200 +NOT_FOUND = 404 +BAD_REQUEST = 400 +UNAUTHORIZED = 401 +FORBIDDEN = 403 +METHOD_NOT_ALLOWED = 405 +SERVER_ERROR = 500 + +# END STATUS_CODE CONSTANTS +# ================================ + + # ================================ # BEGIN DATASETS CONSTANTS From d40146a390fc23cc1e2f2a1f1f332f6e2cd6be3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 17 Oct 2021 18:14:24 -0300 Subject: [PATCH 41/61] test paper post endpoint --- app/test/route_tests/conftest.py | 26 ++++++++++++++++---- app/test/route_tests/test_paper_route.py | 16 ++++++++++++ app/test/utils/constants.py | 31 ++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 app/test/route_tests/test_paper_route.py diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index fbf27b6..f78dec5 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -2,11 +2,15 @@ from httpx import AsyncClient from app.main import app -from app.test.utils.constants import DATASETS_KEYS,\ - DATASETS_BODY,\ - TASK_KEYS, \ - TASK, \ - SUCCESS +from app.test.utils.constants import ( + DATASETS_KEYS, + DATASETS_BODY, + TASK_KEYS, + TASK, + PAPER_BODY, + PAPER_KEYS, + SUCCESS, +) @pytest.fixture(scope="session") @@ -33,3 +37,15 @@ async def task_created(base_url: str, headers: dict): response = await ac.delete(f"/tasks/{a['id']}") assert response.status_code == SUCCESS assert response.json().keys() == TASK_KEYS.keys() + + +@pytest.fixture(scope="session") +async def paper_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/papers", json=PAPER_BODY) + yield response + # paper_id = response.json()["id"] + # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + # response = await ac.delete(f"/paper/{paper_id}") + # assert response.status_code == SUCCESS + # assert PAPER_KEYS == set(response.json().keys()) diff --git a/app/test/route_tests/test_paper_route.py b/app/test/route_tests/test_paper_route.py new file mode 100644 index 0000000..81e5662 --- /dev/null +++ b/app/test/route_tests/test_paper_route.py @@ -0,0 +1,16 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + PAPER_GET, + PAPER_KEYS, + PAPER_KEYS_POST, + SUCCESS, +) + + +def test_paper_post(paper_created: Response) -> None: + assert paper_created.status_code == SUCCESS + assert paper_created.json().items() >= PAPER_GET.items() + assert set(paper_created.json().keys()) == PAPER_KEYS_POST diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 124a9bb..c480aba 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -280,3 +280,34 @@ # END USER CONSTANTS # ================================ + +# ================================ +# BEGIN PAPER CONSTANTS + +PAPER_GET = { + "title": "foo", + "link": "bar", + "code_link": "baz", + "publication_date": "2021-10-17", + "authors": [], + # "models": [] +} + +PAPER_BODY = { + **PAPER_GET, + "models": [] +} + +PAPER_KEYS = {*PAPER_GET, "id"} + +PAPER_KEYS_POST = { + *PAPER_KEYS, + "is_public", + "updated_at", + "identifier", + "link", + "created_at" +} + +# END PAPER CONSTANTS +# ================================ \ No newline at end of file From 242c1468745f82c99fe1d33b58971ebfebfd24be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 17 Oct 2021 19:32:13 -0300 Subject: [PATCH 42/61] test paper get endpoint --- app/test/route_tests/test_paper_route.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/test/route_tests/test_paper_route.py b/app/test/route_tests/test_paper_route.py index 81e5662..3ee1ec6 100644 --- a/app/test/route_tests/test_paper_route.py +++ b/app/test/route_tests/test_paper_route.py @@ -14,3 +14,18 @@ def test_paper_post(paper_created: Response) -> None: assert paper_created.status_code == SUCCESS assert paper_created.json().items() >= PAPER_GET.items() assert set(paper_created.json().keys()) == PAPER_KEYS_POST + +@pytest.mark.asyncio +async def test_paper_get(headers: dict, base_url: str): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/papers/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == PAPER_KEYS + +@pytest.mark.asyncio +async def test_paper_get_id(base_url: str, headers: dict, paper_created: Response): + paper_id = paper_created.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/papers/{paper_id}") + assert response.status_code == SUCCESS + assert { **PAPER_GET, "id": paper_id} == response.json() \ No newline at end of file From bbf4c84f22ff80f7df4466774ec68b4591886d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 17 Oct 2021 20:39:16 -0300 Subject: [PATCH 43/61] test paper put endpoint --- app/test/route_tests/test_paper_route.py | 21 ++++++++++++++++++--- app/test/utils/constants.py | 6 ++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/app/test/route_tests/test_paper_route.py b/app/test/route_tests/test_paper_route.py index 3ee1ec6..17b8c8c 100644 --- a/app/test/route_tests/test_paper_route.py +++ b/app/test/route_tests/test_paper_route.py @@ -6,6 +6,7 @@ PAPER_GET, PAPER_KEYS, PAPER_KEYS_POST, + PAPER_NEW, SUCCESS, ) @@ -15,17 +16,31 @@ def test_paper_post(paper_created: Response) -> None: assert paper_created.json().items() >= PAPER_GET.items() assert set(paper_created.json().keys()) == PAPER_KEYS_POST + @pytest.mark.asyncio -async def test_paper_get(headers: dict, base_url: str): +async def test_paper_get(headers: dict, base_url: str) -> None: async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/papers/?skip=0&limit=1", headers=headers) assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == PAPER_KEYS + @pytest.mark.asyncio -async def test_paper_get_id(base_url: str, headers: dict, paper_created: Response): +async def test_paper_get_id( + base_url: str, headers: dict, paper_created: Response +) -> None: paper_id = paper_created.json()["id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/papers/{paper_id}") assert response.status_code == SUCCESS - assert { **PAPER_GET, "id": paper_id} == response.json() \ No newline at end of file + assert {**PAPER_GET, "id": paper_id} == response.json() + + +@pytest.mark.asyncio +async def test_cpu_put(base_url: str, headers: dict, paper_created: Response) -> None: + paper_json = paper_created.json() + paper_id = paper_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/papers/{paper_id}", json=PAPER_NEW) + assert response.status_code == SUCCESS + assert {**PAPER_NEW, "id": paper_id} == response.json() diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index c480aba..c1d8eac 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -309,5 +309,11 @@ "created_at" } +PAPER_NEW = { + **PAPER_GET, + "title": "foofoo", + "code_link": "barbar" +} + # END PAPER CONSTANTS # ================================ \ No newline at end of file From 2fc8e2f42418ec5a679baa616e367c479ea04ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 17 Oct 2021 20:42:51 -0300 Subject: [PATCH 44/61] test papers delete endpoint --- app/test/route_tests/conftest.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index f78dec5..d000ac5 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -44,8 +44,8 @@ async def paper_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post("/papers", json=PAPER_BODY) yield response - # paper_id = response.json()["id"] - # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - # response = await ac.delete(f"/paper/{paper_id}") - # assert response.status_code == SUCCESS - # assert PAPER_KEYS == set(response.json().keys()) + paper_id = response.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.delete(f"/papers/{paper_id}") + assert response.status_code == SUCCESS + assert PAPER_KEYS == set(response.json().keys()) From b57cdc4e59ad52efec0a3d53a07d796be0a87959 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Thu, 21 Oct 2021 15:17:38 -0300 Subject: [PATCH 45/61] fixing test and supressing unwanted logs --- app/test/conftest.py | 7 +++++++ app/test/route_tests/test_datasets_route.py | 6 +++++- app/test/utils/test_db.py | 10 +++++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/test/conftest.py b/app/test/conftest.py index d2a8769..340efc9 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -2,6 +2,8 @@ import asyncio from httpx import AsyncClient from sqlalchemy_utils import create_database, database_exists +from os import system, name +from time import sleep from app.database.base import Base from app.settings import settings @@ -22,6 +24,11 @@ Base.metadata.create_all(bind=engine) init_db(TestSessionLocal()) +if name == 'nt': + _ = system('cls') + +else: + _ = system('clear') @pytest.fixture(scope="session") def event_loop(): diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index a0ed824..3fc28f5 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -35,13 +35,17 @@ async def test_datasets_get_id( async def test_datasets_put(base_url: str, headers: dict, datasets_created: Response): datasets_json = datasets_created.json() datasets_id = datasets_json["id"] + print(datasets_id) put_json = { - **DATASETS_BODY, + "name": "foo", + "image": "bar", + "identifier": "foo bar", "description": "i changed my description because i want", "source": "example", } print(put_json) async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/datasets/{datasets_id}", json=put_json) + print(response.json()) assert response.status_code == SUCCESS assert {**put_json, "id": datasets_id} == response.json() diff --git a/app/test/utils/test_db.py b/app/test/utils/test_db.py index dc37c85..556bbc2 100644 --- a/app/test/utils/test_db.py +++ b/app/test/utils/test_db.py @@ -2,6 +2,7 @@ from sqlalchemy.engine import create_engine from sqlalchemy.orm.session import sessionmaker from app.settings import settings +import logging SQLALCHEMY_TEST_DATABASE_URI = PostgresDsn.build( scheme="postgresql", @@ -10,5 +11,12 @@ host=settings.POSTGRES_SERVER, path=f"/{settings.POSTGRES_DB}_test", ) -engine = create_engine(SQLALCHEMY_TEST_DATABASE_URI, pool_pre_ping=True) + +engine = create_engine(SQLALCHEMY_TEST_DATABASE_URI, pool_pre_ping=True, logging_name='sqlalchemy.engine') TestSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +levels = [logging.ERROR, logging.DEBUG, logging.INFO, logging.WARNING, logging.CRITICAL] +for i in range(len(levels)): + sqla_logger = logging.getLogger('sqlalchemy.engine') + sqla_logger.propagate = False + sqla_logger.setLevel(levels[i]) + sqla_logger.addHandler(logging.FileHandler(f'/tmp/sqla_{i}.log')) From e3f635e2659fddde812ca5529ac8c3137c54334c Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Sun, 31 Oct 2021 15:08:21 -0300 Subject: [PATCH 46/61] Add test environment for initial seeding data. --- Makefile | 8 +++++ app/test/conftest.py | 7 +++++ app/test/utils/initial_seed.sql | 52 +++++++++++++++++++++++++++++++++ test.docker-compose.yml | 38 ++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 Makefile create mode 100644 app/test/utils/initial_seed.sql create mode 100644 test.docker-compose.yml diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7d91e85 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +include .env + +.PHONY: up-test + +test: + (sudo docker-compose -f test.docker-compose.yml up -d && \ + sudo docker-compose -f test.docker-compose.yml exec backend-tests pytest);\ + sudo docker-compose -f test.docker-compose.yml down diff --git a/app/test/conftest.py b/app/test/conftest.py index 340efc9..1ccce0c 100644 --- a/app/test/conftest.py +++ b/app/test/conftest.py @@ -18,12 +18,19 @@ from .utils.test_db import TestSessionLocal app.dependency_overrides[get_db] = override_get_db + if not database_exists(SQLALCHEMY_TEST_DATABASE_URI): create_database(SQLALCHEMY_TEST_DATABASE_URI) + Base.metadata.drop_all(bind=engine) Base.metadata.create_all(bind=engine) init_db(TestSessionLocal()) +with open('app/test/utils/initial_seed.sql') as sql_file: + for statement in sql_file.read().split(';'): + if len(statement.strip()) > 0: + engine.execute(statement + ';') + if name == 'nt': _ = system('cls') diff --git a/app/test/utils/initial_seed.sql b/app/test/utils/initial_seed.sql new file mode 100644 index 0000000..6bc457a --- /dev/null +++ b/app/test/utils/initial_seed.sql @@ -0,0 +1,52 @@ + +insert into "task" ("created_at", "description", "id", "identifier", "image", "name", "updated_at") values ('2021-07-02 02:08:29.864713', 'Image Classification is a fundamental task that attempts to comprehend an entire image as a whole. The goal is to classify the image by assigning it to a specific label. Typically, Image Classification refers to images in which only one object appears and is analyzed. In contrast, object detection involves both classification and localization tasks, and is used to analyze.', 10, 'image-classification', 'https://computerprogress.xyz/image/image-classification.svg', 'Image Classification', '2021-07-02 02:08:29.864713'); +insert into "task" ("created_at", "description", "id", "identifier", "image", "name", "updated_at") values ('2021-07-02 02:08:30.399504', 'Named entity recognition (NER) is the task of tagging entities in text with their corresponding type. Approaches typically use BIO notation, which differentiates the beginning (B) and the inside (I) of entities. O is used for non-entity tokens.', 20, 'named-entity-recognition', 'https://computerprogress.xyz/image/named-entity-recognition.svg', 'Named Entity Recognition', '2021-07-02 02:08:30.399504'); +insert into "task" ("created_at", "description", "id", "identifier", "image", "name", "updated_at") values ('2021-07-02 02:08:30.547009', 'Object detection is the task of detecting instances of objects of a certain class within an image. The state-of-the-art methods can be categorized into two main types: one-stage methods and two stage-methods. One-stage methods prioritize inference speed, and example models include YOLO, SSD and RetinaNet. Two-stage methods prioritize detection accuracy, and example models include Faster R-CNN, Mask R-CNN and Cascade R-CNN. The most popular benchmark is the MSCOCO dataset. Models are typically evaluated according to a Mean Average Precision metric.', 30, 'object-detection', 'https://computerprogress.xyz/image/object-detection.svg', 'Object Detection', '2021-07-02 02:08:30.547009'); +insert into "task" ("created_at", "description", "id", "identifier", "image", "name", "updated_at") values ('2021-07-02 02:08:30.971315', 'Question Answering is the task of answering questions (typically reading comprehension questions), but abstaining when presented with a question that cannot be answered based on the provided context.', 40, 'question-answering', 'https://computerprogress.xyz/image/question-answering.svg', 'Question Answering', '2021-07-02 02:08:30.971315'); +insert into "task" ("created_at", "description", "id", "identifier", "image", "name", "updated_at") values ('2021-07-02 02:08:31.147218', 'Machine translation is the task of translating a sentence in a source language to a different target language.', 50, 'machine-translation', 'https://computerprogress.xyz/image/machine-translation.svg', 'Machine Translation', '2021-07-02 02:08:31.147218'); + +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:29.864713', NULL, 10, 'imagenet', NULL, 'Imagenet', NULL, '2021-07-02 02:08:29.864713'); +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:30.399504', NULL, 20, 'conll-2003', NULL, 'Conll 2003', NULL, '2021-07-02 02:08:30.399504'); +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 30, 'ms-coco', NULL, 'MS COCO', NULL, '2021-07-02 02:08:30.547009'); +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:30.971315', NULL, 40, 'squad11', NULL, 'SQuAD 1.1', NULL, '2021-07-02 02:08:30.971315'); +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:31.147218', NULL, 50, 'wmt2014-en-ge', NULL, 'WMT2014 English-German', NULL, '2021-07-02 02:08:31.147218'); +insert into "dataset" ("created_at", "description", "id", "identifier", "image", "name", "source", "updated_at") values ('2021-07-02 02:08:31.312437', NULL, 60, 'wmt2014-en-fr', NULL, 'WMT2014 English-French', NULL, '2021-07-02 02:08:31.312437'); + +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:29.864713', NULL, 10, 'TOP 1', '2021-07-02 02:08:29.864713'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:29.864713', NULL, 20, 'TOP 5', '2021-07-02 02:08:29.864713'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.399504', NULL, 30, 'F1', '2021-07-02 02:08:30.399504'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 40, 'BOX AP', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 50, 'AP50', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 60, 'AP75', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 70, 'APS', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 80, 'APM', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.547009', NULL, 90, 'APL', '2021-07-02 02:08:30.547009'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.971315', NULL, 100, 'F1', '2021-07-02 02:08:30.971315'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:30.971315', NULL, 101, 'EM', '2021-07-02 02:08:30.971315'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:31.147218', NULL, 102, 'BLEU score', '2021-07-02 02:08:31.147218'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:31.147218', NULL, 103, 'SacreBLEU', '2021-07-02 02:08:31.147218'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:31.312437', NULL, 104, 'BLEU score', '2021-07-02 02:08:31.312437'); +insert into "accuracy_type" ("created_at", "description", "id", "name", "updated_at") values ('2021-07-02 02:08:31.312437', NULL, 105, 'SacreBLEU', '2021-07-02 02:08:31.312437'); + +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:29.864713', 10, 10, 'image-classification-on-imagenet', 10, '2021-07-02 02:08:29.864713'); +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:30.399504', 20, 20, 'named-entity-recognition-on-conll-2003', 20, '2021-07-02 02:08:30.399504'); +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:30.547009', 30, 30, 'object-detection-on-ms-coco', 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:30.971315', 40, 40, 'question-answering-on-squad11', 40, '2021-07-02 02:08:30.971315'); +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:31.147218', 50, 50, 'machine-translation-on-wmt2014-en-ge', 50, '2021-07-02 02:08:31.147218'); +insert into "task_dataset" ("created_at", "dataset_id", "id", "identifier", "task_id", "updated_at") values ('2021-07-02 02:08:31.312437', 60, 60, 'machine-translation-on-wmt2014-en-fr', 50, '2021-07-02 02:08:31.312437'); + +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (10, '2021-07-02 02:08:29.864713', 10, true, true, 10, '2021-07-02 02:08:29.864713'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (20, '2021-07-02 02:08:29.864713', 20, false, false, 10, '2021-07-02 02:08:29.864713'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (30, '2021-07-02 02:08:30.399504', 30, true, true, 20, '2021-07-02 02:08:30.399504'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (40, '2021-07-02 02:08:30.547009', 40, true, true, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (50, '2021-07-02 02:08:30.547009', 50, false, false, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (60, '2021-07-02 02:08:30.547009', 60, false, false, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (70, '2021-07-02 02:08:30.547009', 70, false, false, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (80, '2021-07-02 02:08:30.547009', 80, false, false, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (90, '2021-07-02 02:08:30.547009', 90, false, false, 30, '2021-07-02 02:08:30.547009'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (100, '2021-07-02 02:08:30.971315', 100, true, true, 40, '2021-07-02 02:08:30.971315'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (101, '2021-07-02 02:08:30.971315', 101, false, false, 40, '2021-07-02 02:08:30.971315'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (102, '2021-07-02 02:08:31.147218', 102, true, true, 50, '2021-07-02 02:08:31.147218'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (103, '2021-07-02 02:08:31.147218', 103, false, false, 50, '2021-07-02 02:08:31.147218'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (104, '2021-07-02 02:08:31.312437', 104, true, true, 60, '2021-07-02 02:08:31.312437'); +insert into "task_dataset_accuracy_type" ("accuracy_type_id", "created_at", "id", "main", "required", "task_dataset_id", "updated_at") values (105, '2021-07-02 02:08:31.312437', 105, false, false, 60, '2021-07-02 02:08:31.312437'); diff --git a/test.docker-compose.yml b/test.docker-compose.yml new file mode 100644 index 0000000..55b7fec --- /dev/null +++ b/test.docker-compose.yml @@ -0,0 +1,38 @@ +version: "3.3" +services: + dbtest: + image: postgres:12 + env_file: + - .env + environment: + - PGDATA=/var/lib/postgresql/data/pgdata + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 4s + retries: 5 + + backend-tests: + command: bash -c "alembic upgrade head && poetry run python initial_data.py && poetry run uvicorn app.main:app --reload --host 0.0.0.0" + image: "computerprogres-api:latest" + volumes: + - .:/app + ports: + - "8000:8000" + depends_on: + dbtest: + condition: service_healthy + env_file: + - .env + environment: + - POSTGRES_SERVER=dbtest + build: + context: . + dockerfile: Dockerfile + args: + INSTALL_DEV: ${INSTALL_DEV-true} + +volumes: + app-db-data: From 5f2601c07af9f533fcc174076aa44fe28e2876dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 31 Oct 2021 20:38:19 -0300 Subject: [PATCH 47/61] make submission flow works - change cpu,tpu,gpu fixture to be in the conftest.py - create model get route test - create submission and model fixture in the conftest.py --- app/test/route_tests/conftest.py | 78 ++++++++++- app/test/route_tests/test_cpu_route.py | 10 -- app/test/route_tests/test_model_route.py | 22 ++++ app/test/route_tests/test_submission_route.py | 1 - app/test/route_tests/test_tpu_route.py | 13 -- app/test/utils/constants.py | 123 +++++++++++++++--- 6 files changed, 201 insertions(+), 46 deletions(-) create mode 100644 app/test/route_tests/test_model_route.py diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index d000ac5..a624011 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -1,5 +1,5 @@ import pytest -from httpx import AsyncClient +from httpx import AsyncClient, Response from app.main import app from app.test.utils.constants import ( @@ -9,10 +9,54 @@ TASK, PAPER_BODY, PAPER_KEYS, + SUBMISSION_ALT_BODY, + MODEL_KEYS, SUCCESS, + CPU_BODY, + CPU_KEYS, + TPU_BODY, + GPU_BODY, + GPU_KEYS, ) +@pytest.fixture(scope="session") +async def cpu_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/cpus", json=CPU_BODY) + yield response + # cpu_id = response.json()["id"] + # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + # response = await ac.delete(f"/cpus/{cpu_id}") + # assert response.status_code == SUCCESS + # assert CPU_KEYS == set(response.json().keys()) + + +@pytest.fixture(scope="session") +async def tpu_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/tpus", json=TPU_BODY) + yield response + # json = response.json() + # tpu_id = json["id"] + # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + # response = await ac.delete(f"/tpus/{tpu_id}") + # assert response.status_code == SUCCESS + # assert response.json().keys() == json.keys() + + +@pytest.fixture(scope="session") +async def gpu_created(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/gpus", json=GPU_BODY) + yield response + # gpu_id = response.json()["id"] + # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + # response = await ac.delete(f"/gpus/{gpu_id}") + # assert response.status_code == SUCCESS + # assert GPU_KEYS == set(response.json().keys()) + + @pytest.fixture(scope="session") async def datasets_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: @@ -39,6 +83,38 @@ async def task_created(base_url: str, headers: dict): assert response.json().keys() == TASK_KEYS.keys() +@pytest.fixture(scope="session") +async def submission_approved_created( + base_url: str, + headers: dict, + datasets_created: Response, + task_created: Response, + tpu_created: Response, + cpu_created: Response, + gpu_created: Response +): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response_create = await ac.post("/submissions", json=SUBMISSION_ALT_BODY) + response_update_status = await ac.put( + f'/submissions/{response_create.json()["id"]}/status', + json={"status": "approved"}, + ) + assert response_create.status_code == SUCCESS + assert response_update_status.status_code == SUCCESS + return response_update_status.json() + + +@pytest.fixture(scope="session") +async def get_test_model( + headers: dict, base_url: str, submission_approved_created: Response +): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/models/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == MODEL_KEYS + yield response.json()[0] + + @pytest.fixture(scope="session") async def paper_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index 3b875cb..4f8f1ab 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -5,16 +5,6 @@ from app.test.utils.constants import CPU_BODY, CPU_KEYS, CPU_NEW, SUCCESS -@pytest.fixture(scope="module") -async def cpu_created(base_url: str, headers: dict): - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/cpus", json=CPU_BODY) - yield response - cpu_id = response.json()["id"] - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.delete(f"/cpus/{cpu_id}") - assert response.status_code == SUCCESS - assert CPU_KEYS == set(response.json().keys()) def test_cpu_post(cpu_created: Response): diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py new file mode 100644 index 0000000..c29251f --- /dev/null +++ b/app/test/route_tests/test_model_route.py @@ -0,0 +1,22 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import MODEL_KEYS, SUCCESS + + +@pytest.mark.asyncio +async def test_model_get_id(headers: dict, base_url: str, get_test_model: Response): + model_id = get_test_model["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/models/{model_id}") + assert response.status_code == SUCCESS + assert get_test_model == response.json() + +@pytest.mark.asyncio +async def test_model_get_id_csv(headers: dict, base_url: str, get_test_model: Response): + model_id = get_test_model["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/models/{model_id}") + assert response.status_code == SUCCESS + assert get_test_model == response.json() \ No newline at end of file diff --git a/app/test/route_tests/test_submission_route.py b/app/test/route_tests/test_submission_route.py index 9c84c52..2cf880d 100644 --- a/app/test/route_tests/test_submission_route.py +++ b/app/test/route_tests/test_submission_route.py @@ -50,7 +50,6 @@ async def test_submission_get(base_url: str, response = await ac.get('/submissions') assert response.status_code == SUCCESS assert response.json()[0].keys() == SUBMISSION_KEYS.keys() - assert response.json()[0]['data'] == SUBMISSION_BODY @pytest.mark.asyncio diff --git a/app/test/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py index 0dc21df..775cded 100644 --- a/app/test/route_tests/test_tpu_route.py +++ b/app/test/route_tests/test_tpu_route.py @@ -5,19 +5,6 @@ from app.test.utils.constants import TPU_BODY, TPU_NEW, SUCCESS -@pytest.fixture(scope="module") -async def tpu_created(base_url: str, headers: dict): - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.post("/tpus", json=TPU_BODY) - yield response - json = response.json() - tpu_id = json["id"] - async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.delete(f"/tpus/{tpu_id}") - assert response.status_code == SUCCESS - assert response.json().keys() == json.keys() - - def test_tpu_post(tpu_created: Response): json = tpu_created.json() body_keys = list(TPU_BODY.keys()) diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index c1d8eac..feeceab 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -96,6 +96,44 @@ # END CPU CONSTANTS # ================================ +# ================================ +# BEGIN TPU CONSTANTS + +TPU_BODY = { + "name": "foobar", + "transistors": 10, + "tdp": 20, + "gflops": 5 +} + +TPU_NEW = { + "name": "barfoo", + "transistors": 50, + "tdp": 21, + "gflops": 3 +} + +# END TPU CONSTANTS +# ================================ + +# ================================ +# BEGIN GPU CONSTANTS + +GPU_BODY = { + "name": "GeForce 8300 GS", + "transistors": 210, + "tdp": 40, + "gflops": 14.4 +} + +GPU_KEYS = { + *GPU_BODY, + "id" +} + +# END GPU CONSTANTS +# ================================ + # ================================ # BEGIN LOGIN CONSTANTS @@ -185,6 +223,42 @@ ] } +SUBMISSION_ALT_BODY = { + "title": "string", + "link": "string", + "code_link": "string", + "publication_date": "2021-10-30", + "authors": [ + "string" + ], + "models": [ + { + "name": "string", + "task": "Image Classification", + "dataset": "Imagenet", + "cpu": CPU_BODY["name"], + "gpu": GPU_BODY["name"], + "tpu": TPU_BODY["name"], + "gflops": 0, + "multiply_adds": 0, + "number_of_parameters": 0, + "training_time": 0, + "epochs": 0, + "extra_training_data": False, + "accuracies": [ + { + "accuracy_type": "TOP 1", + "value": 1 + } + ], + "number_of_gpus": 0, + "number_of_cpus": 0, + "number_of_tpus": 0, + "extra_training_time": False + } + ] +} + SUBMISSION_KEYS = { "data": {**SUBMISSION_BODY}, "paper_id": 0, @@ -215,26 +289,6 @@ # END SUBMISSION CONSTANTS # ================================ -# ================================ -# BEGIN TPU CONSTANTS - -TPU_BODY = { - "name": "foobar", - "transistors": 10, - "tdp": 20, - "gflops": 5 -} - -TPU_NEW = { - "name": "barfoo", - "transistors": 50, - "tdp": 21, - "gflops": 3 -} - -# END TPU CONSTANTS -# ================================ - # ================================ # BEGIN USER CONSTANTS @@ -316,4 +370,31 @@ } # END PAPER CONSTANTS -# ================================ \ No newline at end of file +# ================================ + +# ================================ +# BEGIN MODEL CONSTANTS + +MODEL_KEYS = { + "name", + "hardware_burden", + "training_time", + "gflops", + "epochs", + "number_of_parameters", + "multiply_adds", + "number_of_cpus", + "number_of_gpus", + "number_of_tpus", + "task_dataset_id", + "task_dataset_id", + "paper_id", + "cpu_id", + "tpu_id", + "gpu_id", + "id" +} + + +# END MODEL CONSTANTS +# ================================ From 635062489561788b85e7dd34726c72560218f3e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 31 Oct 2021 21:01:52 -0300 Subject: [PATCH 48/61] test model put route --- app/test/route_tests/test_model_route.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index c29251f..98dbf3b 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -13,10 +13,12 @@ async def test_model_get_id(headers: dict, base_url: str, get_test_model: Respon assert response.status_code == SUCCESS assert get_test_model == response.json() + @pytest.mark.asyncio -async def test_model_get_id_csv(headers: dict, base_url: str, get_test_model: Response): +async def test_model_put(headers: dict, base_url: str, get_test_model: Response): model_id = get_test_model["id"] + put_body = {**get_test_model, "name": "fooo", "gflops": 2, "epochs": 3} async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - response = await ac.get(f"/models/{model_id}") + response = await ac.put(f"/models/{model_id}", json=put_body) assert response.status_code == SUCCESS - assert get_test_model == response.json() \ No newline at end of file + assert set(put_body.items()) <= set(response.json().items()) From 41e33c3e40b86269f40516fc79fb0611f9cb6e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Sun, 31 Oct 2021 21:23:45 -0300 Subject: [PATCH 49/61] test model delete route and some fix codestyle --- app/test/route_tests/conftest.py | 31 ++++++++++++++++++------ app/test/route_tests/test_model_route.py | 4 +-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index a624011..3af9e4f 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -25,11 +25,6 @@ async def cpu_created(base_url: str, headers: dict): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.post("/cpus", json=CPU_BODY) yield response - # cpu_id = response.json()["id"] - # async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: - # response = await ac.delete(f"/cpus/{cpu_id}") - # assert response.status_code == SUCCESS - # assert CPU_KEYS == set(response.json().keys()) @pytest.fixture(scope="session") @@ -91,7 +86,7 @@ async def submission_approved_created( task_created: Response, tpu_created: Response, cpu_created: Response, - gpu_created: Response + gpu_created: Response, ): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response_create = await ac.post("/submissions", json=SUBMISSION_ALT_BODY) @@ -106,13 +101,35 @@ async def submission_approved_created( @pytest.fixture(scope="session") async def get_test_model( - headers: dict, base_url: str, submission_approved_created: Response + headers: dict, + base_url: str, + submission_approved_created: Response, + cpu_created: Response, + tpu_created: Response, + gpu_created: Response, ): async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/models/?skip=0&limit=1", headers=headers) assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == MODEL_KEYS yield response.json()[0] + model_id = response.json()[0]["id"] + cpu_id = cpu_created.json()["id"] + tpu_id = tpu_created.json()["id"] + gpu_id = gpu_created.json()["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response_models = await ac.delete(f"/models/{model_id}") + response_cpu = await ac.delete(f"/cpus/{cpu_id}") + response_tpu = await ac.delete(f"/tpus/{tpu_id}") + response_gpu = await ac.delete(f"/gpus/{gpu_id}") + assert response_cpu.status_code == SUCCESS + assert CPU_KEYS == set(response_cpu.json().keys()) + assert response_models.status_code == SUCCESS + assert MODEL_KEYS == set(response_models.json().keys()) + assert response_tpu.status_code == SUCCESS + assert response_tpu.json().keys() == tpu_created.json().keys() + assert response_gpu.status_code == SUCCESS + assert GPU_KEYS == set(response_gpu.json().keys()) @pytest.fixture(scope="session") diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index 98dbf3b..6885093 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -17,8 +17,8 @@ async def test_model_get_id(headers: dict, base_url: str, get_test_model: Respon @pytest.mark.asyncio async def test_model_put(headers: dict, base_url: str, get_test_model: Response): model_id = get_test_model["id"] - put_body = {**get_test_model, "name": "fooo", "gflops": 2, "epochs": 3} + put_body = {**get_test_model, "name": "fooo", "gflops": 2.0, "epochs": 3} async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.put(f"/models/{model_id}", json=put_body) assert response.status_code == SUCCESS - assert set(put_body.items()) <= set(response.json().items()) + assert {**put_body, "id": model_id} == response.json() From 2d9982a4b3730366b37603d92c5faf1e685cb96f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 01:53:48 -0300 Subject: [PATCH 50/61] test model get task dataset route --- app/test/route_tests/conftest.py | 2 -- app/test/route_tests/test_cpu_route.py | 2 -- app/test/route_tests/test_model_route.py | 24 +++++++++++++++++- app/test/utils/constants.py | 32 +++++++++++++++++++++--- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/app/test/route_tests/conftest.py b/app/test/route_tests/conftest.py index 3af9e4f..157fbd0 100644 --- a/app/test/route_tests/conftest.py +++ b/app/test/route_tests/conftest.py @@ -82,8 +82,6 @@ async def task_created(base_url: str, headers: dict): async def submission_approved_created( base_url: str, headers: dict, - datasets_created: Response, - task_created: Response, tpu_created: Response, cpu_created: Response, gpu_created: Response, diff --git a/app/test/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py index 4f8f1ab..2cadaff 100644 --- a/app/test/route_tests/test_cpu_route.py +++ b/app/test/route_tests/test_cpu_route.py @@ -5,8 +5,6 @@ from app.test.utils.constants import CPU_BODY, CPU_KEYS, CPU_NEW, SUCCESS - - def test_cpu_post(cpu_created: Response): assert cpu_created.status_code == SUCCESS assert cpu_created.json().items() >= CPU_BODY.items() diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index 6885093..7cef1c4 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -2,7 +2,14 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import MODEL_KEYS, SUCCESS +from app.test.utils.constants import ( + MODEL_KEYS, + SUCCESS, + TASK_MODEL, + DATASET_MODEL, + ACCURACY_TOP1, + MODEL_TASK_DATASET_KEYS +) @pytest.mark.asyncio @@ -22,3 +29,18 @@ async def test_model_put(headers: dict, base_url: str, get_test_model: Response) response = await ac.put(f"/models/{model_id}", json=put_body) assert response.status_code == SUCCESS assert {**put_body, "id": model_id} == response.json() + + +@pytest.mark.asyncio +async def test_model_get_task_dataset( + headers: dict, + base_url: str, + get_test_model: Response, +): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get( + f"/models/{TASK_MODEL['task_id']}/{DATASET_MODEL['dataset_id']}" + ) + + assert response.status_code == SUCCESS + assert MODEL_TASK_DATASET_KEYS == set(response.json().keys()) diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index feeceab..8e13541 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -31,6 +31,12 @@ } DATASETS_KEYS = {*DATASETS_BODY, "id"} +DATASET_MODEL = { + "dataset_id": 10, + "dataset_identifier": "imagenet", + "dataset_name": "Imagenet", +} + # END DATASETS CONSTANTS # ================================ @@ -57,6 +63,13 @@ "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit", } +TASK_MODEL = { + "task_name": "Image Classification", + "task_image": "https://computerprogress.xyz/image/image-classification.svg", + "task_identifier": "image-classification", + "task_id": 10 +} + # END TASK CONSTANTS # ================================ @@ -71,6 +84,12 @@ ACCURACY_KEYS_GET = {*ACCURACY_KEYS, "updated_at", "created_at"} +ACCURACY_TOP1 = { + "name": "TOP 1", + "description": None, + "main": True +} + # END ACCURACY CONSTANTS # ================================ @@ -234,8 +253,8 @@ "models": [ { "name": "string", - "task": "Image Classification", - "dataset": "Imagenet", + "task": TASK_MODEL["task_name"], + "dataset": DATASET_MODEL["dataset_name"], "cpu": CPU_BODY["name"], "gpu": GPU_BODY["name"], "tpu": TPU_BODY["name"], @@ -247,7 +266,7 @@ "extra_training_data": False, "accuracies": [ { - "accuracy_type": "TOP 1", + "accuracy_type": ACCURACY_TOP1["name"], "value": 1 } ], @@ -387,7 +406,6 @@ "number_of_gpus", "number_of_tpus", "task_dataset_id", - "task_dataset_id", "paper_id", "cpu_id", "tpu_id", @@ -395,6 +413,12 @@ "id" } +MODEL_TASK_DATASET_KEYS = { + *TASK_MODEL, + *DATASET_MODEL, + "accuracy_types", + "models" +} # END MODEL CONSTANTS # ================================ From 4d97f0f94c437eae94cc9b9e6ac6a9a837e688a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 02:11:51 -0300 Subject: [PATCH 51/61] test get model csv route --- app/test/route_tests/test_model_route.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index 7cef1c4..a16dc84 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -8,7 +8,7 @@ TASK_MODEL, DATASET_MODEL, ACCURACY_TOP1, - MODEL_TASK_DATASET_KEYS + MODEL_TASK_DATASET_KEYS, ) @@ -41,6 +41,19 @@ async def test_model_get_task_dataset( response = await ac.get( f"/models/{TASK_MODEL['task_id']}/{DATASET_MODEL['dataset_id']}" ) - assert response.status_code == SUCCESS assert MODEL_TASK_DATASET_KEYS == set(response.json().keys()) + + +@pytest.mark.asyncio +async def test_model_get_task_dataset_csv( + headers: dict, + base_url: str, + get_test_model: Response, +): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get( + f"/models/{TASK_MODEL['task_id']}/{DATASET_MODEL['dataset_id']}/csv" + ) + assert response.status_code == SUCCESS + assert len(response.text) > 340 From fc308bd2be035cfc40ec9ec826b87af0fc3e9c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 02:19:07 -0300 Subject: [PATCH 52/61] test all gpu routes --- app/test/route_tests/test_gpu_route.py | 39 ++++++++++++++++++++++++++ app/test/utils/constants.py | 5 ++++ 2 files changed, 44 insertions(+) create mode 100644 app/test/route_tests/test_gpu_route.py diff --git a/app/test/route_tests/test_gpu_route.py b/app/test/route_tests/test_gpu_route.py new file mode 100644 index 0000000..2a652f7 --- /dev/null +++ b/app/test/route_tests/test_gpu_route.py @@ -0,0 +1,39 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import GPU_BODY, GPU_KEYS, GPU_NEW, SUCCESS + + +def test_gpu_post(gpu_created: Response): + assert gpu_created.status_code == SUCCESS + assert gpu_created.json().items() >= GPU_BODY.items() + assert set(gpu_created.json().keys()) == GPU_KEYS + + +@pytest.mark.asyncio +async def test_gpu_get(headers: dict, base_url: str, gpu_created: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/gpus/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == GPU_KEYS + + +@pytest.mark.asyncio +async def test_gpu_get_id(base_url: str, headers: dict, gpu_created: Response): + gpu_json = gpu_created.json() + gpu_id = gpu_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/gpus/{gpu_id}") + assert response.status_code == SUCCESS + assert gpu_json == response.json() + + +@pytest.mark.asyncio +async def test_gpu_put(base_url: str, headers: dict, gpu_created: Response): + gpu_json = gpu_created.json() + gpu_id = gpu_json["id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.put(f"/gpus/{gpu_id}", json=GPU_NEW) + assert response.status_code == SUCCESS + assert {**GPU_NEW, "id": gpu_id} == response.json() diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 8e13541..6eb0cff 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -150,6 +150,11 @@ "id" } +GPU_NEW = { + **GPU_BODY, + "tdp": 222 +} + # END GPU CONSTANTS # ================================ From 9dc2df440b5e081d4bb5d89ce4e82084044c522e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 15:59:44 -0300 Subject: [PATCH 53/61] add one more assert to test model csv route --- app/test/route_tests/test_model_route.py | 6 ++++++ app/test/utils/constants.py | 25 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index a16dc84..723a3be 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -9,6 +9,7 @@ DATASET_MODEL, ACCURACY_TOP1, MODEL_TASK_DATASET_KEYS, + MODEL_CSV_KEYS ) @@ -55,5 +56,10 @@ async def test_model_get_task_dataset_csv( response = await ac.get( f"/models/{TASK_MODEL['task_id']}/{DATASET_MODEL['dataset_id']}/csv" ) + response.encondig = "UTF-8" + csvReader = response.text.replace('\n', ',', 1) + csvReader = csvReader.split(",", maxsplit=len(MODEL_CSV_KEYS)) + print(csvReader) assert response.status_code == SUCCESS assert len(response.text) > 340 + assert set(csvReader[0:-1]) == MODEL_CSV_KEYS diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 6eb0cff..b46de4d 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -425,5 +425,30 @@ "models" } +MODEL_CSV_KEYS = { + "task_name", + "dataset_name", + "paper_publication_date", + "paper_title", + "paper_link", + "paper_code_link", + "model_name", + ACCURACY_TOP1["name"], + "model_gflops", + "model_multiply_adds", + "model_operation_per_network_pass", + "model_extra_training_time", + "model_number_of_cpus", + "model_cpu", + "model_number_of_gpus", + "model_gpu", + "model_number_of_tpus", + "model_tpu", + "model_training_time", + "model_hardware_burden", + "model_number_of_parameters", + "model_epochs", +} + # END MODEL CONSTANTS # ================================ From 7516750230114a1c88142525fb6395dd8e3ca36f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 19:11:54 -0300 Subject: [PATCH 54/61] install pytest-order --- poetry.lock | 716 ++++++++++++++++++++++++++++--------------------- pyproject.toml | 1 + 2 files changed, 405 insertions(+), 312 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7b19f99..1da7341 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,21 +8,24 @@ python-versions = ">=3.6,<4.0" [[package]] name = "alembic" -version = "1.6.5" +version = "1.7.4" description = "A database migration tool for SQLAlchemy." category = "main" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +python-versions = ">=3.6" [package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.9\""} +importlib-resources = {version = "*", markers = "python_version < \"3.9\""} Mako = "*" -python-dateutil = "*" -python-editor = ">=0.3" SQLAlchemy = ">=1.3.0" +[package.extras] +tz = ["python-dateutil"] + [[package]] name = "anyio" -version = "3.3.0" +version = "3.3.4" description = "High level compatibility layer for multiple asynchronous event loop implementations" category = "dev" optional = false @@ -40,7 +43,7 @@ trio = ["trio (>=0.16)"] [[package]] name = "asgiref" -version = "3.3.4" +version = "3.4.1" description = "ASGI specs, helper code, and adapters" category = "main" optional = false @@ -92,7 +95,7 @@ typecheck = ["mypy"] [[package]] name = "cachetools" -version = "4.2.2" +version = "4.2.4" description = "Extensible memoizing collections and decorators" category = "main" optional = false @@ -100,7 +103,7 @@ python-versions = "~=3.5" [[package]] name = "certifi" -version = "2021.5.30" +version = "2021.10.8" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -108,7 +111,7 @@ python-versions = "*" [[package]] name = "cffi" -version = "1.14.5" +version = "1.15.0" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -127,9 +130,9 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "charset-normalizer" -version = "2.0.4" +version = "2.0.7" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" +category = "main" optional = false python-versions = ">=3.5.0" @@ -138,7 +141,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.1" +version = "8.0.3" description = "Composable command line interface toolkit" category = "main" optional = false @@ -211,11 +214,11 @@ gmpy2 = ["gmpy2"] [[package]] name = "email-validator" -version = "1.1.2" +version = "1.1.3" description = "A robust email syntax and deliverability validation library for Python 2.x/3.x." category = "main" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] dnspython = ">=1.15.0" @@ -239,7 +242,7 @@ requests = "*" [[package]] name = "fastapi" -version = "0.65.1" +version = "0.65.3" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -252,12 +255,12 @@ starlette = "0.14.2" [package.extras] 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 (>=4.0.1,<5.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)"] 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)"] -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)"] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "markdown-include (>=0.6.0,<0.7.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] test = ["pytest (==5.4.3)", "pytest-cov (==2.10.0)", "pytest-asyncio (>=0.14.0,<0.15.0)", "mypy (==0.812)", "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,<1.4.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.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)"] [[package]] name = "greenlet" -version = "1.1.0" +version = "1.1.2" description = "Lightweight in-process concurrent programming" category = "main" optional = false @@ -276,7 +279,7 @@ python-versions = ">=3.6" [[package]] name = "httpcore" -version = "0.13.6" +version = "0.13.7" description = "A minimal low-level HTTP client." category = "dev" optional = false @@ -311,15 +314,15 @@ http2 = ["h2 (>=3,<5)"] [[package]] name = "idna" -version = "2.10" +version = "3.3" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.5.0" +version = "4.8.1" description = "Read metadata from Python packages" category = "main" optional = false @@ -331,11 +334,27 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] + +[[package]] +name = "importlib-resources" +version = "5.4.0" +description = "Read resources from Python packages" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] name = "jinja2" -version = "3.0.1" +version = "3.0.2" description = "A very fast and expressive template engine." category = "main" optional = false @@ -363,7 +382,7 @@ source = ["Cython (>=0.29.7)"] [[package]] name = "mako" -version = "1.1.4" +version = "1.1.5" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." category = "main" optional = false @@ -386,7 +405,7 @@ python-versions = ">=3.6" [[package]] name = "more-itertools" -version = "8.8.0" +version = "8.10.0" description = "More routines for operating on iterables, beyond itertools" category = "dev" optional = false @@ -394,38 +413,51 @@ python-versions = ">=3.5" [[package]] name = "numpy" -version = "1.21.0" +version = "1.21.1" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "numpy" +version = "1.21.3" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7,<3.11" + [[package]] name = "packaging" -version = "20.9" +version = "21.2" description = "Core utilities for Python packages" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] -pyparsing = ">=2.0.2" +pyparsing = ">=2.0.2,<3" [[package]] name = "pandas" -version = "1.2.5" +version = "1.3.4" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.7.1" [package.dependencies] -numpy = ">=1.16.5" +numpy = [ + {version = ">=1.17.3", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, + {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, +] python-dateutil = ">=2.7.3" pytz = ">=2017.3" [package.extras] -test = ["pytest (>=5.0.1)", "pytest-xdist", "hypothesis (>=3.58)"] +test = ["hypothesis (>=3.58)", "pytest (>=6.0)", "pytest-xdist"] [[package]] name = "passlib" @@ -457,7 +489,7 @@ dev = ["pre-commit", "tox"] [[package]] name = "premailer" -version = "3.9.0" +version = "3.10.0" description = "Turns CSS blocks into style attributes" category = "main" optional = false @@ -476,11 +508,11 @@ test = ["nose", "mock"] [[package]] name = "psycopg2" -version = "2.8.6" +version = "2.9.1" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = ">=3.6" [[package]] name = "py" @@ -568,9 +600,20 @@ pytest = ">=5.4.0" [package.extras] testing = ["coverage", "hypothesis (>=5.7.1)"] +[[package]] +name = "pytest-order" +version = "1.0.0" +description = "pytest plugin to run your tests in a specific order" +category = "dev" +optional = false +python-versions = "*" + +[package.dependencies] +pytest = ">=5.0" + [[package]] name = "python-dateutil" -version = "2.8.1" +version = "2.8.2" description = "Extensions to the standard Python datetime module" category = "main" optional = false @@ -581,23 +624,15 @@ six = ">=1.5" [[package]] name = "python-dotenv" -version = "0.17.1" +version = "0.19.1" description = "Read key-value pairs from a .env file and set them as environment variables" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.5" [package.extras] cli = ["click (>=5.0)"] -[[package]] -name = "python-editor" -version = "1.0.4" -description = "Programmatically open an editor, capture the result." -category = "main" -optional = false -python-versions = "*" - [[package]] name = "python-jose" version = "3.3.0" @@ -643,7 +678,7 @@ unidecode = ["Unidecode (>=1.1.1)"] [[package]] name = "pytz" -version = "2021.1" +version = "2021.3" description = "World timezone definitions, modern and historical" category = "main" optional = false @@ -651,21 +686,21 @@ python-versions = "*" [[package]] name = "requests" -version = "2.25.1" +version = "2.26.0" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [package.dependencies] certifi = ">=2017.4.17" -chardet = ">=3.0.2,<5" -idna = ">=2.5,<3" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} urllib3 = ">=1.21.1,<1.27" [package.extras] -security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rfc3986" @@ -710,27 +745,28 @@ python-versions = ">=3.5" [[package]] name = "sqlalchemy" -version = "1.4.17" +version = "1.4.26" description = "Database Abstraction Library" category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\""} +greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [package.extras] aiomysql = ["greenlet (!=0.4.17)", "aiomysql"] -aiosqlite = ["greenlet (!=0.4.17)", "aiosqlite"] +aiosqlite = ["typing_extensions (!=3.10.0.1)", "greenlet (!=0.4.17)", "aiosqlite"] asyncio = ["greenlet (!=0.4.17)"] +asyncmy = ["greenlet (!=0.4.17)", "asyncmy (>=0.2.3)"] mariadb_connector = ["mariadb (>=1.0.1)"] mssql = ["pyodbc"] mssql_pymssql = ["pymssql"] mssql_pyodbc = ["pyodbc"] -mypy = ["sqlalchemy2-stubs", "mypy (>=0.800)"] +mypy = ["sqlalchemy2-stubs", "mypy (>=0.910)"] mysql = ["mysqlclient (>=1.4.0,<2)", "mysqlclient (>=1.4.0)"] -mysql_connector = ["mysqlconnector"] +mysql_connector = ["mysql-connector-python"] oracle = ["cx_oracle (>=7,<8)", "cx_oracle (>=7)"] postgresql = ["psycopg2 (>=2.7)"] postgresql_asyncpg = ["greenlet (!=0.4.17)", "asyncpg"] @@ -742,7 +778,7 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "sqlalchemy-utils" -version = "0.37.8" +version = "0.37.9" description = "Various utility functions for SQLAlchemy." category = "main" optional = false @@ -753,7 +789,6 @@ six = "*" SQLAlchemy = ">=1.0" [package.extras] -anyjson = ["anyjson (>=0.3.3)"] arrow = ["arrow (>=0.3.4)"] babel = ["Babel (>=1.3)"] color = ["colour (>=0.0.4)"] @@ -763,7 +798,7 @@ password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] test = ["pytest (>=2.7.1)", "Pygments (>=1.2)", "Jinja2 (>=2.3)", "docutils (>=0.10)", "flexmock (>=0.9.7)", "mock (==2.0.0)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pg8000 (>=1.12.4)", "pytz (>=2014.2)", "python-dateutil (>=2.6)", "pymysql", "flake8 (>=2.4.0)", "isort (>=4.2.2)", "pyodbc", "backports.zoneinfo"] -test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "anyjson (>=0.3.3)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)", "backports.zoneinfo"] +test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)", "backports.zoneinfo"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] @@ -788,7 +823,7 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.0" +version = "3.10.0.2" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -796,7 +831,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.5" +version = "1.26.7" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false @@ -834,7 +869,7 @@ python-versions = "*" [[package]] name = "zipp" -version = "3.4.1" +version = "3.6.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false @@ -842,12 +877,12 @@ python-versions = ">=3.6" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "^3.7.1" -content-hash = "4e49d058f548e2ea583afe81cd06c61f31f6ffb0417ddcc243eeedde50a81429" +content-hash = "0f30f2faf5535e0b799a1882c6f77e93ab3253b33e54af785c5571b24449e055" [metadata.files] aiofiles = [ @@ -855,16 +890,16 @@ aiofiles = [ {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, ] alembic = [ - {file = "alembic-1.6.5-py2.py3-none-any.whl", hash = "sha256:e78be5b919f5bb184e3e0e2dd1ca986f2362e29a2bc933c446fe89f39dbe4e9c"}, - {file = "alembic-1.6.5.tar.gz", hash = "sha256:a21fedebb3fb8f6bbbba51a11114f08c78709377051384c9c5ead5705ee93a51"}, + {file = "alembic-1.7.4-py3-none-any.whl", hash = "sha256:e3cab9e59778b3b6726bb2da9ced451c6622d558199fd3ef914f3b1e8f4ef704"}, + {file = "alembic-1.7.4.tar.gz", hash = "sha256:9d33f3ff1488c4bfab1e1a6dfebbf085e8a8e1a3e047a43ad29ad1f67f012a1d"}, ] anyio = [ - {file = "anyio-3.3.0-py3-none-any.whl", hash = "sha256:929a6852074397afe1d989002aa96d457e3e1e5441357c60d03e7eea0e65e1b0"}, - {file = "anyio-3.3.0.tar.gz", hash = "sha256:ae57a67583e5ff8b4af47666ff5651c3732d45fd26c929253748e796af860374"}, + {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, + {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, ] asgiref = [ - {file = "asgiref-3.3.4-py3-none-any.whl", hash = "sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee"}, - {file = "asgiref-3.3.4.tar.gz", hash = "sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78"}, + {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, + {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, @@ -884,75 +919,76 @@ bcrypt = [ {file = "bcrypt-3.2.0.tar.gz", hash = "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29"}, ] cachetools = [ - {file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"}, - {file = "cachetools-4.2.2.tar.gz", hash = "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"}, + {file = "cachetools-4.2.4-py3-none-any.whl", hash = "sha256:92971d3cb7d2a97efff7c7bb1657f21a8f5fb309a37530537c71b1774189f2d1"}, + {file = "cachetools-4.2.4.tar.gz", hash = "sha256:89ea6f1b638d5a73a4f9226be57ac5e4f399d22770b92355f92dcb0f7f001693"}, ] certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] cffi = [ - {file = "cffi-1.14.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1"}, - {file = "cffi-1.14.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa"}, - {file = "cffi-1.14.5-cp27-cp27m-win32.whl", hash = "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3"}, - {file = "cffi-1.14.5-cp27-cp27m-win_amd64.whl", hash = "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482"}, - {file = "cffi-1.14.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6"}, - {file = "cffi-1.14.5-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa"}, - {file = "cffi-1.14.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406"}, - {file = "cffi-1.14.5-cp35-cp35m-win32.whl", hash = "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369"}, - {file = "cffi-1.14.5-cp35-cp35m-win_amd64.whl", hash = "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315"}, - {file = "cffi-1.14.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed"}, - {file = "cffi-1.14.5-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55"}, - {file = "cffi-1.14.5-cp36-cp36m-win32.whl", hash = "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53"}, - {file = "cffi-1.14.5-cp36-cp36m-win_amd64.whl", hash = "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813"}, - {file = "cffi-1.14.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05"}, - {file = "cffi-1.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc"}, - {file = "cffi-1.14.5-cp37-cp37m-win32.whl", hash = "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62"}, - {file = "cffi-1.14.5-cp37-cp37m-win_amd64.whl", hash = "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4"}, - {file = "cffi-1.14.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f"}, - {file = "cffi-1.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76"}, - {file = "cffi-1.14.5-cp38-cp38-win32.whl", hash = "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e"}, - {file = "cffi-1.14.5-cp38-cp38-win_amd64.whl", hash = "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396"}, - {file = "cffi-1.14.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_i686.whl", hash = "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333"}, - {file = "cffi-1.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7"}, - {file = "cffi-1.14.5-cp39-cp39-win32.whl", hash = "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396"}, - {file = "cffi-1.14.5-cp39-cp39-win_amd64.whl", hash = "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d"}, - {file = "cffi-1.14.5.tar.gz", hash = "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c"}, + {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, + {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, + {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, + {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, + {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, + {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, + {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, + {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, + {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, + {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, + {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, + {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, + {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, + {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, + {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, + {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, + {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"}, - {file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"}, + {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, + {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, ] click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, @@ -975,91 +1011,96 @@ ecdsa = [ {file = "ecdsa-0.17.0.tar.gz", hash = "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa"}, ] email-validator = [ - {file = "email-validator-1.1.2.tar.gz", hash = "sha256:1a13bd6050d1db4475f13e444e169b6fe872434922d38968c67cea9568cce2f0"}, - {file = "email_validator-1.1.2-py2.py3-none-any.whl", hash = "sha256:094b1d1c60d790649989d38d34f69e1ef07792366277a2cf88684d03495d018f"}, + {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, + {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, ] emails = [ {file = "emails-0.6-py2.py3-none-any.whl", hash = "sha256:72c1e3198075709cc35f67e1b49e2da1a2bc087e9b444073db61a379adfb7f3c"}, {file = "emails-0.6.tar.gz", hash = "sha256:a4c2d67ea8b8831967a750d8edc6e77040d7693143fe280e6d2a367d9c36ff88"}, ] fastapi = [ - {file = "fastapi-0.65.1-py3-none-any.whl", hash = "sha256:7619282fbce0ec53c7dfa3fa262280c00ace9f6d772cfd06e4ab219dce66985e"}, - {file = "fastapi-0.65.1.tar.gz", hash = "sha256:478b7e0cbb52c9913b9903d88ae14195cb8a479c4596e0b2f2238d317840a7dc"}, + {file = "fastapi-0.65.3-py3-none-any.whl", hash = "sha256:d3e3c0ac35110efb22ee3ed28201cf32f9d11a9a0e52d7dd676cad25f5219523"}, + {file = "fastapi-0.65.3.tar.gz", hash = "sha256:6ea2286e439c4ced7cce2b2862c25859601bf327a515c12dd6e431ef5d49d12f"}, ] greenlet = [ - {file = "greenlet-1.1.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:60848099b76467ef09b62b0f4512e7e6f0a2c977357a036de602b653667f5f4c"}, - {file = "greenlet-1.1.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f42ad188466d946f1b3afc0a9e1a266ac8926461ee0786c06baac6bd71f8a6f3"}, - {file = "greenlet-1.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:76ed710b4e953fc31c663b079d317c18f40235ba2e3d55f70ff80794f7b57922"}, - {file = "greenlet-1.1.0-cp27-cp27m-win32.whl", hash = "sha256:b33b51ab057f8a20b497ffafdb1e79256db0c03ef4f5e3d52e7497200e11f821"}, - {file = "greenlet-1.1.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed1377feed808c9c1139bdb6a61bcbf030c236dd288d6fca71ac26906ab03ba6"}, - {file = "greenlet-1.1.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:da862b8f7de577bc421323714f63276acb2f759ab8c5e33335509f0b89e06b8f"}, - {file = "greenlet-1.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5f75e7f237428755d00e7460239a2482fa7e3970db56c8935bd60da3f0733e56"}, - {file = "greenlet-1.1.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:258f9612aba0d06785143ee1cbf2d7361801c95489c0bd10c69d163ec5254a16"}, - {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d928e2e3c3906e0a29b43dc26d9b3d6e36921eee276786c4e7ad9ff5665c78a"}, - {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cc407b68e0a874e7ece60f6639df46309376882152345508be94da608cc0b831"}, - {file = "greenlet-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c557c809eeee215b87e8a7cbfb2d783fb5598a78342c29ade561440abae7d22"}, - {file = "greenlet-1.1.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:3d13da093d44dee7535b91049e44dd2b5540c2a0e15df168404d3dd2626e0ec5"}, - {file = "greenlet-1.1.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b3090631fecdf7e983d183d0fad7ea72cfb12fa9212461a9b708ff7907ffff47"}, - {file = "greenlet-1.1.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:06ecb43b04480e6bafc45cb1b4b67c785e183ce12c079473359e04a709333b08"}, - {file = "greenlet-1.1.0-cp35-cp35m-win32.whl", hash = "sha256:944fbdd540712d5377a8795c840a97ff71e7f3221d3fddc98769a15a87b36131"}, - {file = "greenlet-1.1.0-cp35-cp35m-win_amd64.whl", hash = "sha256:c767458511a59f6f597bfb0032a1c82a52c29ae228c2c0a6865cfeaeaac4c5f5"}, - {file = "greenlet-1.1.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2325123ff3a8ecc10ca76f062445efef13b6cf5a23389e2df3c02a4a527b89bc"}, - {file = "greenlet-1.1.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:598bcfd841e0b1d88e32e6a5ea48348a2c726461b05ff057c1b8692be9443c6e"}, - {file = "greenlet-1.1.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:be9768e56f92d1d7cd94185bab5856f3c5589a50d221c166cc2ad5eb134bd1dc"}, - {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe7eac0d253915116ed0cd160a15a88981a1d194c1ef151e862a5c7d2f853d3"}, - {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a6b035aa2c5fcf3dbbf0e3a8a5bc75286fc2d4e6f9cfa738788b433ec894919"}, - {file = "greenlet-1.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca1c4a569232c063615f9e70ff9a1e2fee8c66a6fb5caf0f5e8b21a396deec3e"}, - {file = "greenlet-1.1.0-cp36-cp36m-win32.whl", hash = "sha256:3096286a6072553b5dbd5efbefc22297e9d06a05ac14ba017233fedaed7584a8"}, - {file = "greenlet-1.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:c35872b2916ab5a240d52a94314c963476c989814ba9b519bc842e5b61b464bb"}, - {file = "greenlet-1.1.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b97c9a144bbeec7039cca44df117efcbeed7209543f5695201cacf05ba3b5857"}, - {file = "greenlet-1.1.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:16183fa53bc1a037c38d75fdc59d6208181fa28024a12a7f64bb0884434c91ea"}, - {file = "greenlet-1.1.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6b1d08f2e7f2048d77343279c4d4faa7aef168b3e36039cba1917fffb781a8ed"}, - {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14927b15c953f8f2d2a8dffa224aa78d7759ef95284d4c39e1745cf36e8cdd2c"}, - {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bdcff4b9051fb1aa4bba4fceff6a5f770c6be436408efd99b76fc827f2a9319"}, - {file = "greenlet-1.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70c7dd733a4c56838d1f1781e769081a25fade879510c5b5f0df76956abfa05"}, - {file = "greenlet-1.1.0-cp37-cp37m-win32.whl", hash = "sha256:0de64d419b1cb1bfd4ea544bedea4b535ef3ae1e150b0f2609da14bbf48a4a5f"}, - {file = "greenlet-1.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8833e27949ea32d27f7e96930fa29404dd4f2feb13cce483daf52e8842ec246a"}, - {file = "greenlet-1.1.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:c1580087ab493c6b43e66f2bdd165d9e3c1e86ef83f6c2c44a29f2869d2c5bd5"}, - {file = "greenlet-1.1.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ad80bb338cf9f8129c049837a42a43451fc7c8b57ad56f8e6d32e7697b115505"}, - {file = "greenlet-1.1.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:a9017ff5fc2522e45562882ff481128631bf35da444775bc2776ac5c61d8bcae"}, - {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7920e3eccd26b7f4c661b746002f5ec5f0928076bd738d38d894bb359ce51927"}, - {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:408071b64e52192869129a205e5b463abda36eff0cebb19d6e63369440e4dc99"}, - {file = "greenlet-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be13a18cec649ebaab835dff269e914679ef329204704869f2f167b2c163a9da"}, - {file = "greenlet-1.1.0-cp38-cp38-win32.whl", hash = "sha256:22002259e5b7828b05600a762579fa2f8b33373ad95a0ee57b4d6109d0e589ad"}, - {file = "greenlet-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:206295d270f702bc27dbdbd7651e8ebe42d319139e0d90217b2074309a200da8"}, - {file = "greenlet-1.1.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:096cb0217d1505826ba3d723e8981096f2622cde1eb91af9ed89a17c10aa1f3e"}, - {file = "greenlet-1.1.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:03f28a5ea20201e70ab70518d151116ce939b412961c33827519ce620957d44c"}, - {file = "greenlet-1.1.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:7db68f15486d412b8e2cfcd584bf3b3a000911d25779d081cbbae76d71bd1a7e"}, - {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70bd1bb271e9429e2793902dfd194b653221904a07cbf207c3139e2672d17959"}, - {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f92731609d6625e1cc26ff5757db4d32b6b810d2a3363b0ff94ff573e5901f6f"}, - {file = "greenlet-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06d7ac89e6094a0a8f8dc46aa61898e9e1aec79b0f8b47b2400dd51a44dbc832"}, - {file = "greenlet-1.1.0-cp39-cp39-win32.whl", hash = "sha256:adb94a28225005890d4cf73648b5131e885c7b4b17bc762779f061844aabcc11"}, - {file = "greenlet-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:aa4230234d02e6f32f189fd40b59d5a968fe77e80f59c9c933384fe8ba535535"}, - {file = "greenlet-1.1.0.tar.gz", hash = "sha256:c87df8ae3f01ffb4483c796fe1b15232ce2b219f0b18126948616224d3f658ee"}, + {file = "greenlet-1.1.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:58df5c2a0e293bf665a51f8a100d3e9956febfbf1d9aaf8c0677cf70218910c6"}, + {file = "greenlet-1.1.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:aec52725173bd3a7b56fe91bc56eccb26fbdff1386ef123abb63c84c5b43b63a"}, + {file = "greenlet-1.1.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:833e1551925ed51e6b44c800e71e77dacd7e49181fdc9ac9a0bf3714d515785d"}, + {file = "greenlet-1.1.2-cp27-cp27m-win32.whl", hash = "sha256:aa5b467f15e78b82257319aebc78dd2915e4c1436c3c0d1ad6f53e47ba6e2713"}, + {file = "greenlet-1.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:40b951f601af999a8bf2ce8c71e8aaa4e8c6f78ff8afae7b808aae2dc50d4c40"}, + {file = "greenlet-1.1.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:95e69877983ea39b7303570fa6760f81a3eec23d0e3ab2021b7144b94d06202d"}, + {file = "greenlet-1.1.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:356b3576ad078c89a6107caa9c50cc14e98e3a6c4874a37c3e0273e4baf33de8"}, + {file = "greenlet-1.1.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:8639cadfda96737427330a094476d4c7a56ac03de7265622fcf4cfe57c8ae18d"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e5306482182170ade15c4b0d8386ded995a07d7cc2ca8f27958d34d6736497"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6a36bb9474218c7a5b27ae476035497a6990e21d04c279884eb10d9b290f1b1"}, + {file = "greenlet-1.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb7a75ed8b968f3061327c433a0fbd17b729947b400747c334a9c29a9af6c58"}, + {file = "greenlet-1.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:14d4f3cd4e8b524ae9b8aa567858beed70c392fdec26dbdb0a8a418392e71708"}, + {file = "greenlet-1.1.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:17ff94e7a83aa8671a25bf5b59326ec26da379ace2ebc4411d690d80a7fbcf23"}, + {file = "greenlet-1.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9f3cba480d3deb69f6ee2c1825060177a22c7826431458c697df88e6aeb3caee"}, + {file = "greenlet-1.1.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:fa877ca7f6b48054f847b61d6fa7bed5cebb663ebc55e018fda12db09dcc664c"}, + {file = "greenlet-1.1.2-cp35-cp35m-win32.whl", hash = "sha256:7cbd7574ce8e138bda9df4efc6bf2ab8572c9aff640d8ecfece1b006b68da963"}, + {file = "greenlet-1.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:903bbd302a2378f984aef528f76d4c9b1748f318fe1294961c072bdc7f2ffa3e"}, + {file = "greenlet-1.1.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:049fe7579230e44daef03a259faa24511d10ebfa44f69411d99e6a184fe68073"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:dd0b1e9e891f69e7675ba5c92e28b90eaa045f6ab134ffe70b52e948aa175b3c"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:7418b6bfc7fe3331541b84bb2141c9baf1ec7132a7ecd9f375912eca810e714e"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9d29ca8a77117315101425ec7ec2a47a22ccf59f5593378fc4077ac5b754fce"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21915eb821a6b3d9d8eefdaf57d6c345b970ad722f856cd71739493ce003ad08"}, + {file = "greenlet-1.1.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eff9d20417ff9dcb0d25e2defc2574d10b491bf2e693b4e491914738b7908168"}, + {file = "greenlet-1.1.2-cp36-cp36m-win32.whl", hash = "sha256:32ca72bbc673adbcfecb935bb3fb1b74e663d10a4b241aaa2f5a75fe1d1f90aa"}, + {file = "greenlet-1.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f0214eb2a23b85528310dad848ad2ac58e735612929c8072f6093f3585fd342d"}, + {file = "greenlet-1.1.2-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:b92e29e58bef6d9cfd340c72b04d74c4b4e9f70c9fa7c78b674d1fec18896dc4"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fdcec0b8399108577ec290f55551d926d9a1fa6cad45882093a7a07ac5ec147b"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:93f81b134a165cc17123626ab8da2e30c0455441d4ab5576eed73a64c025b25c"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e12bdc622676ce47ae9abbf455c189e442afdde8818d9da983085df6312e7a1"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c790abda465726cfb8bb08bd4ca9a5d0a7bd77c7ac1ca1b839ad823b948ea28"}, + {file = "greenlet-1.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f276df9830dba7a333544bd41070e8175762a7ac20350786b322b714b0e654f5"}, + {file = "greenlet-1.1.2-cp37-cp37m-win32.whl", hash = "sha256:64e6175c2e53195278d7388c454e0b30997573f3f4bd63697f88d855f7a6a1fc"}, + {file = "greenlet-1.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b11548073a2213d950c3f671aa88e6f83cda6e2fb97a8b6317b1b5b33d850e06"}, + {file = "greenlet-1.1.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:9633b3034d3d901f0a46b7939f8c4d64427dfba6bbc5a36b1a67364cf148a1b0"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eb6ea6da4c787111adf40f697b4e58732ee0942b5d3bd8f435277643329ba627"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f3acda1924472472ddd60c29e5b9db0cec629fbe3c5c5accb74d6d6d14773478"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e859fcb4cbe93504ea18008d1df98dee4f7766db66c435e4882ab35cf70cac43"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e44c8afdbe5467e4f7b5851be223be68adb4272f44696ee71fe46b7036a711"}, + {file = "greenlet-1.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec8c433b3ab0419100bd45b47c9c8551248a5aee30ca5e9d399a0b57ac04651b"}, + {file = "greenlet-1.1.2-cp38-cp38-win32.whl", hash = "sha256:288c6a76705dc54fba69fbcb59904ae4ad768b4c768839b8ca5fdadec6dd8cfd"}, + {file = "greenlet-1.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:8d2f1fb53a421b410751887eb4ff21386d119ef9cde3797bf5e7ed49fb51a3b3"}, + {file = "greenlet-1.1.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:166eac03e48784a6a6e0e5f041cfebb1ab400b394db188c48b3a84737f505b67"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:572e1787d1460da79590bf44304abbc0a2da944ea64ec549188fa84d89bba7ab"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:be5f425ff1f5f4b3c1e33ad64ab994eed12fc284a6ea71c5243fd564502ecbe5"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1692f7d6bc45e3200844be0dba153612103db241691088626a33ff1f24a0d88"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7227b47e73dedaa513cdebb98469705ef0d66eb5a1250144468e9c3097d6b59b"}, + {file = "greenlet-1.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff61ff178250f9bb3cd89752df0f1dd0e27316a8bd1465351652b1b4a4cdfd3"}, + {file = "greenlet-1.1.2-cp39-cp39-win32.whl", hash = "sha256:f70a9e237bb792c7cc7e44c531fd48f5897961701cdaa06cf22fc14965c496cf"}, + {file = "greenlet-1.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:013d61294b6cd8fe3242932c1c5e36e5d1db2c8afb58606c5a67efce62c1f5fd"}, + {file = "greenlet-1.1.2.tar.gz", hash = "sha256:e30f5ea4ae2346e62cedde8794a56858a67b878dd79f7df76a0767e356b1744a"}, ] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, ] httpcore = [ - {file = "httpcore-0.13.6-py3-none-any.whl", hash = "sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff"}, - {file = "httpcore-0.13.6.tar.gz", hash = "sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e"}, + {file = "httpcore-0.13.7-py3-none-any.whl", hash = "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"}, + {file = "httpcore-0.13.7.tar.gz", hash = "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3"}, ] httpx = [ {file = "httpx-0.19.0-py3-none-any.whl", hash = "sha256:9bd728a6c5ec0a9e243932a9983d57d3cc4a87bb4f554e1360fce407f78f9435"}, {file = "httpx-0.19.0.tar.gz", hash = "sha256:92ecd2c00c688b529eda11cedb15161eaf02dee9116712f621c70d9a40b2cdd0"}, ] idna = [ - {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, - {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, - {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, + {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, + {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, +] +importlib-resources = [ + {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, + {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, ] jinja2 = [ - {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, - {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, + {file = "Jinja2-3.0.2-py3-none-any.whl", hash = "sha256:8569982d3f0889eed11dd620c706d39b60c36d6d25843961f33f77fb6bc6b20c"}, + {file = "Jinja2-3.0.2.tar.gz", hash = "sha256:827a0e32839ab1600d4eb1c4c33ec5a8edfbc5cb42dafa13b81f182f97784b45"}, ] lxml = [ {file = "lxml-4.6.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:df7c53783a46febb0e70f6b05df2ba104610f2fb0d27023409734a3ecbb78fb2"}, @@ -1112,8 +1153,8 @@ lxml = [ {file = "lxml-4.6.3.tar.gz", hash = "sha256:39b78571b3b30645ac77b95f7c69d1bffc4cf8c3b157c435a34da72e78c82468"}, ] mako = [ - {file = "Mako-1.1.4-py2.py3-none-any.whl", hash = "sha256:aea166356da44b9b830c8023cd9b557fa856bd8b4035d6de771ca027dfc5cc6e"}, - {file = "Mako-1.1.4.tar.gz", hash = "sha256:17831f0b7087c313c0ffae2bcbbd3c1d5ba9eeac9c38f2eb7b50e8c99fe9d5ab"}, + {file = "Mako-1.1.5-py2.py3-none-any.whl", hash = "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23"}, + {file = "Mako-1.1.5.tar.gz", hash = "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3"}, ] markupsafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, @@ -1121,6 +1162,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, @@ -1132,6 +1176,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, @@ -1143,6 +1190,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, @@ -1155,6 +1205,9 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, @@ -1167,67 +1220,109 @@ markupsafe = [ {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] more-itertools = [ - {file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"}, - {file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"}, + {file = "more-itertools-8.10.0.tar.gz", hash = "sha256:1debcabeb1df793814859d64a81ad7cb10504c24349368ccf214c664c474f41f"}, + {file = "more_itertools-8.10.0-py3-none-any.whl", hash = "sha256:56ddac45541718ba332db05f464bebfb0768110111affd27f66e0051f276fa43"}, ] numpy = [ - {file = "numpy-1.21.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d5caa946a9f55511e76446e170bdad1d12d6b54e17a2afe7b189112ed4412bb8"}, - {file = "numpy-1.21.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ac4fd578322842dbda8d968e3962e9f22e862b6ec6e3378e7415625915e2da4d"}, - {file = "numpy-1.21.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:598fe100b2948465cf3ed64b1a326424b5e4be2670552066e17dfaa67246011d"}, - {file = "numpy-1.21.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c55407f739f0bfcec67d0df49103f9333edc870061358ac8a8c9e37ea02fcd2"}, - {file = "numpy-1.21.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:75579acbadbf74e3afd1153da6177f846212ea2a0cc77de53523ae02c9256513"}, - {file = "numpy-1.21.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc367c86eb87e5b7c9592935620f22d13b090c609f1b27e49600cd033b529f54"}, - {file = "numpy-1.21.0-cp37-cp37m-win32.whl", hash = "sha256:d89b0dc7f005090e32bb4f9bf796e1dcca6b52243caf1803fdd2b748d8561f63"}, - {file = "numpy-1.21.0-cp37-cp37m-win_amd64.whl", hash = "sha256:eda2829af498946c59d8585a9fd74da3f810866e05f8df03a86f70079c7531dd"}, - {file = "numpy-1.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1a784e8ff7ea2a32e393cc53eb0003eca1597c7ca628227e34ce34eb11645a0e"}, - {file = "numpy-1.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bba474a87496d96e61461f7306fba2ebba127bed7836212c360f144d1e72ac54"}, - {file = "numpy-1.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fd0a359c1c17f00cb37de2969984a74320970e0ceef4808c32e00773b06649d9"}, - {file = "numpy-1.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e4d5a86a5257843a18fb1220c5f1c199532bc5d24e849ed4b0289fb59fbd4d8f"}, - {file = "numpy-1.21.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:620732f42259eb2c4642761bd324462a01cdd13dd111740ce3d344992dd8492f"}, - {file = "numpy-1.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9205711e5440954f861ceeea8f1b415d7dd15214add2e878b4d1cf2bcb1a914"}, - {file = "numpy-1.21.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ad09f55cc95ed8d80d8ab2052f78cc21cb231764de73e229140d81ff49d8145e"}, - {file = "numpy-1.21.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a1f2fb2da242568af0271455b89aee0f71e4e032086ee2b4c5098945d0e11cf6"}, - {file = "numpy-1.21.0-cp38-cp38-win32.whl", hash = "sha256:e58ddb53a7b4959932f5582ac455ff90dcb05fac3f8dcc8079498d43afbbde6c"}, - {file = "numpy-1.21.0-cp38-cp38-win_amd64.whl", hash = "sha256:d2910d0a075caed95de1a605df00ee03b599de5419d0b95d55342e9a33ad1fb3"}, - {file = "numpy-1.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a290989cd671cd0605e9c91a70e6df660f73ae87484218e8285c6522d29f6e38"}, - {file = "numpy-1.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3537b967b350ad17633b35c2f4b1a1bbd258c018910b518c30b48c8e41272717"}, - {file = "numpy-1.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc6c650f8700ce1e3a77668bb7c43e45c20ac06ae00d22bdf6760b38958c883"}, - {file = "numpy-1.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:709884863def34d72b183d074d8ba5cfe042bc3ff8898f1ffad0209161caaa99"}, - {file = "numpy-1.21.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bebab3eaf0641bba26039fb0b2c5bf9b99407924b53b1ea86e03c32c64ef5aef"}, - {file = "numpy-1.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf680682ad0a3bef56dae200dbcbac2d57294a73e5b0f9864955e7dd7c2c2491"}, - {file = "numpy-1.21.0-cp39-cp39-win32.whl", hash = "sha256:d95d16204cd51ff1a1c8d5f9958ce90ae190be81d348b514f9be39f878b8044a"}, - {file = "numpy-1.21.0-cp39-cp39-win_amd64.whl", hash = "sha256:2ba579dde0563f47021dcd652253103d6fd66165b18011dce1a0609215b2791e"}, - {file = "numpy-1.21.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c40e6b860220ed862e8097b8f81c9af6d7405b723f4a7af24a267b46f90e461"}, - {file = "numpy-1.21.0.zip", hash = "sha256:e80fe25cba41c124d04c662f33f6364909b985f2eb5998aaa5ae4b9587242cce"}, + {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, + {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, + {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, + {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, + {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, + {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, + {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, + {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, + {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, + {file = "numpy-1.21.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:508b0b513fa1266875524ba8a9ecc27b02ad771fe1704a16314dc1a816a68737"}, + {file = "numpy-1.21.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5dfe9d6a4c39b8b6edd7990091fea4f852888e41919d0e6722fe78dd421db0eb"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10968963640e75cc0193e1847616ab4c718e83b6938ae74dea44953950f6b7"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c6249260890e05b8111ebfc391ed58b3cb4b33e63197b2ec7f776e45330721"}, + {file = "numpy-1.21.3-cp310-cp310-win_amd64.whl", hash = "sha256:f8f4625536926a155b80ad2bbff44f8cc59e9f2ad14cdda7acf4c135b4dc8ff2"}, + {file = "numpy-1.21.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e54af82d68ef8255535a6cdb353f55d6b8cf418a83e2be3569243787a4f4866f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f41b018f126aac18583956c54544db437f25c7ee4794bcb23eb38bef8e5e192a"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50cd26b0cf6664cb3b3dd161ba0a09c9c1343db064e7c69f9f8b551f5104d654"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cc9b512e9fb590797474f58b7f6d1f1b654b3a94f4fa8558b48ca8b3cfc97cf"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:88a5d6b268e9ad18f3533e184744acdaa2e913b13148160b1152300c949bbb5f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c09418a14471c7ae69ba682e2428cae5b4420a766659605566c0fa6987f6b7e"}, + {file = "numpy-1.21.3-cp37-cp37m-win32.whl", hash = "sha256:90bec6a86b348b4559b6482e2b684db4a9a7eed1fa054b86115a48d58fbbf62a"}, + {file = "numpy-1.21.3-cp37-cp37m-win_amd64.whl", hash = "sha256:043e83bfc274649c82a6f09836943e4a4aebe5e33656271c7dbf9621dd58b8ec"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:75621882d2230ab77fb6a03d4cbccd2038511491076e7964ef87306623aa5272"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:188031f833bbb623637e66006cf75e933e00e7231f67e2b45cf8189612bb5dc3"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:160ccc1bed3a8371bf0d760971f09bfe80a3e18646620e9ded0ad159d9749baa"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:29fb3dcd0468b7715f8ce2c0c2d9bbbaf5ae686334951343a41bd8d155c6ea27"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32437f0b275c1d09d9c3add782516413e98cd7c09e6baf4715cbce781fc29912"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e606e6316911471c8d9b4618e082635cfe98876007556e89ce03d52ff5e8fcf0"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a99a6b067e5190ac6d12005a4d85aa6227c5606fa93211f86b1dafb16233e57d"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dde972a1e11bb7b702ed0e447953e7617723760f420decb97305e66fb4afc54f"}, + {file = "numpy-1.21.3-cp38-cp38-win32.whl", hash = "sha256:fe52dbe47d9deb69b05084abd4b0df7abb39a3c51957c09f635520abd49b29dd"}, + {file = "numpy-1.21.3-cp38-cp38-win_amd64.whl", hash = "sha256:75eb7cadc8da49302f5b659d40ba4f6d94d5045fbd9569c9d058e77b0514c9e4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a6ee9620061b2a722749b391c0d80a0e2ae97290f1b32e28d5a362e21941ee4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c4193f70f8069550a1788bd0cd3268ab7d3a2b70583dfe3b2e7f421e9aace06"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f15209fb535dd4c504a7762d3bc440779b0e37d50ed810ced209e5cea60d96"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c6c2d535a7beb1f8790aaa98fd089ceab2e3dd7ca48aca0af7dc60e6ef93ffe1"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bffa2eee3b87376cc6b31eee36d05349571c236d1de1175b804b348dc0941e3f"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14e7519fab2a4ed87d31f99c31a3796e4e1fe63a86ebdd1c5a1ea78ebd5896"}, + {file = "numpy-1.21.3-cp39-cp39-win32.whl", hash = "sha256:dd0482f3fc547f1b1b5d6a8b8e08f63fdc250c58ce688dedd8851e6e26cff0f3"}, + {file = "numpy-1.21.3-cp39-cp39-win_amd64.whl", hash = "sha256:300321e3985c968e3ae7fbda187237b225f3ffe6528395a5b7a5407f73cf093e"}, + {file = "numpy-1.21.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98339aa9911853f131de11010f6dd94c8cec254d3d1f7261528c3b3e3219f139"}, + {file = "numpy-1.21.3.zip", hash = "sha256:63571bb7897a584ca3249c86dd01c10bcb5fe4296e3568b2e9c1a55356b6410e"}, ] packaging = [ - {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, - {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, + {file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"}, + {file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"}, ] pandas = [ - {file = "pandas-1.2.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1102d719038e134e648e7920672188a00375f3908f0383fd3b202fbb9d2c3a95"}, - {file = "pandas-1.2.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38e7486410de23069392bdf1dc7297ae75d2d67531750753f3149c871cd1c6e3"}, - {file = "pandas-1.2.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:94ca6ea3f46f44a979a38a4d5a70a88cee734f7248d7aeeed202e6b3ba485af1"}, - {file = "pandas-1.2.5-cp37-cp37m-win32.whl", hash = "sha256:821d92466fcd2826656374a9b6fe4f2ec2ba5e370cce71d5a990577929d948df"}, - {file = "pandas-1.2.5-cp37-cp37m-win_amd64.whl", hash = "sha256:0dbd125b0e44e5068163cbc9080a00db1756a5e36309329ae14fd259747f2300"}, - {file = "pandas-1.2.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7b09293c7119ab22ab3f7f086f813ac2acbfa3bcaaaeb650f4cddfb5b9fa9be4"}, - {file = "pandas-1.2.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc9215dd1dd836ff26b896654e66b2dfcf4bbb18aa4c1089a79bab527b665a90"}, - {file = "pandas-1.2.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e36515163829e0e95a6af10820f178dd8768102482c01872bff8ae592e508e58"}, - {file = "pandas-1.2.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0c34b89215f984a9e4956446e0a29330d720085efa08ea72022387ee37d8b373"}, - {file = "pandas-1.2.5-cp38-cp38-win32.whl", hash = "sha256:f20e4b8a7909f5a0c0a9e745091e3ea18b45af9f73496a4d498688badbdac7ea"}, - {file = "pandas-1.2.5-cp38-cp38-win_amd64.whl", hash = "sha256:9244fb0904512b074d8c6362fb13aac1da6c4db94372760ddb2565c620240264"}, - {file = "pandas-1.2.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c862cd72353921c102166784fc4db749f1c3b691dd017fc36d9df2c67a9afe4e"}, - {file = "pandas-1.2.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e6edddeac9a8e473391d2d2067bb3c9dc7ad79fd137af26a39ee425c2b4c78"}, - {file = "pandas-1.2.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a67227e17236442c6bc31c02cb713b5277b26eee204eac14b5aecba52492e3a3"}, - {file = "pandas-1.2.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4bfbf62b00460f78a8bc4407112965c5ab44324f34551e8e1f4cac271a07706c"}, - {file = "pandas-1.2.5-cp39-cp39-win32.whl", hash = "sha256:25fc8ef6c6beb51c9224284a1ad89dfb591832f23ceff78845f182de35c52356"}, - {file = "pandas-1.2.5-cp39-cp39-win_amd64.whl", hash = "sha256:78de96c1174bcfdbe8dece9c38c2d7994e407fd8bb62146bb46c61294bcc06ef"}, - {file = "pandas-1.2.5.tar.gz", hash = "sha256:14abb8ea73fce8aebbb1fb44bec809163f1c55241bcc1db91c2c780e97265033"}, + {file = "pandas-1.3.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9707bdc1ea9639c886b4d3be6e2a45812c1ac0c2080f94c31b71c9fa35556f9b"}, + {file = "pandas-1.3.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c2f44425594ae85e119459bb5abb0748d76ef01d9c08583a667e3339e134218e"}, + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:372d72a3d8a5f2dbaf566a5fa5fa7f230842ac80f29a931fb4b071502cf86b9a"}, + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99d2350adb7b6c3f7f8f0e5dfb7d34ff8dd4bc0a53e62c445b7e43e163fce63"}, + {file = "pandas-1.3.4-cp310-cp310-win_amd64.whl", hash = "sha256:4acc28364863127bca1029fb72228e6f473bb50c32e77155e80b410e2068eeac"}, + {file = "pandas-1.3.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c2646458e1dce44df9f71a01dc65f7e8fa4307f29e5c0f2f92c97f47a5bf22f5"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5298a733e5bfbb761181fd4672c36d0c627320eb999c59c65156c6a90c7e1b4f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22808afb8f96e2269dcc5b846decacb2f526dd0b47baebc63d913bf847317c8f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b528e126c13816a4374e56b7b18bfe91f7a7f6576d1aadba5dee6a87a7f479ae"}, + {file = "pandas-1.3.4-cp37-cp37m-win32.whl", hash = "sha256:fe48e4925455c964db914b958f6e7032d285848b7538a5e1b19aeb26ffaea3ec"}, + {file = "pandas-1.3.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eaca36a80acaacb8183930e2e5ad7f71539a66805d6204ea88736570b2876a7b"}, + {file = "pandas-1.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42493f8ae67918bf129869abea8204df899902287a7f5eaf596c8e54e0ac7ff4"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a388960f979665b447f0847626e40f99af8cf191bce9dc571d716433130cb3a7"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba0aac1397e1d7b654fccf263a4798a9e84ef749866060d19e577e927d66e1b"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f567e972dce3bbc3a8076e0b675273b4a9e8576ac629149cf8286ee13c259ae5"}, + {file = "pandas-1.3.4-cp38-cp38-win32.whl", hash = "sha256:c1aa4de4919358c5ef119f6377bc5964b3a7023c23e845d9db7d9016fa0c5b1c"}, + {file = "pandas-1.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:dd324f8ee05925ee85de0ea3f0d66e1362e8c80799eb4eb04927d32335a3e44a"}, + {file = "pandas-1.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d47750cf07dee6b55d8423471be70d627314277976ff2edd1381f02d52dbadf9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d1dc09c0013d8faa7474574d61b575f9af6257ab95c93dcf33a14fd8d2c1bab"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10e10a2527db79af6e830c3d5842a4d60383b162885270f8cffc15abca4ba4a9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35c77609acd2e4d517da41bae0c11c70d31c87aae8dd1aabd2670906c6d2c143"}, + {file = "pandas-1.3.4-cp39-cp39-win32.whl", hash = "sha256:003ba92db58b71a5f8add604a17a059f3068ef4e8c0c365b088468d0d64935fd"}, + {file = "pandas-1.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:a51528192755f7429c5bcc9e80832c517340317c861318fea9cea081b57c9afd"}, + {file = "pandas-1.3.4.tar.gz", hash = "sha256:a2aa18d3f0b7d538e21932f637fbfe8518d085238b429e4790a35e1e44a96ffc"}, ] passlib = [ {file = "passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1"}, @@ -1238,25 +1333,19 @@ pluggy = [ {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] premailer = [ - {file = "premailer-3.9.0-py2.py3-none-any.whl", hash = "sha256:d674826981be58d2eaa51db25f31bfe02f2859760aa1ff9879de9110f48e6476"}, - {file = "premailer-3.9.0.tar.gz", hash = "sha256:da18b9e8cb908893b67ab9b7451276fef7c0ab179f40189378545f6bb0ab3695"}, + {file = "premailer-3.10.0-py2.py3-none-any.whl", hash = "sha256:021b8196364d7df96d04f9ade51b794d0b77bcc19e998321c515633a2273be1a"}, + {file = "premailer-3.10.0.tar.gz", hash = "sha256:d1875a8411f5dc92b53ef9f193db6c0f879dc378d618e0ad292723e388bfe4c2"}, ] psycopg2 = [ - {file = "psycopg2-2.8.6-cp27-cp27m-win32.whl", hash = "sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725"}, - {file = "psycopg2-2.8.6-cp27-cp27m-win_amd64.whl", hash = "sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5"}, - {file = "psycopg2-2.8.6-cp34-cp34m-win32.whl", hash = "sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad"}, - {file = "psycopg2-2.8.6-cp34-cp34m-win_amd64.whl", hash = "sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3"}, - {file = "psycopg2-2.8.6-cp35-cp35m-win32.whl", hash = "sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821"}, - {file = "psycopg2-2.8.6-cp35-cp35m-win_amd64.whl", hash = "sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301"}, - {file = "psycopg2-2.8.6-cp36-cp36m-win32.whl", hash = "sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a"}, - {file = "psycopg2-2.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d"}, - {file = "psycopg2-2.8.6-cp37-cp37m-win32.whl", hash = "sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84"}, - {file = "psycopg2-2.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5"}, - {file = "psycopg2-2.8.6-cp38-cp38-win32.whl", hash = "sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e"}, - {file = "psycopg2-2.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051"}, - {file = "psycopg2-2.8.6-cp39-cp39-win32.whl", hash = "sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3"}, - {file = "psycopg2-2.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7"}, - {file = "psycopg2-2.8.6.tar.gz", hash = "sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543"}, + {file = "psycopg2-2.9.1-cp36-cp36m-win32.whl", hash = "sha256:7f91312f065df517187134cce8e395ab37f5b601a42446bdc0f0d51773621854"}, + {file = "psycopg2-2.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:830c8e8dddab6b6716a4bf73a09910c7954a92f40cf1d1e702fb93c8a919cc56"}, + {file = "psycopg2-2.9.1-cp37-cp37m-win32.whl", hash = "sha256:89409d369f4882c47f7ea20c42c5046879ce22c1e4ea20ef3b00a4dfc0a7f188"}, + {file = "psycopg2-2.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7640e1e4d72444ef012e275e7b53204d7fab341fb22bc76057ede22fe6860b25"}, + {file = "psycopg2-2.9.1-cp38-cp38-win32.whl", hash = "sha256:079d97fc22de90da1d370c90583659a9f9a6ee4007355f5825e5f1c70dffc1fa"}, + {file = "psycopg2-2.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:2c992196719fadda59f72d44603ee1a2fdcc67de097eea38d41c7ad9ad246e62"}, + {file = "psycopg2-2.9.1-cp39-cp39-win32.whl", hash = "sha256:2087013c159a73e09713294a44d0c8008204d06326006b7f652bef5ace66eebb"}, + {file = "psycopg2-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:bf35a25f1aaa8a3781195595577fcbb59934856ee46b4f252f56ad12b8043bcf"}, + {file = "psycopg2-2.9.1.tar.gz", hash = "sha256:de5303a6f1d0a7a34b9d40e4d3bef684ccc44a49bbe3eb85e3c0bffb4a131b7c"}, ] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, @@ -1317,20 +1406,17 @@ pytest-asyncio = [ {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, ] +pytest-order = [ + {file = "pytest-order-1.0.0.tar.gz", hash = "sha256:5997a262b31234eebb461f9a9ef24687bf732029b499845a4398b69edb5ac321"}, + {file = "pytest_order-1.0.0-py3-none-any.whl", hash = "sha256:a4cdf12f4c83c76bdfd6e6088e2e157df7fdf91a9c3e3ca7d8809e8dabce0f4b"}, +] python-dateutil = [ - {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, - {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] python-dotenv = [ - {file = "python-dotenv-0.17.1.tar.gz", hash = "sha256:b1ae5e9643d5ed987fc57cc2583021e38db531946518130777734f9589b3141f"}, - {file = "python_dotenv-0.17.1-py2.py3-none-any.whl", hash = "sha256:00aa34e92d992e9f8383730816359647f358f4a3be1ba45e5a5cefd27ee91544"}, -] -python-editor = [ - {file = "python-editor-1.0.4.tar.gz", hash = "sha256:51fda6bcc5ddbbb7063b2af7509e43bd84bfc32a4ff71349ec7847713882327b"}, - {file = "python_editor-1.0.4-py2-none-any.whl", hash = "sha256:5f98b069316ea1c2ed3f67e7f5df6c0d8f10b689964a4a811ff64f0106819ec8"}, - {file = "python_editor-1.0.4-py2.7.egg", hash = "sha256:ea87e17f6ec459e780e4221f295411462e0d0810858e055fc514684350a2f522"}, - {file = "python_editor-1.0.4-py3-none-any.whl", hash = "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d"}, - {file = "python_editor-1.0.4-py3.5.egg", hash = "sha256:c3da2053dbab6b29c94e43c486ff67206eafbe7eb52dbec7390b5e2fb05aac77"}, + {file = "python-dotenv-0.19.1.tar.gz", hash = "sha256:14f8185cc8d494662683e6914addcb7e95374771e707601dfc70166946b4c4b8"}, + {file = "python_dotenv-0.19.1-py2.py3-none-any.whl", hash = "sha256:bbd3da593fc49c249397cbfbcc449cf36cb02e75afc8157fcc6a81df6fb7750a"}, ] python-jose = [ {file = "python-jose-3.3.0.tar.gz", hash = "sha256:55779b5e6ad599c6336191246e95eb2293a9ddebd555f796a65f838f07e5d78a"}, @@ -1344,12 +1430,12 @@ python-slugify = [ {file = "python_slugify-5.0.2-py2.py3-none-any.whl", hash = "sha256:6d8c5df75cd4a7c3a2d21e257633de53f52ab0265cd2d1dc62a730e8194a7380"}, ] pytz = [ - {file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"}, - {file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"}, + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, ] requests = [ - {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, - {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, ] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, @@ -1368,40 +1454,46 @@ sniffio = [ {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.17-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c367ed95d41df584f412a9419b5ece85b0d6c2a08a51ae13ae47ef74ff9a9349"}, - {file = "SQLAlchemy-1.4.17-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fdad4a33140b77df61d456922b7974c1f1bb2c35238f6809f078003a620c4734"}, - {file = "SQLAlchemy-1.4.17-cp27-cp27m-win32.whl", hash = "sha256:f1c68f7bd4a57ffdb85eab489362828dddf6cd565a4c18eda4c446c1d5d3059d"}, - {file = "SQLAlchemy-1.4.17-cp27-cp27m-win_amd64.whl", hash = "sha256:ee6e7ca09ff274c55d19a1e15ee6f884fa0230c0d9b8d22a456e249d08dee5bf"}, - {file = "SQLAlchemy-1.4.17-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5f00a2be7d777119e15ccfb5ba0b2a92e8a193959281089d79821a001095f80"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1dd77acbc19bee9c0ba858ff5e4e5d5c60895495c83b4df9bcdf4ad5e9b74f21"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5732858e56d32fa7e02468f4fd2d8f01ddf709e5b93d035c637762890f8ed8b6"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:949ac299903d2ed8419086f81847381184e2264f3431a33af4679546dcc87f01"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:196fb6bb2733834e506c925d7532f8eabad9d2304deef738a40846e54c31e236"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-win32.whl", hash = "sha256:bde055c019e6e449ebc4ec61abd3e08690abeb028c7ada2a3b95d8e352b7b514"}, - {file = "SQLAlchemy-1.4.17-cp36-cp36m-win_amd64.whl", hash = "sha256:b0ad951a6e590bbcfbfeadc5748ef5ec8ede505a8119a71b235f7481cc08371c"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:82922a320d38d7d6aa3a8130523ec7e8c70fa95f7ca7d0fd6ec114b626e4b10b"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e133e2551fa99c75849848a4ac08efb79930561eb629dd7d2dc9b7ee05256e6"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7e45043fe11d503e1c3f9dcf5b42f92d122a814237cd9af68a11dae46ecfcae1"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:461a4ea803ce0834822f372617a68ac97f9fa1281f2a984624554c651d7c3ae1"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-win32.whl", hash = "sha256:4d93b62e98248e3e1ac1e91c2e6ee1e7316f704be1f734338b350b6951e6c175"}, - {file = "SQLAlchemy-1.4.17-cp37-cp37m-win_amd64.whl", hash = "sha256:a2d225c8863a76d15468896dc5af36f1e196b403eb9c7e0151e77ffab9e7df57"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:b59b2c0a3b1d93027f6b6b8379a50c354483fe1ebe796c6740e157bb2e06d39a"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7222f3236c280fab3a2d76f903b493171f0ffc29667538cc388a5d5dd0216a88"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4b09191ed22af149c07a880f309b7740f3f782ff13325bae5c6168a6aa57e715"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216ff28fe803885ceb5b131dcee6507d28d255808dd5bcffcb3b5fa75be2e102"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-win32.whl", hash = "sha256:dde05ae0987e43ec84e64d6722ce66305eda2a5e2b7d6fda004b37aabdfbb909"}, - {file = "SQLAlchemy-1.4.17-cp38-cp38-win_amd64.whl", hash = "sha256:bc89e37c359dcd4d75b744e5e81af128ba678aa2ecea4be957e80e6e958a1612"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:4c5e20666b33b03bf7f14953f0deb93007bf8c1342e985bd7c7cf25f46fac579"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f63e1f531a8bf52184e2afb53648511f3f8534decb7575b483a583d3cd8d13ed"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7dc3d3285fb682316d580d84e6e0840fdd8ffdc05cb696db74b9dd746c729908"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58c02d1771bb0e61bc9ced8f3b36b5714d9ece8fd4bdbe2a44a892574c3bbc3c"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-win32.whl", hash = "sha256:6fe1c8dc26bc0005439cb78ebc78772a22cccc773f5a0e67cb3002d791f53f0f"}, - {file = "SQLAlchemy-1.4.17-cp39-cp39-win_amd64.whl", hash = "sha256:7eb55d5583076c03aaf1510473fad2a61288490809049cb31028af56af7068ee"}, - {file = "SQLAlchemy-1.4.17.tar.gz", hash = "sha256:651cdb3adcee13624ba22d5ff3e96f91e16a115d2ca489ddc16a8e4c217e8509"}, + {file = "SQLAlchemy-1.4.26-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c2f2114b0968a280f94deeeaa31cfbac9175e6ac7bd3058b3ce6e054ecd762b3"}, + {file = "SQLAlchemy-1.4.26-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91efbda4e6d311812f23996242bad7665c1392209554f8a31ec6db757456db5c"}, + {file = "SQLAlchemy-1.4.26-cp27-cp27m-win32.whl", hash = "sha256:de996756d894a2d52c132742e3b6d64ecd37e0919ddadf4dc3981818777c7e67"}, + {file = "SQLAlchemy-1.4.26-cp27-cp27m-win_amd64.whl", hash = "sha256:463ef692259ff8189be42223e433542347ae17e33f91c1013e9c5c64e2798088"}, + {file = "SQLAlchemy-1.4.26-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c757ba1279b85b3460e72e8b92239dae6f8b060a75fb24b3d9be984dd78cfa55"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:c24c01dcd03426a5fe5ee7af735906bec6084977b9027a3605d11d949a565c01"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c46f013ff31b80cbe36410281675e1fb4eaf3e25c284fd8a69981c73f6fa4cb4"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fb2aa74a6e3c2cebea38dd21633671841fbe70ea486053cba33d68e3e22ccc0a"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7e403fc1e3cb76e802872694e30d6ca6129b9bc6ad4e7caa48ca35f8a144f8"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-win32.whl", hash = "sha256:7ef421c3887b39c6f352e5022a53ac18de8387de331130481cb956b2d029cad6"}, + {file = "SQLAlchemy-1.4.26-cp310-cp310-win_amd64.whl", hash = "sha256:908fad32c53b17aad12d722379150c3c5317c422437e44032256a77df1746292"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:1ef37c9ec2015ce2f0dc1084514e197f2f199d3dc3514190db7620b78e6004c8"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:090536fd23bf49077ee94ff97142bc5ee8bad24294c3d7c8d5284267c885dde7"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e700d48056475d077f867e6a36e58546de71bdb6fdc3d34b879e3240827fefab"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:295b90efef1278f27fe27d94a45460ae3c17f5c5c2b32c163e29c359740a1599"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-win32.whl", hash = "sha256:cc6b21f19bc9d4cd77cbcba5f3b260436ce033f1053cea225b6efea2603d201e"}, + {file = "SQLAlchemy-1.4.26-cp36-cp36m-win_amd64.whl", hash = "sha256:ba84026e84379326bbf2f0c50792f2ae56ab9c01937df5597b6893810b8ca369"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f1e97c5f36b94542f72917b62f3a2f92be914b2cf33b80fa69cede7529241d2a"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c185c928e2638af9bae13acc3f70e0096eac76471a1101a10f96b80666b8270"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bca660b76672e15d70a7dba5e703e1ce451a0257b6bd2028e62b0487885e8ae9"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff8f91a7b1c4a1c7772caa9efe640f2768828897044748f2458b708f1026e2d4"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-win32.whl", hash = "sha256:a95bf9c725012dcd7ea3cac16bf647054e0d62b31d67467d228338e6a163e4ff"}, + {file = "SQLAlchemy-1.4.26-cp37-cp37m-win_amd64.whl", hash = "sha256:07ac4461a1116b317519ddf6f34bcb00b011b5c1370ebeaaf56595504ffc7e84"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:5039faa365e7522a8eb4736a54afd24a7e75dcc33b81ab2f0e6c456140f1ad64"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e8ef103eaa72a857746fd57dda5b8b5961e8e82a528a3f8b7e2884d8506f0b7"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:31f4426cfad19b5a50d07153146b2bcb372a279975d5fa39f98883c0ef0f3313"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2feb028dc75e13ba93456a42ac042b255bf94dbd692bf80b47b22653bb25ccf8"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-win32.whl", hash = "sha256:2ce42ad1f59eb85c55c44fb505f8854081ee23748f76b62a7f569cfa9b6d0604"}, + {file = "SQLAlchemy-1.4.26-cp38-cp38-win_amd64.whl", hash = "sha256:dbf588ab09e522ac2cbd010919a592c6aae2f15ccc3cd9a96d01c42fbc13f63e"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a6506c17b0b6016656783232d0bdd03fd333f1f654d51a14d93223f953903646"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a882dedb9dfa6f33524953c3e3d72bcf518a5defd6d5863150a821928b19ad3"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1dee515578d04bc80c4f9a8c8cfe93f455db725059e885f1b1da174d91c4d077"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c0c5f54560a92691d54b0768d67b4d3159e514b426cfcb1258af8c195577e8f"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-win32.whl", hash = "sha256:b86f762cee3709722ab4691981958cbec475ea43406a6916a7ec375db9cbd9e9"}, + {file = "SQLAlchemy-1.4.26-cp39-cp39-win_amd64.whl", hash = "sha256:5c6774b34782116ad9bdec61c2dbce9faaca4b166a0bc8e7b03c2b870b121d94"}, + {file = "SQLAlchemy-1.4.26.tar.gz", hash = "sha256:6bc7f9d7d90ef55e8c6db1308a8619cd8f40e24a34f759119b95e7284dca351a"}, ] sqlalchemy-utils = [ - {file = "SQLAlchemy-Utils-0.37.8.tar.gz", hash = "sha256:a6aaee154f798be4e479af0ceffaa5034d35fcf6f40707c0947d21bde64e05e5"}, - {file = "SQLAlchemy_Utils-0.37.8-py3-none-any.whl", hash = "sha256:b1bf67d904fed16b16ef1dc07f03e5e93a6b23899f920f6b41c09be45fbb85f2"}, + {file = "SQLAlchemy-Utils-0.37.9.tar.gz", hash = "sha256:4667edbdcb1ece011076b69772ef524bfbb17cc97e03f11ee6b85d98e7741d61"}, + {file = "SQLAlchemy_Utils-0.37.9-py3-none-any.whl", hash = "sha256:bb6f4da8ac044cb0dd4d0278b1fb434141a5ee9d1881c757a076830ddbb04160"}, ] starlette = [ {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, @@ -1412,13 +1504,13 @@ text-unidecode = [ {file = "text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, - {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, - {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ - {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, - {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, ] uvicorn = [ {file = "uvicorn-0.14.0-py3-none-any.whl", hash = "sha256:2a76bb359171a504b3d1c853409af3adbfa5cef374a4a59e5881945a97a93eae"}, @@ -1429,6 +1521,6 @@ wcwidth = [ {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, ] zipp = [ - {file = "zipp-3.4.1-py3-none-any.whl", hash = "sha256:51cb66cc54621609dd593d1787f286ee42a5c0adbb4b29abea5a63edc3e03098"}, - {file = "zipp-3.4.1.tar.gz", hash = "sha256:3607921face881ba3e026887d8150cca609d517579abe052ac81fc5aeffdbd76"}, + {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, + {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, ] diff --git a/pyproject.toml b/pyproject.toml index 060d495..964af2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ SQLAlchemy-Utils = "^0.37.8" pytest = "^5.2" httpx = "^0.19.0" pytest-asyncio = "^0.15.1" +pytest-order = "^1.0.0" [build-system] requires = ["poetry-core>=1.0.0"] From 93203cde9a7adcd53edd0dd262d069f746e324b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 19:12:31 -0300 Subject: [PATCH 55/61] test sota route --- app/test/route_tests/test_model_route.py | 3 +- app/test/route_tests/test_sota_route.py | 60 ++++++++++++++++++++++++ app/test/utils/constants.py | 33 +++++++++++-- 3 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 app/test/route_tests/test_sota_route.py diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index 723a3be..b87c36e 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -3,11 +3,9 @@ from app.main import app from app.test.utils.constants import ( - MODEL_KEYS, SUCCESS, TASK_MODEL, DATASET_MODEL, - ACCURACY_TOP1, MODEL_TASK_DATASET_KEYS, MODEL_CSV_KEYS ) @@ -23,6 +21,7 @@ async def test_model_get_id(headers: dict, base_url: str, get_test_model: Respon @pytest.mark.asyncio +@pytest.mark.order(-1) async def test_model_put(headers: dict, base_url: str, get_test_model: Response): model_id = get_test_model["id"] put_body = {**get_test_model, "name": "fooo", "gflops": 2.0, "epochs": 3} diff --git a/app/test/route_tests/test_sota_route.py b/app/test/route_tests/test_sota_route.py new file mode 100644 index 0000000..ec4fe97 --- /dev/null +++ b/app/test/route_tests/test_sota_route.py @@ -0,0 +1,60 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + SOTA_KEYS, + SUCCESS, + TASK_MODEL, + TASK_DESCRIPTION, + DATASET_MODEL, +) + + +@pytest.mark.asyncio +async def test_sota_get(headers: dict, base_url: str, get_test_model: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/sota/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == SOTA_KEYS + + +@pytest.mark.asyncio +async def test_sota_get_id( + base_url: str, + headers: dict, + get_test_model: Response, + submission_approved_created: Response, +): + submission_data = { + "sota_accuracy_value": submission_approved_created["data"]["models"][0][ + "accuracies" + ][0]["value"], + "sota_paper_publication_date": submission_approved_created["data"][ + "publication_date" + ], + "accuracy_name": submission_approved_created["data"]["models"][0]["accuracies"][ + 0 + ]["accuracy_type"], + "sota_paper_link": submission_approved_created["data"]["link"], + "sota_paper_title": submission_approved_created["data"]["title"], + "sota_name": submission_approved_created["data"]["models"][0]["name"] + } + sota_json = { + **TASK_MODEL, + "task_description": TASK_DESCRIPTION, + "datasets": [ + { + **DATASET_MODEL, + **submission_data, + "task_dataset_id": get_test_model["task_dataset_id"], + "sota_id": get_test_model["id"], + "sota_hardware_burden": get_test_model["hardware_burden"], + } + ], + } + task_id = sota_json["task_id"] + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/sota/{task_id}") + assert response.status_code == SUCCESS + assert sota_json == response.json() diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index b46de4d..d273c1c 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -70,6 +70,16 @@ "task_id": 10 } +TASK_DESCRIPTION = ( + "Image Classification is a fundamental task that attempts to" + + " comprehend an entire image as a whole. The goal is to classify" + + " the image by assigning it to a specific label. Typically," + + " Image Classification refers to images in which only one object" + + " appears and is analyzed. In contrast, object detection involves" + + " both classification and localization tasks, and is used to analyze." + # + " more realistic cases in which multiple objects may exist in an image." +) + # END TASK CONSTANTS # ================================ @@ -248,16 +258,16 @@ } SUBMISSION_ALT_BODY = { - "title": "string", - "link": "string", - "code_link": "string", + "title": "sub_title_alt", + "link": "linking", + "code_link": "lonk", "publication_date": "2021-10-30", "authors": [ - "string" + "DiCaprio" ], "models": [ { - "name": "string", + "name": "oscar", "task": TASK_MODEL["task_name"], "dataset": DATASET_MODEL["dataset_name"], "cpu": CPU_BODY["name"], @@ -452,3 +462,16 @@ # END MODEL CONSTANTS # ================================ + +# ================================ +# BEGIN SOTA CONSTANTS + + +SOTA_KEYS = { + *[x for x in TASK_MODEL if x != "task_image"], + "datasets" +} + + +# END SOTA CONSTANTS +# ================================ \ No newline at end of file From afb1ad6af84da7e2bcb9ab06a0b93aa4657d98cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 19:39:18 -0300 Subject: [PATCH 56/61] test paper with code get route --- app/test/route_tests/test_metrics_route.py | 58 ++++++++++++++++++++++ app/test/utils/constants.py | 19 +++++++ 2 files changed, 77 insertions(+) create mode 100644 app/test/route_tests/test_metrics_route.py diff --git a/app/test/route_tests/test_metrics_route.py b/app/test/route_tests/test_metrics_route.py new file mode 100644 index 0000000..0b2f3a2 --- /dev/null +++ b/app/test/route_tests/test_metrics_route.py @@ -0,0 +1,58 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + METRICS_KEYS, + SUCCESS, + TASK_DATASET_IDENTIFIER +) + + +@pytest.mark.asyncio +async def test_paper_with_code_get(headers: dict, base_url: str, get_test_model: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get(f"/metrics/{TASK_DATASET_IDENTIFIER}/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == METRICS_KEYS + + +# @pytest.mark.asyncio +# async def test_sota_get_id( +# base_url: str, +# headers: dict, +# get_test_model: Response, +# submission_approved_created: Response, +# ): +# submission_data = { +# "sota_accuracy_value": submission_approved_created["data"]["models"][0][ +# "accuracies" +# ][0]["value"], +# "sota_paper_publication_date": submission_approved_created["data"][ +# "publication_date" +# ], +# "accuracy_name": submission_approved_created["data"]["models"][0]["accuracies"][ +# 0 +# ]["accuracy_type"], +# "sota_paper_link": submission_approved_created["data"]["link"], +# "sota_paper_title": submission_approved_created["data"]["title"], +# "sota_name": submission_approved_created["data"]["models"][0]["name"] +# } +# sota_json = { +# **TASK_MODEL, +# "task_description": TASK_DESCRIPTION, +# "datasets": [ +# { +# **DATASET_MODEL, +# **submission_data, +# "task_dataset_id": get_test_model["task_dataset_id"], +# "sota_id": get_test_model["id"], +# "sota_hardware_burden": get_test_model["hardware_burden"], +# } +# ], +# } +# task_id = sota_json["task_id"] +# async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: +# response = await ac.get(f"/sota/{task_id}") +# assert response.status_code == SUCCESS +# assert sota_json == response.json() \ No newline at end of file diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index d273c1c..8a4ab36 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -80,6 +80,8 @@ # + " more realistic cases in which multiple objects may exist in an image." ) +TASK_DATASET_IDENTIFIER = "image-classification-on-imagenet" + # END TASK CONSTANTS # ================================ @@ -474,4 +476,21 @@ # END SOTA CONSTANTS +# ================================ + +# ================================ +# BEGIN METRICS CONSTANTS + + +METRICS_KEYS = { + "tasks_dataset_identifier", + "model_identifier", + "model_name", + "model_hardware_burden", + "model_operation_per_network_pass", + "paper_identifier" +} + + +# END METRICS CONSTANTS # ================================ \ No newline at end of file From 1e8aa1a8d8f0364d5bce1ff271f985b0662bdcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Aquiles=20Guedes=20de=20Rezende?= Date: Mon, 1 Nov 2021 20:07:36 -0300 Subject: [PATCH 57/61] test paper with code get model route --- app/test/route_tests/test_metrics_route.py | 80 +++++++++------------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/app/test/route_tests/test_metrics_route.py b/app/test/route_tests/test_metrics_route.py index 0b2f3a2..68f815e 100644 --- a/app/test/route_tests/test_metrics_route.py +++ b/app/test/route_tests/test_metrics_route.py @@ -2,57 +2,45 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import ( - METRICS_KEYS, - SUCCESS, - TASK_DATASET_IDENTIFIER -) +from app.test.utils.constants import METRICS_KEYS, SUCCESS, TASK_DATASET_IDENTIFIER + + +def make_id(name: str): + return name.replace(" ", "-").replace("_", "-").lower() @pytest.mark.asyncio -async def test_paper_with_code_get(headers: dict, base_url: str, get_test_model: Response): +async def test_paper_with_code_get( + headers: dict, base_url: str, get_test_model: Response +): async with AsyncClient(app=app, base_url=base_url) as ac: - response = await ac.get(f"/metrics/{TASK_DATASET_IDENTIFIER}/?skip=0&limit=1", headers=headers) + response = await ac.get( + f"/metrics/{TASK_DATASET_IDENTIFIER}/?skip=0&limit=1", headers=headers + ) assert response.status_code == SUCCESS assert set(response.json()[0].keys()) == METRICS_KEYS -# @pytest.mark.asyncio -# async def test_sota_get_id( -# base_url: str, -# headers: dict, -# get_test_model: Response, -# submission_approved_created: Response, -# ): -# submission_data = { -# "sota_accuracy_value": submission_approved_created["data"]["models"][0][ -# "accuracies" -# ][0]["value"], -# "sota_paper_publication_date": submission_approved_created["data"][ -# "publication_date" -# ], -# "accuracy_name": submission_approved_created["data"]["models"][0]["accuracies"][ -# 0 -# ]["accuracy_type"], -# "sota_paper_link": submission_approved_created["data"]["link"], -# "sota_paper_title": submission_approved_created["data"]["title"], -# "sota_name": submission_approved_created["data"]["models"][0]["name"] -# } -# sota_json = { -# **TASK_MODEL, -# "task_description": TASK_DESCRIPTION, -# "datasets": [ -# { -# **DATASET_MODEL, -# **submission_data, -# "task_dataset_id": get_test_model["task_dataset_id"], -# "sota_id": get_test_model["id"], -# "sota_hardware_burden": get_test_model["hardware_burden"], -# } -# ], -# } -# task_id = sota_json["task_id"] -# async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: -# response = await ac.get(f"/sota/{task_id}") -# assert response.status_code == SUCCESS -# assert sota_json == response.json() \ No newline at end of file +@pytest.mark.asyncio +async def test_paper_with_code_get_model( + base_url: str, + headers: dict, + get_test_model: Response, + submission_approved_created: Response, +): + model_identifier = make_id(get_test_model["name"]) + paper_identifier = make_id(submission_approved_created["data"]["title"]) + + metrics_json = { + "tasks_dataset_identifier": TASK_DATASET_IDENTIFIER, + "model_identifier": model_identifier, + "model_name": get_test_model["name"], + "model_hardware_burden": get_test_model["hardware_burden"], + "paper_identifier": paper_identifier, + } + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get( + f"/metrics/{TASK_DATASET_IDENTIFIER}/{get_test_model['name']}" + ) + assert response.status_code == SUCCESS + assert set(metrics_json.items()) <= set(response.json().items()) From 77abdd23b3ff7f86bae9fea0d08b0f866b324bdb Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 2 Nov 2021 03:21:00 -0300 Subject: [PATCH 58/61] Fixing sota test and model test warning --- app/test/route_tests/test_model_route.py | 1 - app/test/route_tests/test_sota_route.py | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/test/route_tests/test_model_route.py b/app/test/route_tests/test_model_route.py index b87c36e..0205d63 100644 --- a/app/test/route_tests/test_model_route.py +++ b/app/test/route_tests/test_model_route.py @@ -21,7 +21,6 @@ async def test_model_get_id(headers: dict, base_url: str, get_test_model: Respon @pytest.mark.asyncio -@pytest.mark.order(-1) async def test_model_put(headers: dict, base_url: str, get_test_model: Response): model_id = get_test_model["id"] put_body = {**get_test_model, "name": "fooo", "gflops": 2.0, "epochs": 3} diff --git a/app/test/route_tests/test_sota_route.py b/app/test/route_tests/test_sota_route.py index ec4fe97..976c9d5 100644 --- a/app/test/route_tests/test_sota_route.py +++ b/app/test/route_tests/test_sota_route.py @@ -56,5 +56,9 @@ async def test_sota_get_id( task_id = sota_json["task_id"] async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get(f"/sota/{task_id}") + print(response.json()) + print(sota_json) assert response.status_code == SUCCESS - assert sota_json == response.json() + assert sota_json.keys() == response.json().keys() + for i in range(len(sota_json['datasets'])): + assert sota_json['datasets'][0].keys() == response.json()['datasets'][0].keys() From a6edf8e1102435308cc4cf3cc7caece06551e9e2 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 2 Nov 2021 03:51:54 -0300 Subject: [PATCH 59/61] Adding failure case tests to datasets route --- app/test/route_tests/test_datasets_route.py | 43 +++++++++++++++++- app/test/utils/constants.py | 48 ++++++++++++++++++++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index 3fc28f5..94800c4 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -2,7 +2,18 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import DATASETS_BODY, DATASETS_KEYS, SUCCESS +from app.test.utils.constants import ( + DATASETS_BODY, + DATASETS_KEYS, + DATASETS_BODY_FAIL, + DATASETS_INVALID_BODY, + DATASETS_NO_BODY_FAIL, + DATASETS_INVALID_GET, + DATASETS_INVALID_GET_ID, + SUCCESS, + VALIDATION_ERR, + NOT_FOUND +) def test_datasets_post(datasets_created: Response): @@ -49,3 +60,33 @@ async def test_datasets_put(base_url: str, headers: dict, datasets_created: Resp print(response.json()) assert response.status_code == SUCCESS assert {**put_json, "id": datasets_id} == response.json() + +@pytest.mark.asyncio +async def test_datasets_post_invalid_fail(base_url: str, headers: dict, datasets_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post('/datasets', json=DATASETS_BODY_FAIL) + assert response.status_code == VALIDATION_ERR + assert response.json() == DATASETS_INVALID_BODY + +@pytest.mark.asyncio +async def test_datasets_post_no_body_fail(base_url: str, headers: dict, datasets_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post('/datasets') + assert response.status_code == VALIDATION_ERR + assert response.json() == DATASETS_NO_BODY_FAIL + +@pytest.mark.asyncio +async def test_datasets_get(headers: dict, base_url: str, datasets_created: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/datasets/?skip=b&limit=a", headers=headers) + assert response.status_code == VALIDATION_ERR + assert response.json() == DATASETS_INVALID_GET + +@pytest.mark.asyncio +async def test_datasets_get_id( + base_url: str, headers: dict, datasets_created: Response +): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/datasets/999999") + assert response.status_code == NOT_FOUND + assert DATASETS_INVALID_GET_ID == response.json() diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 8a4ab36..38f5657 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -12,6 +12,7 @@ BAD_REQUEST = 400 UNAUTHORIZED = 401 FORBIDDEN = 403 +VALIDATION_ERR = 422 METHOD_NOT_ALLOWED = 405 SERVER_ERROR = 500 @@ -37,6 +38,51 @@ "dataset_name": "Imagenet", } +DATASETS_BODY_FAIL = { + "name": "string", + "image": "string", + "description": "string", + "source": [], +} + +DATASETS_INVALID_BODY = { + 'detail': [ + { + 'loc': ['body', 'source'], + 'msg': 'str type expected', + 'type': 'type_error.str' + } + ] +} + +DATASETS_NO_BODY_FAIL = { + 'detail': [ + { + 'loc': ['body'], + 'msg': 'field required', + 'type': 'value_error.missing' + } + ] +} + +DATASETS_INVALID_GET = { + 'detail': [ + { + 'loc': ['query', 'skip'], + 'msg': 'value is not a valid integer', + 'type': 'type_error.integer' + }, + { + 'loc': ['query', 'limit'], + 'msg': 'value is not a valid integer', + 'type': 'type_error.integer' + } + ] +} + +DATASETS_INVALID_GET_ID = { 'detail': 'Dataset not found' } + + # END DATASETS CONSTANTS # ================================ @@ -493,4 +539,4 @@ # END METRICS CONSTANTS -# ================================ \ No newline at end of file +# ================================ From d8ca7f7d04ba9960afa14a4362504810b3907e4f Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 2 Nov 2021 04:21:56 -0300 Subject: [PATCH 60/61] Adding failure test case for task route and fix datasets const --- app/test/route_tests/test_datasets_route.py | 4 +- app/test/route_tests/test_task_route.py | 42 ++++++++++++++++++++- app/test/utils/constants.py | 39 +++++++++++-------- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/app/test/route_tests/test_datasets_route.py b/app/test/route_tests/test_datasets_route.py index 94800c4..918f3bc 100644 --- a/app/test/route_tests/test_datasets_route.py +++ b/app/test/route_tests/test_datasets_route.py @@ -8,7 +8,7 @@ DATASETS_BODY_FAIL, DATASETS_INVALID_BODY, DATASETS_NO_BODY_FAIL, - DATASETS_INVALID_GET, + INVALID_GET_PARAM, DATASETS_INVALID_GET_ID, SUCCESS, VALIDATION_ERR, @@ -80,7 +80,7 @@ async def test_datasets_get(headers: dict, base_url: str, datasets_created: Resp async with AsyncClient(app=app, base_url=base_url) as ac: response = await ac.get("/datasets/?skip=b&limit=a", headers=headers) assert response.status_code == VALIDATION_ERR - assert response.json() == DATASETS_INVALID_GET + assert response.json() == INVALID_GET_PARAM @pytest.mark.asyncio async def test_datasets_get_id( diff --git a/app/test/route_tests/test_task_route.py b/app/test/route_tests/test_task_route.py index 065b9cc..2a7378c 100644 --- a/app/test/route_tests/test_task_route.py +++ b/app/test/route_tests/test_task_route.py @@ -2,9 +2,18 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import TASK_KEYS, TASK, NEW_TASK, SUCCESS - +from app.test.utils.constants import ( + TASK_KEYS, + TASK, + NEW_TASK, + TASK_FAIL, + VALIDATION_ERR, + NOT_FOUND, + INVALID_GET_PARAM, + SUCCESS +) +@pytest.mark.order(1) def test_task_creation(task_created: Response): json = task_created.json() assert json.keys() == TASK_KEYS.keys() @@ -13,6 +22,7 @@ def test_task_creation(task_created: Response): @pytest.mark.asyncio +@pytest.mark.order(2) async def test_task_get(base_url: str, headers: dict, task_created: Response): async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: response = await ac.get("/tasks") @@ -22,6 +32,7 @@ async def test_task_get(base_url: str, headers: dict, task_created: Response): @pytest.mark.asyncio +@pytest.mark.order(3) async def test_task_put(base_url: str, headers: dict, task_created: Response): res = task_created.json() @@ -32,3 +43,30 @@ async def test_task_put(base_url: str, headers: dict, task_created: Response): for key in NEW_TASK.keys(): assert NEW_TASK[key] == json[key] assert json.keys() == TASK_KEYS.keys() + +# @pytest.mark.asyncio +# @pytest.mark.order(4) +# async def test_task_delete(base_url: str, headers: dict, task_created: Response): +# id = task_created.json()['id'] +# +# async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: +# response = await ac.delete(f"/tasks/{id}") +# assert response.status_code == SUCCESS +# assert response.json().keys() == task_created.json().keys() + + +@pytest.mark.asyncio +@pytest.mark.order(5) +async def test_task_creation_fail(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/tasks") + assert response.status_code == VALIDATION_ERR + assert response.json() == TASK_FAIL + +@pytest.mark.asyncio +@pytest.mark.order(6) +async def test_task_get_fail(base_url: str, headers: dict, task_created: Response): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get("/tasks?skip=a&limit=b") + assert response.status_code == VALIDATION_ERR + assert response.json() == INVALID_GET_PARAM diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index 38f5657..b198e4c 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -19,6 +19,20 @@ # END STATUS_CODE CONSTANTS # ================================ +INVALID_GET_PARAM = { + 'detail': [ + { + 'loc': ['query', 'skip'], + 'msg': 'value is not a valid integer', + 'type': 'type_error.integer' + }, + { + 'loc': ['query', 'limit'], + 'msg': 'value is not a valid integer', + 'type': 'type_error.integer' + } + ] +} # ================================ # BEGIN DATASETS CONSTANTS @@ -65,21 +79,6 @@ ] } -DATASETS_INVALID_GET = { - 'detail': [ - { - 'loc': ['query', 'skip'], - 'msg': 'value is not a valid integer', - 'type': 'type_error.integer' - }, - { - 'loc': ['query', 'limit'], - 'msg': 'value is not a valid integer', - 'type': 'type_error.integer' - } - ] -} - DATASETS_INVALID_GET_ID = { 'detail': 'Dataset not found' } @@ -128,6 +127,16 @@ TASK_DATASET_IDENTIFIER = "image-classification-on-imagenet" +TASK_FAIL = { + 'detail': [ + { + 'loc': ['body'], + 'msg': 'field required', + 'type': 'value_error.missing' + } + ] +} + # END TASK CONSTANTS # ================================ From c9960a0fa4396b44a97310503f8ff3616b526633 Mon Sep 17 00:00:00 2001 From: Gabriel Tiveron Date: Tue, 2 Nov 2021 04:41:17 -0300 Subject: [PATCH 61/61] Adding accuracy failure test cases --- .../route_tests/test_accuracy_type_route.py | 38 +++++++++++++++++-- app/test/utils/constants.py | 14 +++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/app/test/route_tests/test_accuracy_type_route.py b/app/test/route_tests/test_accuracy_type_route.py index 6ef0734..b6bd22a 100644 --- a/app/test/route_tests/test_accuracy_type_route.py +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -2,10 +2,17 @@ from httpx import AsyncClient, Response from app.main import app -from app.test.utils.constants import ACCURACY_BODY, \ - ACCURACY_KEYS_GET,\ - ACCURACY_KEYS, \ - SUCCESS +from app.test.utils.constants import ( + ACCURACY_BODY, + ACCURACY_KEYS_GET, + ACCURACY_KEYS, + ACCURACY_NO_BODY_FAIL, + INVALID_GET_PARAM, + ACCURACY_INVALID_GET_ID, + VALIDATION_ERR, + NOT_FOUND, + SUCCESS +) @pytest.fixture(scope="module") @@ -58,3 +65,26 @@ async def test_accuracy_put(base_url: str, headers: dict, accuracy_created: Resp response = await ac.put(f"/accuracy_types/{accuracy_id}", json=put_json) assert response.status_code == SUCCESS assert {**put_json, "id": accuracy_id} == response.json() + +@pytest.mark.asyncio +async def test_accuracy_creation_fail(base_url: str, headers: dict): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.post("/accuracy_types") + assert response.status_code == VALIDATION_ERR + assert response.json() == ACCURACY_NO_BODY_FAIL + +@pytest.mark.asyncio +async def test_accuracy_get_fail(headers: dict, base_url: str, accuracy_created: Response): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.get("/accuracy_types/?skip=a&limit=b", headers=headers) + assert response.status_code == VALIDATION_ERR + assert response.json() == INVALID_GET_PARAM + +@pytest.mark.asyncio +async def test_accuracy_get_id_fail( + base_url: str, headers: dict, accuracy_created: Response +): + async with AsyncClient(app=app, base_url=base_url, headers=headers) as ac: + response = await ac.get(f"/accuracy_types/999999") + assert response.status_code == NOT_FOUND + assert ACCURACY_INVALID_GET_ID == response.json() diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py index b198e4c..c4e7446 100644 --- a/app/test/utils/constants.py +++ b/app/test/utils/constants.py @@ -79,6 +79,8 @@ ] } + + DATASETS_INVALID_GET_ID = { 'detail': 'Dataset not found' } @@ -157,6 +159,18 @@ "main": True } +ACCURACY_NO_BODY_FAIL = { + 'detail': [ + { + 'loc': ['body'], + 'msg': 'field required', + 'type': 'value_error.missing' + } + ] +} + +ACCURACY_INVALID_GET_ID = {'detail': 'AccuracyType not found'} + # END ACCURACY CONSTANTS # ================================