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 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. 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/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/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/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 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 new file mode 100644 index 0000000..1ccce0c --- /dev/null +++ b/app/test/conftest.py @@ -0,0 +1,60 @@ +import pytest +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 +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 ( + 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()) + +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') + +else: + _ = system('clear') + +@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(scope="session") +async def headers(base_url) -> dict: + 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/__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..157fbd0 --- /dev/null +++ b/app/test/route_tests/conftest.py @@ -0,0 +1,142 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + DATASETS_KEYS, + DATASETS_BODY, + TASK_KEYS, + 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 + + +@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: + 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 == SUCCESS + 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) + a = response.json() + 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 == SUCCESS + assert response.json().keys() == TASK_KEYS.keys() + + +@pytest.fixture(scope="session") +async def submission_approved_created( + base_url: str, + headers: dict, + 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, + 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") +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"/papers/{paper_id}") + assert response.status_code == SUCCESS + assert PAPER_KEYS == set(response.json().keys()) 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..b6bd22a --- /dev/null +++ b/app/test/route_tests/test_accuracy_type_route.py @@ -0,0 +1,90 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +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") +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=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 == SUCCESS + assert ACCURACY_KEYS == set(response.json().keys()) + + +def test_accuracy_post(accuracy_created: Response): + assert accuracy_created.status_code == SUCCESS + assert accuracy_created.json().items() >= ACCURACY_BODY.items() + assert set(accuracy_created.json().keys()) == ACCURACY_KEYS + + +@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("/accuracy_types/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == ACCURACY_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 == SUCCESS + 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 == 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/route_tests/test_cpu_route.py b/app/test/route_tests/test_cpu_route.py new file mode 100644 index 0000000..2cadaff --- /dev/null +++ b/app/test/route_tests/test_cpu_route.py @@ -0,0 +1,39 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +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() + assert set(cpu_created.json().keys()) == CPU_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("/cpus/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == CPU_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 == SUCCESS + 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"] + 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 == 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 new file mode 100644 index 0000000..918f3bc --- /dev/null +++ b/app/test/route_tests/test_datasets_route.py @@ -0,0 +1,92 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + DATASETS_BODY, + DATASETS_KEYS, + DATASETS_BODY_FAIL, + DATASETS_INVALID_BODY, + DATASETS_NO_BODY_FAIL, + INVALID_GET_PARAM, + DATASETS_INVALID_GET_ID, + SUCCESS, + VALIDATION_ERR, + NOT_FOUND +) + + +def test_datasets_post(datasets_created: Response): + assert datasets_created.status_code == SUCCESS + assert datasets_created.json().items() >= DATASETS_BODY.items() + assert set(datasets_created.json().keys()) == DATASETS_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("/datasets/?skip=0&limit=1", headers=headers) + assert response.status_code == SUCCESS + assert set(response.json()[0].keys()) == DATASETS_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 == SUCCESS + 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"] + print(datasets_id) + put_json = { + "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() + +@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() == INVALID_GET_PARAM + +@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/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/route_tests/test_login_route.py b/app/test/route_tests/test_login_route.py new file mode 100644 index 0000000..55a441b --- /dev/null +++ b/app/test/route_tests/test_login_route.py @@ -0,0 +1,19 @@ +import pytest +from httpx import AsyncClient + +from app.main import app +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 == SUCCESS + json = response.json() + + 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_metrics_route.py b/app/test/route_tests/test_metrics_route.py new file mode 100644 index 0000000..68f815e --- /dev/null +++ b/app/test/route_tests/test_metrics_route.py @@ -0,0 +1,46 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +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 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_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()) 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..0205d63 --- /dev/null +++ b/app/test/route_tests/test_model_route.py @@ -0,0 +1,63 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import ( + SUCCESS, + TASK_MODEL, + DATASET_MODEL, + MODEL_TASK_DATASET_KEYS, + MODEL_CSV_KEYS +) + + +@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_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} + 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 {**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()) + + +@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" + ) + 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/route_tests/test_paper_route.py b/app/test/route_tests/test_paper_route.py new file mode 100644 index 0000000..17b8c8c --- /dev/null +++ b/app/test/route_tests/test_paper_route.py @@ -0,0 +1,46 @@ +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, + PAPER_NEW, + 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 + + +@pytest.mark.asyncio +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 +) -> 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() + + +@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/route_tests/test_sota_route.py b/app/test/route_tests/test_sota_route.py new file mode 100644 index 0000000..976c9d5 --- /dev/null +++ b/app/test/route_tests/test_sota_route.py @@ -0,0 +1,64 @@ +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}") + print(response.json()) + print(sota_json) + assert response.status_code == SUCCESS + 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() 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..2cf880d --- /dev/null +++ b/app/test/route_tests/test_submission_route.py @@ -0,0 +1,102 @@ +import pytest +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,\ + SUCCESS + + +@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 == 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 == SUCCESS + 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 == SUCCESS + 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('/submissions') + assert response.status_code == SUCCESS + assert response.json()[0].keys() == SUBMISSION_KEYS.keys() + + +@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 == SUCCESS + 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 == SUCCESS + 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': SUBMISSION_MSG_RES['body']}) + 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() + + +@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 == 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 new file mode 100644 index 0000000..2a7378c --- /dev/null +++ b/app/test/route_tests/test_task_route.py @@ -0,0 +1,72 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +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() + for key in TASK: + assert json[key] == TASK[key] + + +@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") + res_json = response.json() + assert response.status_code == SUCCESS + assert isinstance(res_json, list) + + +@pytest.mark.asyncio +@pytest.mark.order(3) +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 == SUCCESS + 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/route_tests/test_tpu_route.py b/app/test/route_tests/test_tpu_route.py new file mode 100644 index 0000000..775cded --- /dev/null +++ b/app/test/route_tests/test_tpu_route.py @@ -0,0 +1,46 @@ +import pytest +from httpx import AsyncClient, Response + +from app.main import app +from app.test.utils.constants import TPU_BODY, TPU_NEW, SUCCESS + + +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 == SUCCESS + assert json.pop('id', None) == 1 + assert json.items() == TPU_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 == SUCCESS + 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 == SUCCESS + + 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"] + + 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 == 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 new file mode 100644 index 0000000..8bfdb3f --- /dev/null +++ b/app/test/route_tests/test_user_route.py @@ -0,0 +1,75 @@ +import pytest +from httpx import AsyncClient + +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, \ + SUCCESS + + +@pytest.fixture(scope="module") +async def user_created(base_url): + async with AsyncClient(app=app, base_url=base_url) as ac: + response = await ac.post("/users/open", json=USER_BODY) + return response + + +def test_user_create(user_created): + assert user_created.status_code == SUCCESS + assert set(user_created.json().keys()) == USER_KEYS + + +@pytest.mark.asyncio +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 == SUCCESS + del USER_BODY_AUTH["password"] + assert USER_BODY_AUTH.items() <= response.json().items() + assert set(response.json().keys()) == USER_KEYS + + +@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 == SUCCESS + 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("/users/me", headers=headers) + json = response.json() + assert response.status_code == SUCCESS + 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"] + 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 == SUCCESS + 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): + 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 == SUCCESS + assert USER_SUPERUSER_NEW.items() <= response.json().items() + assert set(response.json().keys()) == USER_KEYS 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' diff --git a/app/test/utils/constants.py b/app/test/utils/constants.py new file mode 100644 index 0000000..c4e7446 --- /dev/null +++ b/app/test/utils/constants.py @@ -0,0 +1,565 @@ +from app.settings import settings + +''' +Test constants +''' + +# ================================ +# BEGIN STATUS_CODE CONSTANTS + +SUCCESS = 200 +NOT_FOUND = 404 +BAD_REQUEST = 400 +UNAUTHORIZED = 401 +FORBIDDEN = 403 +VALIDATION_ERR = 422 +METHOD_NOT_ALLOWED = 405 +SERVER_ERROR = 500 + +# 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 + +DATASETS_BODY = { + "name": "string", + "image": "string", + "description": "string", + "source": "string", + "identifier": "string", +} +DATASETS_KEYS = {*DATASETS_BODY, "id"} + +DATASET_MODEL = { + "dataset_id": 10, + "dataset_identifier": "imagenet", + "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_ID = { 'detail': 'Dataset not found' } + + +# 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", +} + +TASK_MODEL = { + "task_name": "Image Classification", + "task_image": "https://computerprogress.xyz/image/image-classification.svg", + "task_identifier": "image-classification", + "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." +) + +TASK_DATASET_IDENTIFIER = "image-classification-on-imagenet" + +TASK_FAIL = { + 'detail': [ + { + 'loc': ['body'], + 'msg': 'field required', + 'type': 'value_error.missing' + } + ] +} + +# 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"} + +ACCURACY_TOP1 = { + "name": "TOP 1", + "description": None, + "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 +# ================================ + +# ================================ +# 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 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" +} + +GPU_NEW = { + **GPU_BODY, + "tdp": 222 +} + +# END GPU 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_ALT_BODY = { + "title": "sub_title_alt", + "link": "linking", + "code_link": "lonk", + "publication_date": "2021-10-30", + "authors": [ + "DiCaprio" + ], + "models": [ + { + "name": "oscar", + "task": TASK_MODEL["task_name"], + "dataset": DATASET_MODEL["dataset_name"], + "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": ACCURACY_TOP1["name"], + "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, + "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 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 +# ================================ + +# ================================ +# 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" +} + +PAPER_NEW = { + **PAPER_GET, + "title": "foofoo", + "code_link": "barbar" +} + +# END PAPER CONSTANTS +# ================================ + +# ================================ +# 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", + "paper_id", + "cpu_id", + "tpu_id", + "gpu_id", + "id" +} + +MODEL_TASK_DATASET_KEYS = { + *TASK_MODEL, + *DATASET_MODEL, + "accuracy_types", + "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 +# ================================ + +# ================================ +# BEGIN SOTA CONSTANTS + + +SOTA_KEYS = { + *[x for x in TASK_MODEL if x != "task_image"], + "datasets" +} + + +# 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 +# ================================ 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/app/test/utils/overrides.py b/app/test/utils/overrides.py new file mode 100644 index 0000000..5c0e0e6 --- /dev/null +++ b/app/test/utils/overrides.py @@ -0,0 +1,9 @@ +from .test_db import TestSessionLocal + + +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 new file mode 100644 index 0000000..556bbc2 --- /dev/null +++ b/app/test/utils/test_db.py @@ -0,0 +1,22 @@ +from pydantic import PostgresDsn +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", + 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, 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')) 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..1da7341 100644 --- a/poetry.lock +++ b/poetry.lock @@ -8,21 +8,42 @@ 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 = "asgiref" +name = "anyio" version = "3.3.4" +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.4.1" description = "ASGI specs, helper code, and adapters" category = "main" optional = false @@ -74,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 @@ -82,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 @@ -90,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 @@ -107,9 +128,20 @@ 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.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" -version = "8.0.1" +version = "8.0.3" description = "Composable command line interface toolkit" category = "main" optional = false @@ -182,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" @@ -210,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 @@ -223,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 @@ -245,17 +277,52 @@ category = "main" optional = false python-versions = ">=3.6" +[[package]] +name = "httpcore" +version = "0.13.7" +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" +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 @@ -267,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 @@ -299,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 @@ -322,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 @@ -330,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" @@ -393,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 @@ -412,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" @@ -490,9 +586,34 @@ 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 = "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 @@ -503,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" @@ -565,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 @@ -573,21 +686,35 @@ 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" +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" @@ -608,29 +735,38 @@ 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" +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"] @@ -640,6 +776,32 @@ postgresql_psycopg2cffi = ["psycopg2cffi"] pymysql = ["pymysql (<1)", "pymysql"] sqlcipher = ["sqlcipher3-binary"] +[[package]] +name = "sqlalchemy-utils" +version = "0.37.9" +description = "Various utility functions for SQLAlchemy." +category = "main" +optional = false +python-versions = "~=3.4" + +[package.dependencies] +six = "*" +SQLAlchemy = ">=1.0" + +[package.extras] +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)", "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" @@ -661,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 @@ -669,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 @@ -707,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 @@ -715,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 = "15b24a5caddedf68823f793cf0b1bf157d87c42c7a4955142b67412e187cd97f" +content-hash = "0f30f2faf5535e0b799a1882c6f77e93ab3253b33e54af785c5571b24449e055" [metadata.files] aiofiles = [ @@ -728,12 +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.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"}, @@ -753,71 +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.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"}, @@ -840,83 +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.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"}, @@ -926,6 +1110,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"}, @@ -967,16 +1153,32 @@ 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"}, + {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-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"}, {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-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"}, @@ -985,14 +1187,27 @@ 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-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"}, {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-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"}, @@ -1002,67 +1217,112 @@ 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-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"}, @@ -1073,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"}, @@ -1148,20 +1402,21 @@ 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"}, +] +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"}, @@ -1175,12 +1430,16 @@ 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"}, + {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, ] rsa = [ {file = "rsa-4.7.2-py3-none-any.whl", hash = "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2"}, @@ -1190,37 +1449,51 @@ 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"}, - {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.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"}, @@ -1231,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"}, @@ -1248,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 ef2ebb5..964af2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,9 +20,13 @@ 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" +httpx = "^0.19.0" +pytest-asyncio = "^0.15.1" +pytest-order = "^1.0.0" [build-system] requires = ["poetry-core>=1.0.0"] 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: