├── tests ├── __init__.py ├── test_demo.py ├── test_gino_starlette.py └── conftest.py ├── examples ├── prod_fastapi_demo │ ├── tests │ │ ├── __init__.py │ │ ├── test_users.py │ │ └── conftest.py │ ├── src │ │ └── gino_fastapi_demo │ │ │ ├── __init__.py │ │ │ ├── views │ │ │ ├── __init__.py │ │ │ ├── index.py │ │ │ └── users.py │ │ │ ├── asgi.py │ │ │ ├── models │ │ │ ├── users.py │ │ │ └── __init__.py │ │ │ ├── main.py │ │ │ └── config.py │ ├── pytest.ini │ ├── migrations │ │ ├── README │ │ ├── script.py.mako │ │ ├── versions │ │ │ └── 9c28fa5b044e_initial.py │ │ └── env.py │ ├── run.py │ ├── .dockerignore │ ├── Dockerfile │ ├── docker-compose.yml │ ├── pyproject.toml │ ├── alembic.ini │ └── poetry.lock ├── simple_starlette_demo │ ├── requirements.txt │ └── app.py └── simple_fastapi_demo │ ├── requirements.txt │ └── app.py ├── pytest.ini ├── .github ├── ISSUE_TEMPLATE.md └── workflows │ └── test.yml ├── LICENSE ├── pyproject.toml ├── .gitignore ├── README.md ├── src └── gino_starlette.py └── poetry.lock /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = tests 3 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/views/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = tests 3 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /examples/simple_starlette_demo/requirements.txt: -------------------------------------------------------------------------------- 1 | ../.. # gino[starlette] 2 | uvicorn 3 | -------------------------------------------------------------------------------- /examples/simple_fastapi_demo/requirements.txt: -------------------------------------------------------------------------------- 1 | ../.. # gino[starlette] 2 | fastapi 3 | uvicorn 4 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/asgi.py: -------------------------------------------------------------------------------- 1 | from .main import get_app 2 | 3 | app = get_app() 4 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/models/users.py: -------------------------------------------------------------------------------- 1 | from . import db 2 | 3 | 4 | class User(db.Model): 5 | __tablename__ = "prod_fastapi_demo_users" 6 | 7 | id = db.Column(db.BigInteger(), primary_key=True) 8 | nickname = db.Column(db.Unicode(), default="unnamed") 9 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/run.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | if __name__ == "__main__": 4 | import uvicorn 5 | 6 | uvicorn.run( 7 | "gino_fastapi_demo.asgi:app", 8 | host=os.getenv("APP_HOST", "127.0.0.1"), 9 | port=int(os.getenv("APP_PORT", "5000")), 10 | ) 11 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/views/index.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router = APIRouter() 4 | 5 | 6 | @router.get("/") 7 | async def index(): 8 | return {"message": "Hello, world!"} 9 | 10 | 11 | def init_app(app): 12 | app.include_router(router) 13 | -------------------------------------------------------------------------------- /tests/test_demo.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | 4 | def test(venv_client): 5 | assert venv_client.get("/users/1").status_code == 404 6 | nickname = str(uuid.uuid4()) 7 | r = venv_client.post("/users", json=dict(name=nickname)) 8 | r.raise_for_status() 9 | r = r.json() 10 | assert ( 11 | venv_client.get("/users/{}".format(r["id"])).json()["nickname"] 12 | == nickname 13 | ) 14 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | README.md -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/tests/test_users.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | 4 | def test_crud(client): 5 | # create 6 | nickname = str(uuid.uuid4()) 7 | r = client.post("/users", json=dict(name=nickname)) 8 | r.raise_for_status() 9 | 10 | # retrieve 11 | url = "/users/{}".format(r.json()['id']) 12 | assert client.get(url).json()["nickname"] == nickname 13 | 14 | # delete 15 | client.delete(url).raise_for_status() 16 | assert client.get(url).status_code == 404 17 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/models/__init__.py: -------------------------------------------------------------------------------- 1 | from gino.ext.starlette import Gino 2 | 3 | from .. import config 4 | 5 | db = Gino( 6 | dsn=config.DB_DSN, 7 | pool_min_size=config.DB_POOL_MIN_SIZE, 8 | pool_max_size=config.DB_POOL_MAX_SIZE, 9 | echo=config.DB_ECHO, 10 | ssl=config.DB_SSL, 11 | use_connection_for_request=config.DB_USE_CONNECTION_FOR_REQUEST, 12 | retry_limit=config.DB_RETRY_LIMIT, 13 | retry_interval=config.DB_RETRY_INTERVAL, 14 | ) 15 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/tests/conftest.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from pathlib import Path 3 | 4 | import pytest 5 | from starlette.testclient import TestClient 6 | 7 | from gino_fastapi_demo.asgi import app 8 | 9 | 10 | @pytest.fixture 11 | def client(): 12 | cwd = Path(__file__).parent.parent 13 | subprocess.check_call(["alembic", "upgrade", "head"], cwd=cwd) 14 | with TestClient(app) as client: 15 | yield client 16 | subprocess.check_call(["alembic", "downgrade", "base"], cwd=cwd) 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Expected Behavior 2 | 3 | Describe what you were trying to get done and what you expected to happen. 4 | 5 | ## Actual Behavior 6 | 7 | Tell us what happened, what went wrong, 8 | 9 | ## Steps to Reproduce the Problem 10 | 11 | 1. 12 | 2. 13 | 3. 14 | 15 | ```plaintext 16 | Paste the command(s) you ran and the output. 17 | If there was a crash, please include the traceback here. 18 | ``` 19 | 20 | ## Specifications 21 | 22 | * Python version: 23 | * GINO version: 24 | * Starlette version: 25 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8-alpine as base 2 | 3 | FROM base as builder 4 | RUN apk add --no-cache --virtual .build-deps gcc musl-dev libffi-dev openssl-dev make postgresql-dev 5 | RUN pip install poetry==1.1.11 6 | COPY . /src/ 7 | WORKDIR /src 8 | RUN python -m venv /env && . /env/bin/activate && poetry install 9 | 10 | FROM base 11 | RUN apk add --no-cache postgresql-libs 12 | COPY --from=builder /env /env 13 | COPY --from=builder /src /src 14 | WORKDIR /src 15 | CMD ["/env/bin/gunicorn", "gino_fastapi_demo.asgi:app", "-b", "0.0.0.0:80", "-k", "uvicorn.workers.UvicornWorker"] 16 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/migrations/versions/9c28fa5b044e_initial.py: -------------------------------------------------------------------------------- 1 | """initial 2 | 3 | Revision ID: 9c28fa5b044e 4 | Revises: 5 | Create Date: 2020-02-14 21:15:22.049240 6 | 7 | """ 8 | import sqlalchemy as sa 9 | from alembic import op 10 | 11 | # revision identifiers, used by Alembic. 12 | revision = "9c28fa5b044e" 13 | down_revision = None 14 | branch_labels = None 15 | depends_on = None 16 | 17 | 18 | def upgrade(): 19 | op.create_table( 20 | "prod_fastapi_demo_users", 21 | sa.Column("id", sa.BigInteger(), nullable=False), 22 | sa.Column("nickname", sa.Unicode(), nullable=True), 23 | sa.PrimaryKeyConstraint("id"), 24 | ) 25 | 26 | 27 | def downgrade(): 28 | op.drop_table("prod_fastapi_demo_users") 29 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | app: 4 | build: . 5 | ports: 6 | - "8000:80" 7 | volumes: 8 | - .:/src 9 | depends_on: 10 | - migration 11 | environment: 12 | - DB_HOST=db 13 | - DB_USER=gino 14 | command: /env/bin/uvicorn --host 0.0.0.0 --port 80 gino_fastapi_demo.asgi:app --reload 15 | migration: 16 | build: . 17 | volumes: 18 | - .:/src 19 | depends_on: 20 | - db 21 | environment: 22 | - DB_HOST=db 23 | - DB_USER=gino 24 | command: /env/bin/alembic upgrade head 25 | db: 26 | image: postgres 27 | environment: 28 | - POSTGRES_USER=gino 29 | - POSTGRES_HOST_AUTH_METHOD=trust 30 | volumes: 31 | - ./postgres-data:/var/lib/postgresql/data 32 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/views/users.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from pydantic import BaseModel 3 | 4 | from ..models.users import User 5 | 6 | router = APIRouter() 7 | 8 | 9 | class UserModel(BaseModel): 10 | name: str 11 | 12 | 13 | @router.get("/users/{uid}") 14 | async def get_user(uid: int): 15 | user = await User.get_or_404(uid) 16 | return user.to_dict() 17 | 18 | 19 | @router.post("/users") 20 | async def add_user(user: UserModel): 21 | rv = await User.create(nickname=user.name) 22 | return rv.to_dict() 23 | 24 | 25 | @router.delete("/users/{uid}") 26 | async def delete_user(uid: int): 27 | user = await User.get_or_404(uid) 28 | await user.delete() 29 | return dict(id=uid) 30 | 31 | 32 | def init_app(app): 33 | app.include_router(router) 34 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "gino-fastapi-demo" 3 | version = "0.1.0" 4 | description = "A demo of a production-ready project based on GINO and FastAPI." 5 | authors = ["Aobo Shi "] 6 | 7 | [tool.poetry.dependencies] 8 | python = "^3.6.2" 9 | fastapi = "^0.70.0" 10 | gino = {extras = ["starlette"], version = "^1.0.0"} 11 | importlib_metadata = { version = "^1.3.0", python = "<3.8" } 12 | uvicorn = "^0.15.0" 13 | gunicorn = "^20.1.0" 14 | alembic = "^1.7.5" 15 | psycopg2 = "^2.9.2" 16 | 17 | [tool.poetry.dev-dependencies] 18 | pytest = "^6.2.5" 19 | 20 | [tool.poetry.plugins."gino_fastapi_demo.modules"] 21 | "index" = "gino_fastapi_demo.views.index" 22 | "users" = "gino_fastapi_demo.views.users" 23 | 24 | [tool.black] 25 | line-length = 80 26 | 27 | [build-system] 28 | requires = ["poetry>=0.12"] 29 | build-backend = "poetry.masonry.api" 30 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/main.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import click 4 | from fastapi import FastAPI 5 | 6 | from .models import db 7 | 8 | try: 9 | from importlib.metadata import entry_points 10 | except ImportError: # pragma: no cover 11 | from importlib_metadata import entry_points 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | def get_app(): 17 | app = FastAPI(title="GINO FastAPI Demo") 18 | db.init_app(app) 19 | load_modules(app) 20 | return app 21 | 22 | 23 | def load_modules(app=None): 24 | for ep in entry_points()["gino_fastapi_demo.modules"]: 25 | logger.info( 26 | "Loading module: %s", 27 | ep.name, 28 | extra={ 29 | "color_message": "Loading module: " 30 | + click.style("%s", fg="cyan") 31 | }, 32 | ) 33 | mod = ep.load() 34 | if app: 35 | init_app = getattr(mod, "init_app", None) 36 | if init_app: 37 | init_app(app) 38 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/src/gino_fastapi_demo/config.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.engine.url import URL, make_url 2 | from starlette.config import Config 3 | from starlette.datastructures import Secret 4 | 5 | config = Config(".env") 6 | 7 | DB_DRIVER = config("DB_DRIVER", default="postgresql") 8 | DB_HOST = config("DB_HOST", default=None) 9 | DB_PORT = config("DB_PORT", cast=int, default=None) 10 | DB_USER = config("DB_USER", default=None) 11 | DB_PASSWORD = config("DB_PASSWORD", cast=Secret, default=None) 12 | DB_DATABASE = config("DB_DATABASE", default=None) 13 | DB_DSN = config( 14 | "DB_DSN", 15 | cast=make_url, 16 | default=URL( 17 | drivername=DB_DRIVER, 18 | username=DB_USER, 19 | password=DB_PASSWORD, 20 | host=DB_HOST, 21 | port=DB_PORT, 22 | database=DB_DATABASE, 23 | ), 24 | ) 25 | DB_POOL_MIN_SIZE = config("DB_POOL_MIN_SIZE", cast=int, default=1) 26 | DB_POOL_MAX_SIZE = config("DB_POOL_MAX_SIZE", cast=int, default=16) 27 | DB_ECHO = config("DB_ECHO", cast=bool, default=False) 28 | DB_SSL = config("DB_SSL", default=None) 29 | DB_USE_CONNECTION_FOR_REQUEST = config( 30 | "DB_USE_CONNECTION_FOR_REQUEST", cast=bool, default=True 31 | ) 32 | DB_RETRY_LIMIT = config("DB_RETRY_LIMIT", cast=int, default=32) 33 | DB_RETRY_INTERVAL = config("DB_RETRY_INTERVAL", cast=int, default=1) 34 | -------------------------------------------------------------------------------- /examples/simple_fastapi_demo/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from fastapi import FastAPI 4 | from gino.ext.starlette import Gino 5 | from pydantic import BaseModel 6 | 7 | app = FastAPI() 8 | db = Gino( 9 | app, 10 | host=os.getenv("DB_HOST", "localhost"), 11 | port=os.getenv("DB_PORT", 5432), 12 | user=os.getenv("DB_USER", "postgres"), 13 | password=os.getenv("DB_PASS", ""), 14 | database=os.getenv("DB_NAME", "postgres"), 15 | ) 16 | 17 | 18 | class User(db.Model): 19 | __tablename__ = "simple_fastapi_demo_users" 20 | 21 | id = db.Column(db.BigInteger(), primary_key=True) 22 | nickname = db.Column(db.Unicode(), default="unnamed") 23 | 24 | 25 | class UserModel(BaseModel): 26 | name: str 27 | 28 | 29 | @app.get("/") 30 | async def index(): 31 | return {"message": "Hello, world!"} 32 | 33 | 34 | @app.get("/users/{uid}") 35 | async def get_user(uid: int): 36 | q = User.query.where(User.id == uid) 37 | return (await q.gino.first_or_404()).to_dict() 38 | 39 | 40 | @app.post("/users") 41 | async def add_user(user: UserModel): 42 | u = await User.create(nickname=user.name) 43 | return u.to_dict() 44 | 45 | 46 | @app.on_event("startup") 47 | async def create(): 48 | await db.gino.create_all() 49 | 50 | 51 | if __name__ == "__main__": 52 | import uvicorn 53 | 54 | uvicorn.run( 55 | app, 56 | host=os.getenv("APP_HOST", "127.0.0.1"), 57 | port=int(os.getenv("APP_PORT", "5000")), 58 | ) 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | BSD License 3 | 4 | Copyright (c) 2017-present, Tony Wang 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, this 14 | list of conditions and the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 17 | * Neither the name of the copyright holder nor the names of its 18 | contributors may be used to endorse or promote products derived from this 19 | software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 28 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 29 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 30 | OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "gino-starlette" 3 | version = "0.1.6" 4 | description = "An extension for GINO to integrate with Starlette" 5 | license = "BSD-3-Clause" 6 | authors = ["Tony Wang "] 7 | maintainers = ["Aobo Shi "] 8 | readme = "README.md" 9 | homepage = "https://github.com/python-gino/gino-starlette" 10 | repository = "https://github.com/python-gino/gino-starlette" 11 | documentation = "https://python-gino.org/docs/" 12 | keywords = ["sqlalchemy", "python3", "starlette", "gino"] 13 | classifiers = [ 14 | "Development Status :: 4 - Beta", 15 | "Intended Audience :: Developers", 16 | "License :: OSI Approved :: BSD License", 17 | "Natural Language :: English", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.6", 20 | "Programming Language :: Python :: 3.7", 21 | "Programming Language :: Python :: 3.8", 22 | ] 23 | 24 | [tool.poetry.dependencies] 25 | python = ">=3.6.2,<4.0" # fresh black requires at least 3.6.2 so we can't use ^3.6 26 | starlette = ">=0.19,<1.0" # caret behaviour on 0.x is to lock to 0.x.* 27 | gino = "^1.0" 28 | 29 | [tool.poetry.dev-dependencies] 30 | black = "^22.3" 31 | 32 | # tests 33 | pytest = [ 34 | { version = "^7.1", python="^3.7" }, 35 | { version = "^6.2", python="~3.6" } 36 | ] 37 | pytest-asyncio = "^0.15" 38 | pytest-cov = "^3.0" 39 | pytest-mock = "^3.6" 40 | pytest-virtualenv = "^1.7" 41 | requests = "^2.26" 42 | 43 | [tool.poetry.plugins."gino.extensions"] 44 | "starlette" = "gino_starlette" 45 | 46 | [tool.black] 47 | line-length = 80 48 | 49 | [build-system] 50 | requires = ["poetry>=1.2.0"] 51 | build-backend = "poetry.masonry.api" 52 | -------------------------------------------------------------------------------- /examples/simple_starlette_demo/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from gino.ext.starlette import Gino 4 | from starlette.applications import Starlette 5 | from starlette.responses import JSONResponse, PlainTextResponse 6 | 7 | # Database Configuration 8 | PG_URL = "postgresql://{user}:{password}@{host}:{port}/{database}".format( 9 | host=os.getenv("DB_HOST", "localhost"), 10 | port=os.getenv("DB_PORT", 5432), 11 | user=os.getenv("DB_USER", "postgres"), 12 | password=os.getenv("DB_PASS", ""), 13 | database=os.getenv("DB_NAME", "postgres"), 14 | ) 15 | 16 | # Initialize Starlette app 17 | app = Starlette() 18 | 19 | # Initialize Gino instance 20 | db = Gino(app, dsn=PG_URL) 21 | 22 | 23 | # Definition of table 24 | class User(db.Model): 25 | __tablename__ = "simple_starlette_demo_users" 26 | 27 | id = db.Column(db.BigInteger(), primary_key=True) 28 | nickname = db.Column(db.Unicode(), default="unnamed") 29 | 30 | 31 | # Definition of routes 32 | @app.route("/") 33 | async def index(request): 34 | return PlainTextResponse("Hello, world!") 35 | 36 | 37 | @app.route("/users/{uid:int}") 38 | async def get_user(request): 39 | uid = request.path_params.get("uid") 40 | q = User.query.where(User.id == uid) 41 | return JSONResponse((await q.gino.first_or_404()).to_dict()) 42 | 43 | 44 | @app.route("/users", methods=["POST"]) 45 | async def add_user(request): 46 | u = await User.create(nickname=(await request.json()).get("name")) 47 | return JSONResponse(u.to_dict()) 48 | 49 | 50 | @app.on_event("startup") 51 | async def create(): 52 | await db.gino.create_all() 53 | 54 | 55 | if __name__ == "__main__": 56 | import uvicorn 57 | 58 | uvicorn.run( 59 | app, 60 | host=os.getenv("APP_HOST", "127.0.0.1"), 61 | port=int(os.getenv("APP_PORT", "5000")), 62 | ) 63 | -------------------------------------------------------------------------------- /tests/test_gino_starlette.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import pytest 4 | from starlette.testclient import TestClient 5 | 6 | 7 | def _test_index_returns_200(app): 8 | client = TestClient(app) 9 | with client: 10 | response = client.get("/") 11 | assert response.status_code == 200 12 | assert response.text == "Hello, world!" 13 | 14 | 15 | def test_index_returns_200(app): 16 | _test_index_returns_200(app) 17 | 18 | 19 | def test_index_returns_200_dsn(app_dsn): 20 | _test_index_returns_200(app_dsn) 21 | 22 | 23 | def _test(app): 24 | client = TestClient(app) 25 | with client: 26 | for method in "01234": 27 | response = client.get("/users/1?method=" + method) 28 | assert response.status_code == 404 29 | 30 | response = client.post("/users", json=dict(name="fantix")) 31 | assert response.status_code == 200 32 | assert response.json() == dict(id=1, nickname="fantix") 33 | 34 | for method in "01234": 35 | response = client.get("/users/1?method=" + method) 36 | assert response.status_code == 200 37 | assert response.json() == dict(id=1, nickname="fantix") 38 | 39 | 40 | def test(app): 41 | _test(app) 42 | 43 | 44 | def test_ssl(app_ssl): 45 | _test(app_ssl) 46 | 47 | 48 | def test_dsn(app_dsn): 49 | _test(app_dsn) 50 | 51 | 52 | def test_app_factory(app_factory): 53 | _test(app_factory) 54 | 55 | 56 | """ 57 | disable this test for now because latest Starlette TestClient is using anyio to 58 | manage event loop, which is in another blocking thread. This call_later is not 59 | invoked until that is terminated. 60 | 61 | def test_db_delayed(app_db_delayed): 62 | loop = asyncio.get_event_loop() 63 | loop.call_later(1, loop.create_task, app_db_delayed.start_proxy()) 64 | client = TestClient(app_db_delayed) 65 | with client: 66 | pass 67 | """ 68 | 69 | 70 | def test_no_db(app_db_delayed): 71 | client = TestClient(app_db_delayed) 72 | with pytest.raises(Exception): 73 | with client: 74 | pass 75 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = migrations 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # timezone to use when rendering the date 11 | # within the migration file as well as the filename. 12 | # string value is passed to dateutil.tz.gettz() 13 | # leave blank for localtime 14 | # timezone = 15 | 16 | # max length of characters to apply to the 17 | # "slug" field 18 | # truncate_slug_length = 40 19 | 20 | # set to 'true' to run the environment during 21 | # the 'revision' command, regardless of autogenerate 22 | # revision_environment = false 23 | 24 | # set to 'true' to allow .pyc and .pyo files without 25 | # a source .py file to be detected as revisions in the 26 | # versions/ directory 27 | # sourceless = false 28 | 29 | # version location specification; this defaults 30 | # to migrations/versions. When using multiple version 31 | # directories, initial revisions must be specified with --version-path 32 | # version_locations = %(here)s/bar %(here)s/bat migrations/versions 33 | 34 | # the output encoding used when revision files 35 | # are written from script.py.mako 36 | # output_encoding = utf-8 37 | 38 | sqlalchemy.url = driver://user:pass@localhost/dbname 39 | 40 | 41 | [post_write_hooks] 42 | # post_write_hooks defines scripts or Python functions that are run 43 | # on newly generated revision scripts. See the documentation for further 44 | # detail and examples 45 | 46 | # format using "black" - use the console_scripts runner, against the "black" entrypoint 47 | # hooks=black 48 | # black.type=console_scripts 49 | # black.entrypoint=black 50 | # black.options=-l 79 51 | 52 | # Logging configuration 53 | [loggers] 54 | keys = root,sqlalchemy,alembic 55 | 56 | [handlers] 57 | keys = console 58 | 59 | [formatters] 60 | keys = generic 61 | 62 | [logger_root] 63 | level = WARN 64 | handlers = console 65 | qualname = 66 | 67 | [logger_sqlalchemy] 68 | level = WARN 69 | handlers = 70 | qualname = sqlalchemy.engine 71 | 72 | [logger_alembic] 73 | level = INFO 74 | handlers = 75 | qualname = alembic 76 | 77 | [handler_console] 78 | class = StreamHandler 79 | args = (sys.stderr,) 80 | level = NOTSET 81 | formatter = generic 82 | 83 | [formatter_generic] 84 | format = %(levelname)-5.5s [%(name)s] %(message)s 85 | datefmt = %H:%M:%S 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .vscode/ 132 | .idea/ 133 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/migrations/env.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | import time 5 | from logging.config import fileConfig 6 | 7 | from alembic import context 8 | from gino_fastapi_demo.config import DB_DSN, DB_RETRY_LIMIT, DB_RETRY_INTERVAL 9 | from gino_fastapi_demo.main import get_app, db 10 | from sqlalchemy import engine_from_config, pool 11 | 12 | sys.path.append(os.path.dirname(os.path.dirname(__file__))) 13 | 14 | # other values from the config, defined by the needs of env.py, 15 | # can be acquired: 16 | # my_important_option = config.get_main_option("my_important_option") 17 | # ... etc. 18 | 19 | get_app() 20 | target_metadata = db 21 | 22 | # this is the Alembic Config object, which provides 23 | # access to the values within the .ini file in use. 24 | config = context.config 25 | 26 | # Interpret the config file for Python logging. 27 | # This line sets up loggers basically. 28 | fileConfig(config.config_file_name) 29 | 30 | config.set_main_option("sqlalchemy.url", str(DB_DSN)) 31 | 32 | 33 | def run_migrations_offline(): 34 | """Run migrations in 'offline' mode. 35 | 36 | This configures the context with just a URL 37 | and not an Engine, though an Engine is acceptable 38 | here as well. By skipping the Engine creation 39 | we don't even need a DBAPI to be available. 40 | 41 | Calls to context.execute() here emit the given string to the 42 | script output. 43 | 44 | """ 45 | url = config.get_main_option("sqlalchemy.url") 46 | context.configure( 47 | url=url, 48 | target_metadata=target_metadata, 49 | literal_binds=True, 50 | dialect_opts={"paramstyle": "named"}, 51 | ) 52 | 53 | with context.begin_transaction(): 54 | context.run_migrations() 55 | 56 | 57 | def run_migrations_online(): 58 | """Run migrations in 'online' mode. 59 | 60 | In this scenario we need to create an Engine 61 | and associate a connection with the context. 62 | 63 | """ 64 | connectable = engine_from_config( 65 | config.get_section(config.config_ini_section), 66 | prefix="sqlalchemy.", 67 | poolclass=pool.NullPool, 68 | ) 69 | 70 | retries = 0 71 | while True: 72 | try: 73 | retries += 1 74 | connection = connectable.connect() 75 | except Exception: 76 | if retries < DB_RETRY_LIMIT: 77 | logging.info("Waiting for the database to start...") 78 | time.sleep(DB_RETRY_INTERVAL) 79 | else: 80 | logging.error("Max retries reached.") 81 | raise 82 | else: 83 | break 84 | 85 | with connection: 86 | context.configure( 87 | connection=connection, target_metadata=target_metadata 88 | ) 89 | 90 | with context.begin_transaction(): 91 | context.run_migrations() 92 | 93 | if context.is_offline_mode(): 94 | run_migrations_offline() 95 | else: 96 | run_migrations_online() 97 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - 'v*.*.*' 9 | pull_request: 10 | branches: 11 | - master 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | python-version: [ '3.7', '3.8', '3.9', '3.10' ] 19 | services: 20 | postgres: 21 | image: fantix/postgres-ssl:13.1 22 | env: 23 | POSTGRES_USER: gino 24 | POSTGRES_HOST_AUTH_METHOD: trust 25 | ports: 26 | - 5432:5432 27 | # needed because the postgres container does not provide a healthcheck 28 | options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 29 | steps: 30 | - name: Checkout source code 31 | uses: actions/checkout@v1 32 | - name: Set up Python 33 | uses: actions/setup-python@v1 34 | with: 35 | python-version: ${{ matrix.python-version }} 36 | - name: virtualenv cache 37 | uses: actions/cache@preview 38 | with: 39 | path: ~/.cache/pypoetry/virtualenvs 40 | key: ${{ runner.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles(format('{0}{1}', github.workspace, '/poetry.lock')) }} 41 | restore-keys: | 42 | ${{ runner.os }}-${{ matrix.python-version }}-poetry- 43 | - name: Install Python dependencies 44 | run: | 45 | curl -sSL https://install.python-poetry.org | python 46 | $HOME/.local/bin/poetry install 47 | - name: Test with pytest 48 | env: 49 | DB_HOST: localhost 50 | DB_USER: gino 51 | run: | 52 | $HOME/.local/bin/poetry run pytest --cov=src --cov=examples --cov-fail-under=95 --cov-report xml 53 | - name: Check code format with black 54 | run: | 55 | $HOME/.local/bin/poetry run black --check src 56 | - name: Submit coverage report 57 | if: matrix.python-version == '3.9' && github.ref == 'refs/heads/master' 58 | env: 59 | CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_TOKEN }} 60 | run: | 61 | pip install codacy-coverage 62 | python-codacy-coverage -r coverage.xml 63 | release: 64 | runs-on: ubuntu-latest 65 | needs: test 66 | strategy: 67 | matrix: 68 | python-version: [ '3.8' ] 69 | steps: 70 | - name: Checkout source code 71 | if: startsWith(github.ref, 'refs/tags/') 72 | uses: actions/checkout@v1 73 | - name: Set up Python 74 | if: startsWith(github.ref, 'refs/tags/') 75 | uses: actions/setup-python@v1 76 | with: 77 | python-version: ${{ matrix.python-version }} 78 | - name: virtualenv cache 79 | if: startsWith(github.ref, 'refs/tags/') 80 | uses: actions/cache@preview 81 | with: 82 | path: ~/.cache/pypoetry/virtualenvs 83 | key: ${{ runner.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles(format('{0}{1}', github.workspace, '/poetry.lock')) }} 84 | restore-keys: | 85 | ${{ runner.os }}-${{ matrix.python-version }}-poetry- 86 | - name: Release to PyPI 87 | if: startsWith(github.ref, 'refs/tags/') 88 | env: 89 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 90 | run: | 91 | curl -sSL https://install.python-poetry.org | python 92 | $HOME/.local/bin/poetry install 93 | $HOME/.local/bin/poetry build 94 | $HOME/.local/bin/poetry publish --username __token__ --password ${{ secrets.PYPI_TOKEN }} 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gino-starlette 2 | 3 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/0bec53f18d3b49aea6f558a269df318a)](https://app.codacy.com/gh/python-gino/gino-starlette?utm_source=github.com&utm_medium=referral&utm_content=python-gino/gino-starlette&utm_campaign=Badge_Grade_Settings) 4 | 5 | ## Introduction 6 | 7 | An extension for GINO to support starlette server. 8 | 9 | ## Usage 10 | 11 | The common usage looks like this: 12 | 13 | ```python 14 | from starlette.applications import Starlette 15 | from gino.ext.starlette import Gino 16 | 17 | app = Starlette() 18 | db = Gino(app, **kwargs) 19 | ``` 20 | 21 | ## Configuration 22 | 23 | GINO adds a middleware to the Starlette app to setup and cleanup database according to 24 | the configurations that passed in the `kwargs` parameter. 25 | 26 | The config includes: 27 | 28 | | Name | Description | Default | 29 | | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------- | 30 | | `driver` | the database driver | `asyncpg` | 31 | | `host` | database server host | `localhost` | 32 | | `port` | database server port | `5432` | 33 | | `user` | database server user | `postgres` | 34 | | `password` | database server password | empty | 35 | | `database` | database name | `postgres` | 36 | | `dsn` | a SQLAlchemy database URL to create the engine, its existence will replace all previous connect arguments. | N/A | 37 | | `retry_times` | the retry times when database failed to connect | `20` | 38 | | `retry_interval` | the interval in **seconds** between each time of retry | `5` | 39 | | `pool_min_size` | the initial number of connections of the db pool. | N/A | 40 | | `pool_max_size` | the maximum number of connections in the db pool. | N/A | 41 | | `echo` | enable SQLAlchemy echo mode. | N/A | 42 | | `ssl` | SSL context passed to `asyncpg.connect` | `None` | 43 | | `use_connection_for_request` | flag to set up lazy connection for requests. | N/A | 44 | | `retry_limit` | the number of retries to connect to the database on start up. | 1 | 45 | | `retry_interval` | seconds to wait between retries. | 1 | 46 | | `kwargs` | other parameters passed to the specified dialects, like `asyncpg`. Unrecognized parameters will cause exceptions. | N/A | 47 | 48 | ## Lazy Connection 49 | 50 | If `use_connection_for_request` is set to be True, then a lazy connection is available 51 | at `request['connection']`. By default, a database connection is borrowed on the first 52 | query, shared in the same execution context, and returned to the pool on response. 53 | If you need to release the connection early in the middle to do some long-running tasks, 54 | you can simply do this: 55 | 56 | ```python 57 | await request['connection'].release(permanent=False) 58 | ``` 59 | -------------------------------------------------------------------------------- /src/gino_starlette.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import logging 3 | 4 | from gino.api import Gino as _Gino 5 | from gino.api import GinoExecutor as _Executor 6 | from gino.engine import GinoConnection as _Connection 7 | from gino.engine import GinoEngine as _Engine 8 | from gino.strategies import GinoStrategy 9 | from sqlalchemy.engine.url import make_url, URL 10 | from starlette import status 11 | from starlette.exceptions import HTTPException 12 | from starlette.types import Receive, Scope, Send 13 | 14 | logger = logging.getLogger("gino.ext.starlette") 15 | 16 | 17 | class StarletteModelMixin: 18 | @classmethod 19 | async def get_or_404(cls, *args, **kwargs): 20 | # noinspection PyUnresolvedReferences 21 | rv = await cls.get(*args, **kwargs) 22 | if rv is None: 23 | raise HTTPException( 24 | status.HTTP_404_NOT_FOUND, 25 | "{} is not found".format(cls.__name__), 26 | ) 27 | return rv 28 | 29 | 30 | # noinspection PyClassHasNoInit 31 | class GinoExecutor(_Executor): 32 | async def first_or_404(self, *args, **kwargs): 33 | rv = await self.first(*args, **kwargs) 34 | if rv is None: 35 | raise HTTPException(status.HTTP_404_NOT_FOUND, "No such data") 36 | return rv 37 | 38 | 39 | # noinspection PyClassHasNoInit 40 | class GinoConnection(_Connection): 41 | async def first_or_404(self, *args, **kwargs): 42 | rv = await self.first(*args, **kwargs) 43 | if rv is None: 44 | raise HTTPException(status.HTTP_404_NOT_FOUND, "No such data") 45 | return rv 46 | 47 | 48 | # noinspection PyClassHasNoInit 49 | class GinoEngine(_Engine): 50 | connection_cls = GinoConnection 51 | 52 | async def first_or_404(self, *args, **kwargs): 53 | rv = await self.first(*args, **kwargs) 54 | if rv is None: 55 | raise HTTPException(status.HTTP_404_NOT_FOUND, "No such data") 56 | return rv 57 | 58 | 59 | class StarletteStrategy(GinoStrategy): 60 | name = "starlette" 61 | engine_cls = GinoEngine 62 | 63 | 64 | StarletteStrategy() 65 | 66 | 67 | class _Middleware: 68 | def __init__(self, app, db): 69 | self.app = app 70 | self.db = db 71 | self._conn_for_req = db.config["use_connection_for_request"] 72 | 73 | async def __call__( 74 | self, scope: Scope, receive: Receive, send: Send 75 | ) -> None: 76 | if scope["type"] == "http" and self._conn_for_req: 77 | scope["connection"] = await self.db.acquire(lazy=True) 78 | try: 79 | await self.app(scope, receive, send) 80 | finally: 81 | conn = scope.pop("connection", None) 82 | if conn is not None: 83 | await conn.release() 84 | return 85 | 86 | await self.app(scope, receive, send) 87 | 88 | 89 | class Gino(_Gino): 90 | """Support Starlette server. 91 | 92 | The common usage looks like this:: 93 | 94 | from starlette.applications import Starlette 95 | from gino.ext.starlette import Gino 96 | 97 | app = Starlette() 98 | db = Gino(app, **kwargs) 99 | 100 | GINO adds a middleware to the Starlette app to setup and cleanup database 101 | according to the configurations that passed in the ``kwargs`` parameter. 102 | 103 | The config includes: 104 | 105 | * ``driver`` - the database driver, default is ``asyncpg``. 106 | * ``host`` - database server host, default is ``localhost``. 107 | * ``port`` - database server port, default is ``5432``. 108 | * ``user`` - database server user, default is ``postgres``. 109 | * ``password`` - database server password, default is empty. 110 | * ``database`` - database name, default is ``postgres``. 111 | * ``dsn`` - a SQLAlchemy database URL to create the engine, its existence 112 | will replace all previous connect arguments. 113 | * ``pool_min_size`` - the initial number of connections of the db pool. 114 | * ``pool_max_size`` - the maximum number of connections in the db pool. 115 | * ``echo`` - enable SQLAlchemy echo mode. 116 | * ``ssl`` - SSL context passed to ``asyncpg.connect``, default is ``None``. 117 | * ``use_connection_for_request`` - flag to set up lazy connection for 118 | requests. 119 | * ``retry_limit`` - the number of retries to connect to the database on 120 | start up, default is 1. 121 | * ``retry_interval`` - seconds to wait between retries, default is 1. 122 | * ``kwargs`` - other parameters passed to the specified dialects, 123 | like ``asyncpg``. Unrecognized parameters will cause exceptions. 124 | 125 | If ``use_connection_for_request`` is set to be True, then a lazy connection 126 | is available at ``request['connection']``. By default, a database 127 | connection is borrowed on the first query, shared in the same execution 128 | context, and returned to the pool on response. If you need to release the 129 | connection early in the middle to do some long-running tasks, you can 130 | simply do this:: 131 | 132 | await request['connection'].release(permanent=False) 133 | 134 | """ 135 | 136 | model_base_classes = _Gino.model_base_classes + (StarletteModelMixin,) 137 | query_executor = GinoExecutor 138 | 139 | def __init__(self, app=None, *args, **kwargs): 140 | self.config = dict() 141 | if "dsn" in kwargs: 142 | self.config["dsn"] = make_url(kwargs.pop("dsn")) 143 | else: 144 | self.config["dsn"] = URL( 145 | drivername=kwargs.pop("driver", "asyncpg"), 146 | host=kwargs.pop("host", "localhost"), 147 | port=kwargs.pop("port", 5432), 148 | username=kwargs.pop("user", "postgres"), 149 | password=kwargs.pop("password", ""), 150 | database=kwargs.pop("database", "postgres"), 151 | ) 152 | self.config["retry_limit"] = kwargs.pop("retry_limit", 1) 153 | self.config["retry_interval"] = kwargs.pop("retry_interval", 1) 154 | self.config["echo"] = kwargs.pop("echo", False) 155 | self.config["min_size"] = kwargs.pop("pool_min_size", 5) 156 | self.config["max_size"] = kwargs.pop("pool_max_size", 10) 157 | self.config["ssl"] = kwargs.pop("ssl", None) 158 | self.config["use_connection_for_request"] = kwargs.pop( 159 | "use_connection_for_request", True 160 | ) 161 | self.config["kwargs"] = kwargs.pop("kwargs", dict()) 162 | 163 | super().__init__(*args, **kwargs) 164 | if app is not None: 165 | self.init_app(app) 166 | 167 | def init_app(self, app): 168 | @app.on_event("startup") 169 | async def startup(): 170 | config = self.config 171 | logger.info("Connecting to the database: %r", config["dsn"]) 172 | retries = 0 173 | while True: 174 | retries += 1 175 | # noinspection PyBroadException 176 | try: 177 | await self.set_bind( 178 | config["dsn"], 179 | echo=config["echo"], 180 | min_size=config["min_size"], 181 | max_size=config["max_size"], 182 | ssl=config["ssl"], 183 | **config["kwargs"], 184 | ) 185 | break 186 | except Exception: 187 | if retries < config["retry_limit"]: 188 | logger.info("Waiting for the database to start...") 189 | await asyncio.sleep(config["retry_interval"]) 190 | else: 191 | logger.error( 192 | "Cannot connect to the database; max retries reached." 193 | ) 194 | raise 195 | msg = "Database connection pool created: " 196 | logger.info( 197 | msg + repr(self.bind), 198 | extra={"color_message": msg + self.bind.repr(color=True)}, 199 | ) 200 | 201 | @app.on_event("shutdown") 202 | async def shutdown(): 203 | msg = "Closing database connection: " 204 | logger.info( 205 | msg + repr(self.bind), 206 | extra={"color_message": msg + self.bind.repr(color=True)}, 207 | ) 208 | _bind = self.pop_bind() 209 | await _bind.close() 210 | msg = "Closed database connection: " 211 | logger.info( 212 | msg + repr(_bind), 213 | extra={"color_message": msg + _bind.repr(color=True)}, 214 | ) 215 | 216 | app.add_middleware(_Middleware, db=self) 217 | 218 | async def first_or_404(self, *args, **kwargs): 219 | rv = await self.first(*args, **kwargs) 220 | if rv is None: 221 | raise HTTPException(status.HTTP_404_NOT_FOUND, "No such data") 222 | return rv 223 | 224 | async def set_bind(self, bind, loop=None, **kwargs): 225 | kwargs.setdefault("strategy", "starlette") 226 | return await super().set_bind(bind, loop=loop, **kwargs) 227 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import os 3 | import socket 4 | import ssl 5 | import subprocess 6 | from contextlib import closing 7 | from pathlib import Path 8 | from urllib.parse import urljoin 9 | 10 | import asyncpg 11 | import gino 12 | import pytest 13 | import requests 14 | from gino.ext.starlette import Gino 15 | from requests.adapters import HTTPAdapter 16 | from starlette.applications import Starlette 17 | from starlette.responses import JSONResponse, PlainTextResponse 18 | from urllib3.util.retry import Retry 19 | 20 | _MAX_INACTIVE_CONNECTION_LIFETIME = 59.0 21 | DB_ARGS = dict( 22 | host=os.getenv("DB_HOST", "localhost"), 23 | port=os.getenv("DB_PORT", 5432), 24 | user=os.getenv("DB_USER", "postgres"), 25 | password=os.getenv("DB_PASS", ""), 26 | database=os.getenv("DB_NAME", "postgres"), 27 | ) 28 | PG_URL = "postgresql://{user}:{password}@{host}:{port}/{database}".format( 29 | **DB_ARGS 30 | ) 31 | 32 | 33 | def find_free_port(): 34 | with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: 35 | s.bind(("", 0)) 36 | s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 37 | return s.getsockname()[1] 38 | 39 | 40 | class ProxyServerProtocol(asyncio.Protocol): 41 | def __init__(self, loop, target_host, target_port): 42 | self._loop = loop 43 | self._target_host = target_host 44 | self._target_port = target_port 45 | self._transport = None 46 | self._task = None 47 | self._eof_received = False 48 | self._buffer = [] 49 | 50 | def connection_made(self, transport: asyncio.Transport): 51 | # transport.pause_reading() 52 | 53 | self._task = self._loop.create_task( 54 | self._loop.create_connection( 55 | lambda: ProxyClientProtocol(transport), 56 | self._target_host, 57 | self._target_port, 58 | ) 59 | ) 60 | 61 | def cb(task): 62 | self._task = None 63 | # noinspection PyBroadException 64 | try: 65 | self._transport = task.result()[0] 66 | except Exception: 67 | transport.close() 68 | else: 69 | # transport.resume_reading() 70 | for data in self._buffer: 71 | self._transport.write(data) 72 | self._buffer.clear() 73 | if self._eof_received: 74 | self._transport.write_eof() 75 | 76 | self._task.add_done_callback(cb) 77 | 78 | def data_received(self, data): 79 | if self._transport: 80 | self._transport.write(data) 81 | else: 82 | self._buffer.append(data) 83 | 84 | def pause_writing(self): 85 | self._transport.pause_reading() 86 | 87 | def resume_writing(self): 88 | self._transport.resume_reading() 89 | 90 | def eof_received(self): 91 | self._eof_received = True 92 | if self._transport: 93 | self._transport.write_eof() 94 | return True 95 | 96 | def connection_lost(self, exc): 97 | if self._task: 98 | self._task.cancel() 99 | if self._transport: 100 | self._transport.close() 101 | 102 | 103 | class ProxyClientProtocol(asyncio.Protocol): 104 | def __init__(self, transport): 105 | self._trans = transport 106 | 107 | def data_received(self, data): 108 | self._trans.write(data) 109 | 110 | def pause_writing(self): 111 | self._trans.pause_reading() 112 | 113 | def resume_writing(self): 114 | self._trans.resume_reading() 115 | 116 | def eof_received(self): 117 | self._trans.write_eof() 118 | return True 119 | 120 | def connection_lost(self, exc): 121 | self._trans.close() 122 | 123 | 124 | async def _app(**kwargs): 125 | app = Starlette() 126 | kwargs.update( 127 | { 128 | "kwargs": dict( 129 | max_inactive_connection_lifetime=_MAX_INACTIVE_CONNECTION_LIFETIME, 130 | ), 131 | } 132 | ) 133 | factory = kwargs.pop("factory", False) 134 | db_delayed = kwargs.pop("db_delayed", False) 135 | if db_delayed: 136 | 137 | async def start_proxy(_port): 138 | loop = asyncio.get_event_loop() 139 | app.db_proxy = await loop.create_server( 140 | lambda: ProxyServerProtocol( 141 | loop, DB_ARGS["host"], DB_ARGS["port"] 142 | ), 143 | "localhost", 144 | _port, 145 | reuse_address=True, 146 | reuse_port=True, 147 | ) 148 | return app.db_proxy 149 | 150 | server = await start_proxy(0) 151 | for s in server.sockets: 152 | try: 153 | host, port = s.getsockname() 154 | break 155 | except ValueError: 156 | pass 157 | server.close() 158 | await server.wait_closed() 159 | app.start_proxy = lambda: start_proxy(port) 160 | kwargs["host"] = host 161 | kwargs["port"] = port 162 | kwargs["retry_limit"] = 4 163 | kwargs["retry_interval"] = 0.5 164 | 165 | if factory: 166 | db = Gino(**kwargs) 167 | db.init_app(app) 168 | else: 169 | db = Gino(app, **kwargs) 170 | 171 | class User(db.Model): 172 | __tablename__ = "gino_users" 173 | 174 | id = db.Column(db.BigInteger(), primary_key=True) 175 | nickname = db.Column(db.Unicode(), default="noname") 176 | 177 | @app.route("/") 178 | async def root(request): 179 | conn = await request["connection"].get_raw_connection() 180 | # noinspection PyProtectedMember 181 | assert ( 182 | conn._holder._max_inactive_time == _MAX_INACTIVE_CONNECTION_LIFETIME 183 | ) 184 | return PlainTextResponse("Hello, world!") 185 | 186 | @app.route("/users/{uid:int}") 187 | async def get_user(request): 188 | uid = request.path_params.get("uid") 189 | method = request.query_params.get("method") 190 | q = User.query.where(User.id == uid) 191 | if method == "1": 192 | return JSONResponse((await q.gino.first_or_404()).to_dict()) 193 | elif method == "2": 194 | return JSONResponse( 195 | (await request["connection"].first_or_404(q)).to_dict() 196 | ) 197 | elif method == "3": 198 | return JSONResponse((await db.bind.first_or_404(q)).to_dict()) 199 | elif method == "4": 200 | return JSONResponse((await db.first_or_404(q)).to_dict()) 201 | else: 202 | return JSONResponse((await User.get_or_404(uid)).to_dict()) 203 | 204 | @app.route("/users", methods=["POST"]) 205 | async def add_user(request): 206 | u = await User.create(nickname=(await request.json()).get("name")) 207 | await u.query.gino.first_or_404() 208 | await db.first_or_404(u.query) 209 | await db.bind.first_or_404(u.query) 210 | await request["connection"].first_or_404(u.query) 211 | return JSONResponse(u.to_dict()) 212 | 213 | e = await gino.create_engine(PG_URL) 214 | try: 215 | try: 216 | await db.gino.create_all(e) 217 | yield app 218 | finally: 219 | await db.gino.drop_all(e) 220 | finally: 221 | await e.close() 222 | 223 | 224 | @pytest.fixture 225 | async def app(): 226 | async for a in _app( 227 | host=DB_ARGS["host"], 228 | port=DB_ARGS["port"], 229 | user=DB_ARGS["user"], 230 | password=DB_ARGS["password"], 231 | database=DB_ARGS["database"], 232 | ): 233 | yield a 234 | 235 | 236 | @pytest.fixture 237 | async def app_factory(): 238 | async for a in _app( 239 | factory=True, 240 | host=DB_ARGS["host"], 241 | port=DB_ARGS["port"], 242 | user=DB_ARGS["user"], 243 | password=DB_ARGS["password"], 244 | database=DB_ARGS["database"], 245 | ): 246 | yield a 247 | 248 | 249 | @pytest.fixture 250 | def ssl_ctx(): 251 | ctx = ssl.create_default_context() 252 | ctx.check_hostname = False 253 | ctx.verify_mode = ssl.CERT_NONE 254 | return ctx 255 | 256 | 257 | @pytest.fixture 258 | async def app_ssl(ssl_ctx): 259 | async for a in _app( 260 | host=DB_ARGS["host"], 261 | port=DB_ARGS["port"], 262 | user=DB_ARGS["user"], 263 | password=DB_ARGS["password"], 264 | database=DB_ARGS["database"], 265 | ssl=ssl_ctx, 266 | ): 267 | yield a 268 | 269 | 270 | @pytest.fixture 271 | async def app_dsn(): 272 | async for a in _app(dsn=PG_URL): 273 | yield a 274 | 275 | 276 | @pytest.fixture 277 | async def app_db_delayed(): 278 | async for a in _app( 279 | host=DB_ARGS["host"], 280 | port=DB_ARGS["port"], 281 | user=DB_ARGS["user"], 282 | password=DB_ARGS["password"], 283 | database=DB_ARGS["database"], 284 | db_delayed=True, 285 | ): 286 | yield a 287 | 288 | 289 | @pytest.fixture( 290 | params=[ 291 | ("simple_starlette_demo", "requirements.txt", "app.py"), 292 | ("simple_fastapi_demo", "requirements.txt", "app.py"), 293 | ("prod_fastapi_demo", "pyproject.toml", "run.py"), 294 | ], 295 | ids=["simple_starlette_demo", "simple_fastapi_demo", "prod_fastapi_demo"], 296 | ) 297 | def venv_client(virtualenv, request, pytestconfig): 298 | demo, install, run = request.param 299 | cwd = Path(__file__).parent.parent.absolute() 300 | run_with_coverage = [virtualenv.python, virtualenv.coverage, "run", "-p"] 301 | base_path = cwd / "examples" / demo 302 | env = virtualenv.env.copy() 303 | env.update( 304 | { 305 | k: v 306 | for k, v in os.environ.items() 307 | if k.startswith("DB_") or k.startswith("APP_") 308 | } 309 | ) 310 | virtualenv.run("pip install coverage") 311 | if install == "requirements.txt": 312 | virtualenv.run("pip install -r requirements.txt", cwd=base_path) 313 | else: 314 | virtualenv.run("pip install poetry", cwd=base_path) 315 | virtualenv.run("poetry install", cwd=base_path) 316 | virtualenv.run( 317 | run_with_coverage 318 | + [ 319 | "--source=src,migrations/versions", 320 | virtualenv.virtualenv / "bin" / "pytest", 321 | ], 322 | cwd=base_path, 323 | env=env, 324 | ) 325 | virtualenv.run( 326 | run_with_coverage 327 | + [ 328 | "--source=src,migrations/versions", 329 | virtualenv.virtualenv / "bin" / "alembic", 330 | "upgrade", 331 | "head", 332 | ], 333 | cwd=base_path, 334 | env=env, 335 | ) 336 | 337 | port = find_free_port() 338 | 339 | class Client(requests.Session): 340 | def request(self, method, url, *args, **kwargs): 341 | url = urljoin("http://localhost:{}".format(port), url) 342 | return super().request(method, url, *args, **kwargs) 343 | 344 | client = Client() 345 | 346 | retries = Retry( 347 | total=6, backoff_factor=0.1, status_forcelist=[500, 502, 503, 504] 348 | ) 349 | 350 | client.mount("http://", HTTPAdapter(max_retries=retries)) 351 | 352 | try: 353 | args = run_with_coverage.copy() 354 | if getattr(pytestconfig.option, "cov_source", None): 355 | source_dirs = ",".join(pytestconfig.option.cov_source) 356 | args += ["--source=%s" % source_dirs] 357 | args.append(base_path / run) 358 | with subprocess.Popen(args, env={"APP_PORT": str(port), **env}) as p: 359 | try: 360 | client.get("/").raise_for_status() 361 | yield client 362 | finally: 363 | p.terminate() 364 | if install == "requirements.txt": 365 | 366 | async def tear_down(): 367 | conn = await asyncpg.connect(PG_URL) 368 | await conn.execute("DROP TABLE {}_users".format(demo)) 369 | await conn.close() 370 | 371 | asyncio.get_event_loop().run_until_complete(tear_down()) 372 | finally: 373 | if install != "requirements.txt": 374 | virtualenv.run( 375 | run_with_coverage 376 | + [ 377 | "--source=src,migrations/versions", 378 | virtualenv.virtualenv / "bin" / "alembic", 379 | "downgrade", 380 | "base", 381 | ], 382 | cwd=base_path, 383 | env=env, 384 | ) 385 | -------------------------------------------------------------------------------- /examples/prod_fastapi_demo/poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "alembic" 3 | version = "1.7.5" 4 | description = "A database migration tool for SQLAlchemy." 5 | category = "main" 6 | optional = false 7 | python-versions = ">=3.6" 8 | 9 | [package.dependencies] 10 | importlib-metadata = {version = "*", markers = "python_version < \"3.9\""} 11 | importlib-resources = {version = "*", markers = "python_version < \"3.9\""} 12 | Mako = "*" 13 | SQLAlchemy = ">=1.3.0" 14 | 15 | [package.extras] 16 | tz = ["python-dateutil"] 17 | 18 | [[package]] 19 | name = "anyio" 20 | version = "3.3.4" 21 | description = "High level compatibility layer for multiple asynchronous event loop implementations" 22 | category = "main" 23 | optional = false 24 | python-versions = ">=3.6.2" 25 | 26 | [package.dependencies] 27 | dataclasses = {version = "*", markers = "python_version < \"3.7\""} 28 | idna = ">=2.8" 29 | sniffio = ">=1.1" 30 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 31 | 32 | [package.extras] 33 | doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] 34 | 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)"] 35 | trio = ["trio (>=0.16)"] 36 | 37 | [[package]] 38 | name = "asgiref" 39 | version = "3.4.1" 40 | description = "ASGI specs, helper code, and adapters" 41 | category = "main" 42 | optional = false 43 | python-versions = ">=3.6" 44 | 45 | [package.dependencies] 46 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 47 | 48 | [package.extras] 49 | tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] 50 | 51 | [[package]] 52 | name = "asyncpg" 53 | version = "0.24.0" 54 | description = "An asyncio PostgreSQL driver" 55 | category = "main" 56 | optional = false 57 | python-versions = ">=3.6.0" 58 | 59 | [package.dependencies] 60 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} 61 | 62 | [package.extras] 63 | dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] 64 | docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] 65 | test = ["pycodestyle (>=2.7.0,<2.8.0)", "flake8 (>=3.9.2,<3.10.0)", "uvloop (>=0.15.3)"] 66 | 67 | [[package]] 68 | name = "atomicwrites" 69 | version = "1.4.0" 70 | description = "Atomic file writes." 71 | category = "dev" 72 | optional = false 73 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 74 | 75 | [[package]] 76 | name = "attrs" 77 | version = "21.2.0" 78 | description = "Classes Without Boilerplate" 79 | category = "dev" 80 | optional = false 81 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 82 | 83 | [package.extras] 84 | dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] 85 | docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] 86 | tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] 87 | tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] 88 | 89 | [[package]] 90 | name = "click" 91 | version = "8.0.3" 92 | description = "Composable command line interface toolkit" 93 | category = "main" 94 | optional = false 95 | python-versions = ">=3.6" 96 | 97 | [package.dependencies] 98 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 99 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 100 | 101 | [[package]] 102 | name = "colorama" 103 | version = "0.4.4" 104 | description = "Cross-platform colored terminal text." 105 | category = "main" 106 | optional = false 107 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 108 | 109 | [[package]] 110 | name = "contextlib2" 111 | version = "21.6.0" 112 | description = "Backports and enhancements for the contextlib module" 113 | category = "main" 114 | optional = false 115 | python-versions = ">=3.6" 116 | 117 | [[package]] 118 | name = "contextvars" 119 | version = "2.4" 120 | description = "PEP 567 Backport" 121 | category = "main" 122 | optional = false 123 | python-versions = "*" 124 | 125 | [package.dependencies] 126 | immutables = ">=0.9" 127 | 128 | [[package]] 129 | name = "dataclasses" 130 | version = "0.8" 131 | description = "A backport of the dataclasses module for Python 3.6" 132 | category = "main" 133 | optional = false 134 | python-versions = ">=3.6, <3.7" 135 | 136 | [[package]] 137 | name = "fastapi" 138 | version = "0.70.0" 139 | description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" 140 | category = "main" 141 | optional = false 142 | python-versions = ">=3.6.1" 143 | 144 | [package.dependencies] 145 | pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" 146 | starlette = "0.16.0" 147 | 148 | [package.extras] 149 | all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.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.16.0)"] 150 | dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] 151 | doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] 152 | test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] 153 | 154 | [[package]] 155 | name = "gino" 156 | version = "1.0.1" 157 | description = "GINO Is Not ORM - a Python asyncio ORM on SQLAlchemy core." 158 | category = "main" 159 | optional = false 160 | python-versions = ">=3.5,<4.0" 161 | 162 | [package.dependencies] 163 | asyncpg = ">=0.18,<1.0" 164 | contextvars = {version = ">=2.4,<3.0", markers = "python_version < \"3.7\""} 165 | gino-starlette = {version = ">=0.1.1,<0.2.0", optional = true, markers = "python_version >= \"3.6\" and python_version < \"4.0\" and extra == \"starlette\""} 166 | importlib_metadata = {version = ">=1.3.0,<2.0.0", markers = "python_version < \"3.8\""} 167 | SQLAlchemy = ">=1.2.16,<1.4" 168 | 169 | [package.extras] 170 | starlette = ["gino-starlette (>=0.1.1,<0.2.0)"] 171 | aiohttp = ["gino-aiohttp (>=0.1.0,<0.2.0)"] 172 | tornado = ["gino-tornado (>=0.1.0,<0.2.0)"] 173 | sanic = ["gino-sanic (>=0.1.0,<0.2.0)"] 174 | quart = ["gino-quart (>=0.1.0,<0.2.0)"] 175 | 176 | [[package]] 177 | name = "gino-starlette" 178 | version = "0.1.3" 179 | description = "An extension for GINO to integrate with Starlette" 180 | category = "main" 181 | optional = false 182 | python-versions = ">=3.6.2,<4.0.0" 183 | 184 | [package.dependencies] 185 | gino = ">=1.0.0,<2.0.0" 186 | starlette = ">=0.16,<0.17" 187 | 188 | [[package]] 189 | name = "gunicorn" 190 | version = "20.1.0" 191 | description = "WSGI HTTP Server for UNIX" 192 | category = "main" 193 | optional = false 194 | python-versions = ">=3.5" 195 | 196 | [package.extras] 197 | eventlet = ["eventlet (>=0.24.1)"] 198 | gevent = ["gevent (>=1.4.0)"] 199 | setproctitle = ["setproctitle"] 200 | tornado = ["tornado (>=0.2)"] 201 | 202 | [[package]] 203 | name = "h11" 204 | version = "0.12.0" 205 | description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" 206 | category = "main" 207 | optional = false 208 | python-versions = ">=3.6" 209 | 210 | [[package]] 211 | name = "idna" 212 | version = "3.3" 213 | description = "Internationalized Domain Names in Applications (IDNA)" 214 | category = "main" 215 | optional = false 216 | python-versions = ">=3.5" 217 | 218 | [[package]] 219 | name = "immutables" 220 | version = "0.16" 221 | description = "Immutable Collections" 222 | category = "main" 223 | optional = false 224 | python-versions = ">=3.6" 225 | 226 | [package.dependencies] 227 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} 228 | 229 | [package.extras] 230 | test = ["flake8 (>=3.8.4,<3.9.0)", "pycodestyle (>=2.6.0,<2.7.0)", "mypy (>=0.910)", "pytest (>=6.2.4,<6.3.0)"] 231 | 232 | [[package]] 233 | name = "importlib-metadata" 234 | version = "1.7.0" 235 | description = "Read metadata from Python packages" 236 | category = "main" 237 | optional = false 238 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 239 | 240 | [package.dependencies] 241 | zipp = ">=0.5" 242 | 243 | [package.extras] 244 | docs = ["sphinx", "rst.linker"] 245 | testing = ["packaging", "pep517", "importlib-resources (>=1.3)"] 246 | 247 | [[package]] 248 | name = "importlib-resources" 249 | version = "5.4.0" 250 | description = "Read resources from Python packages" 251 | category = "main" 252 | optional = false 253 | python-versions = ">=3.6" 254 | 255 | [package.dependencies] 256 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} 257 | 258 | [package.extras] 259 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 260 | testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"] 261 | 262 | [[package]] 263 | name = "iniconfig" 264 | version = "1.1.1" 265 | description = "iniconfig: brain-dead simple config-ini parsing" 266 | category = "dev" 267 | optional = false 268 | python-versions = "*" 269 | 270 | [[package]] 271 | name = "mako" 272 | version = "1.1.5" 273 | description = "A super-fast templating language that borrows the best ideas from the existing templating languages." 274 | category = "main" 275 | optional = false 276 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 277 | 278 | [package.dependencies] 279 | MarkupSafe = ">=0.9.2" 280 | 281 | [package.extras] 282 | babel = ["babel"] 283 | lingua = ["lingua"] 284 | 285 | [[package]] 286 | name = "markupsafe" 287 | version = "2.0.1" 288 | description = "Safely add untrusted strings to HTML/XML markup." 289 | category = "main" 290 | optional = false 291 | python-versions = ">=3.6" 292 | 293 | [[package]] 294 | name = "packaging" 295 | version = "21.2" 296 | description = "Core utilities for Python packages" 297 | category = "dev" 298 | optional = false 299 | python-versions = ">=3.6" 300 | 301 | [package.dependencies] 302 | pyparsing = ">=2.0.2,<3" 303 | 304 | [[package]] 305 | name = "pluggy" 306 | version = "1.0.0" 307 | description = "plugin and hook calling mechanisms for python" 308 | category = "dev" 309 | optional = false 310 | python-versions = ">=3.6" 311 | 312 | [package.dependencies] 313 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 314 | 315 | [package.extras] 316 | dev = ["pre-commit", "tox"] 317 | testing = ["pytest", "pytest-benchmark"] 318 | 319 | [[package]] 320 | name = "psycopg2" 321 | version = "2.9.2" 322 | description = "psycopg2 - Python-PostgreSQL Database Adapter" 323 | category = "main" 324 | optional = false 325 | python-versions = ">=3.6" 326 | 327 | [[package]] 328 | name = "py" 329 | version = "1.11.0" 330 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 331 | category = "dev" 332 | optional = false 333 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 334 | 335 | [[package]] 336 | name = "pydantic" 337 | version = "1.8.2" 338 | description = "Data validation and settings management using python 3.6 type hinting" 339 | category = "main" 340 | optional = false 341 | python-versions = ">=3.6.1" 342 | 343 | [package.dependencies] 344 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} 345 | typing-extensions = ">=3.7.4.3" 346 | 347 | [package.extras] 348 | dotenv = ["python-dotenv (>=0.10.4)"] 349 | email = ["email-validator (>=1.0.3)"] 350 | 351 | [[package]] 352 | name = "pyparsing" 353 | version = "2.4.7" 354 | description = "Python parsing module" 355 | category = "dev" 356 | optional = false 357 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 358 | 359 | [[package]] 360 | name = "pytest" 361 | version = "6.2.5" 362 | description = "pytest: simple powerful testing with Python" 363 | category = "dev" 364 | optional = false 365 | python-versions = ">=3.6" 366 | 367 | [package.dependencies] 368 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 369 | attrs = ">=19.2.0" 370 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 371 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 372 | iniconfig = "*" 373 | packaging = "*" 374 | pluggy = ">=0.12,<2.0" 375 | py = ">=1.8.2" 376 | toml = "*" 377 | 378 | [package.extras] 379 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 380 | 381 | [[package]] 382 | name = "sniffio" 383 | version = "1.2.0" 384 | description = "Sniff out which async library your code is running under" 385 | category = "main" 386 | optional = false 387 | python-versions = ">=3.5" 388 | 389 | [package.dependencies] 390 | contextvars = {version = ">=2.1", markers = "python_version < \"3.7\""} 391 | 392 | [[package]] 393 | name = "sqlalchemy" 394 | version = "1.3.24" 395 | description = "Database Abstraction Library" 396 | category = "main" 397 | optional = false 398 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 399 | 400 | [package.extras] 401 | mssql = ["pyodbc"] 402 | mssql_pymssql = ["pymssql"] 403 | mssql_pyodbc = ["pyodbc"] 404 | mysql = ["mysqlclient"] 405 | oracle = ["cx-oracle"] 406 | postgresql = ["psycopg2"] 407 | postgresql_pg8000 = ["pg8000 (<1.16.6)"] 408 | postgresql_psycopg2binary = ["psycopg2-binary"] 409 | postgresql_psycopg2cffi = ["psycopg2cffi"] 410 | pymysql = ["pymysql (<1)", "pymysql"] 411 | 412 | [[package]] 413 | name = "starlette" 414 | version = "0.16.0" 415 | description = "The little ASGI library that shines." 416 | category = "main" 417 | optional = false 418 | python-versions = ">=3.6" 419 | 420 | [package.dependencies] 421 | anyio = ">=3.0.0,<4" 422 | contextlib2 = {version = ">=21.6.0", markers = "python_version < \"3.7\""} 423 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 424 | 425 | [package.extras] 426 | full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] 427 | 428 | [[package]] 429 | name = "toml" 430 | version = "0.10.2" 431 | description = "Python Library for Tom's Obvious, Minimal Language" 432 | category = "dev" 433 | optional = false 434 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 435 | 436 | [[package]] 437 | name = "typing-extensions" 438 | version = "3.10.0.2" 439 | description = "Backported and Experimental Type Hints for Python 3.5+" 440 | category = "main" 441 | optional = false 442 | python-versions = "*" 443 | 444 | [[package]] 445 | name = "uvicorn" 446 | version = "0.15.0" 447 | description = "The lightning-fast ASGI server." 448 | category = "main" 449 | optional = false 450 | python-versions = "*" 451 | 452 | [package.dependencies] 453 | asgiref = ">=3.4.0" 454 | click = ">=7.0" 455 | h11 = ">=0.8" 456 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 457 | 458 | [package.extras] 459 | standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] 460 | 461 | [[package]] 462 | name = "zipp" 463 | version = "3.6.0" 464 | description = "Backport of pathlib-compatible object wrapper for zip files" 465 | category = "main" 466 | optional = false 467 | python-versions = ">=3.6" 468 | 469 | [package.extras] 470 | docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] 471 | 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"] 472 | 473 | [metadata] 474 | lock-version = "1.1" 475 | python-versions = "^3.6.2" 476 | content-hash = "b10a16cd6921fb63cb46ea4757bcf3e8a179d1353073b082145e3ba23bceb437" 477 | 478 | [metadata.files] 479 | alembic = [ 480 | {file = "alembic-1.7.5-py3-none-any.whl", hash = "sha256:a9dde941534e3d7573d9644e8ea62a2953541e27bc1793e166f60b777ae098b4"}, 481 | {file = "alembic-1.7.5.tar.gz", hash = "sha256:7c328694a2e68f03ee971e63c3bd885846470373a5b532cf2c9f1601c413b153"}, 482 | ] 483 | anyio = [ 484 | {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, 485 | {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, 486 | ] 487 | asgiref = [ 488 | {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, 489 | {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, 490 | ] 491 | asyncpg = [ 492 | {file = "asyncpg-0.24.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c4fc0205fe4ddd5aeb3dfdc0f7bafd43411181e1f5650189608e5971cceacff1"}, 493 | {file = "asyncpg-0.24.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a7095890c96ba36f9f668eb552bb020dddb44f8e73e932f8573efc613ee83843"}, 494 | {file = "asyncpg-0.24.0-cp310-cp310-win_amd64.whl", hash = "sha256:8ff5073d4b654e34bd5eaadc01dc4d68b8a9609084d835acd364cd934190a08d"}, 495 | {file = "asyncpg-0.24.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e36c6806883786b19551bb70a4882561f31135dc8105a59662e0376cf5b2cbc5"}, 496 | {file = "asyncpg-0.24.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ddffcb85227bf39cd1bedd4603e0082b243cf3b14ced64dce506a15b05232b83"}, 497 | {file = "asyncpg-0.24.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41704c561d354bef01353835a7846e5606faabbeb846214dfcf666cf53319f18"}, 498 | {file = "asyncpg-0.24.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ef6ae0a617fc13cc2ac5dc8e9b367bb83cba220614b437af9b67766f4b6b20"}, 499 | {file = "asyncpg-0.24.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eed43abc6ccf1dc02e0d0efc06ce46a411362f3358847c6b0ec9a43426f91ece"}, 500 | {file = "asyncpg-0.24.0-cp38-cp38-win_amd64.whl", hash = "sha256:129d501f3d30616afd51eb8d3142ef51ba05374256bd5834cec3ef4956a9b317"}, 501 | {file = "asyncpg-0.24.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a458fc69051fbb67d995fdda46d75a012b5d6200f91e17d23d4751482640ed4c"}, 502 | {file = "asyncpg-0.24.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:556b0e92e2b75dc028b3c4bc9bd5162ddf0053b856437cf1f04c97f9c6837d03"}, 503 | {file = "asyncpg-0.24.0-cp39-cp39-win_amd64.whl", hash = "sha256:a738f4807c853623d3f93f0fea11f61be6b0e5ca16ea8aeb42c2c7ee742aa853"}, 504 | {file = "asyncpg-0.24.0.tar.gz", hash = "sha256:dd2fa063c3344823487d9ddccb40802f02622ddf8bf8a6cc53885ee7a2c1c0c6"}, 505 | ] 506 | atomicwrites = [ 507 | {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, 508 | {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, 509 | ] 510 | attrs = [ 511 | {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, 512 | {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, 513 | ] 514 | click = [ 515 | {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, 516 | {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, 517 | ] 518 | colorama = [ 519 | {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, 520 | {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, 521 | ] 522 | contextlib2 = [ 523 | {file = "contextlib2-21.6.0-py2.py3-none-any.whl", hash = "sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f"}, 524 | {file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"}, 525 | ] 526 | contextvars = [ 527 | {file = "contextvars-2.4.tar.gz", hash = "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"}, 528 | ] 529 | dataclasses = [ 530 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, 531 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, 532 | ] 533 | fastapi = [ 534 | {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, 535 | {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, 536 | ] 537 | gino = [ 538 | {file = "gino-1.0.1-py3-none-any.whl", hash = "sha256:56df57cfdefbaf897a7c4897c265a0e91a8cca80716fb64f7d3cf6d501fdfb3d"}, 539 | {file = "gino-1.0.1.tar.gz", hash = "sha256:fe4189e82fe9d20c4a5f03fc775fb91c168061c5176b4c95623caeef22316150"}, 540 | ] 541 | gino-starlette = [ 542 | {file = "gino-starlette-0.1.3.tar.gz", hash = "sha256:fbe5cfa5719199079f195c7b7059660859a60dbc74328da14d1b32447e9b2f0f"}, 543 | {file = "gino_starlette-0.1.3-py3-none-any.whl", hash = "sha256:696e8a2ed1574b55a7ada81b4cb0cd092c77943c266803002a97bf04930521bf"}, 544 | ] 545 | gunicorn = [ 546 | {file = "gunicorn-20.1.0-py3-none-any.whl", hash = "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e"}, 547 | {file = "gunicorn-20.1.0.tar.gz", hash = "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8"}, 548 | ] 549 | h11 = [ 550 | {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, 551 | {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, 552 | ] 553 | idna = [ 554 | {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, 555 | {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, 556 | ] 557 | immutables = [ 558 | {file = "immutables-0.16-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:acbfa79d44228d96296279068441f980dc63dbed52522d9227ff9f4d96c6627e"}, 559 | {file = "immutables-0.16-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c9ed003eacb92e630ef200e31f47236c2139b39476894f7963b32bd39bafa3"}, 560 | {file = "immutables-0.16-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a396314b9024fa55bf83a27813fd76cf9f27dce51f53b0f19b51de035146251"}, 561 | {file = "immutables-0.16-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a2a71678348fb95b13ca108d447f559a754c41b47bd1e7e4fb23974e735682d"}, 562 | {file = "immutables-0.16-cp36-cp36m-win32.whl", hash = "sha256:064001638ab5d36f6aa05b6101446f4a5793fb71e522bc81b8fc65a1894266ff"}, 563 | {file = "immutables-0.16-cp36-cp36m-win_amd64.whl", hash = "sha256:1de393f1b188740ca7b38f946f2bbc7edf3910d2048f03bbb8d01f17a038d67c"}, 564 | {file = "immutables-0.16-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fcf678a3074613119385a02a07c469ec5130559f5ea843c85a0840c80b5b71c6"}, 565 | {file = "immutables-0.16-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a307eb0984eb43e815dcacea3ac50c11d00a936ecf694c46991cd5a23bcb0ec0"}, 566 | {file = "immutables-0.16-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7a58825ff2254e2612c5a932174398a4ea8fbddd8a64a02c880cc32ee28b8820"}, 567 | {file = "immutables-0.16-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:798b095381eb42cf40db6876339e7bed84093e5868018a9e73d8e1f7ab4bb21e"}, 568 | {file = "immutables-0.16-cp37-cp37m-win32.whl", hash = "sha256:19bdede174847c2ef1292df0f23868ab3918b560febb09fcac6eec621bd4812b"}, 569 | {file = "immutables-0.16-cp37-cp37m-win_amd64.whl", hash = "sha256:9ccf4c0e3e2e3237012b516c74c49de8872ccdf9129739f7a0b9d7444a8c4862"}, 570 | {file = "immutables-0.16-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d59beef203a3765db72b1d0943547425c8318ecf7d64c451fd1e130b653c2fbb"}, 571 | {file = "immutables-0.16-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0020aaa4010b136056c20a46ce53204e1407a9e4464246cb2cf95b90808d9161"}, 572 | {file = "immutables-0.16-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edd9f67671555af1eb99ad3c7550238487dd7ac0ac5205b40204ed61c9a922ac"}, 573 | {file = "immutables-0.16-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:298a301f85f307b4c056a0825eb30f060e64d73605e783289f3df37dd762bab8"}, 574 | {file = "immutables-0.16-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b779617f5b94486bfd0f22162cd72eb5f2beb0214a14b75fdafb7b2c908ed0cb"}, 575 | {file = "immutables-0.16-cp38-cp38-win32.whl", hash = "sha256:511c93d8b1bbbf103ff3f1f120c5a68a9866ce03dea6ac406537f93ca9b19139"}, 576 | {file = "immutables-0.16-cp38-cp38-win_amd64.whl", hash = "sha256:b651b61c1af6cda2ee201450f2ffe048a5959bc88e43e6c312f4c93e69c9e929"}, 577 | {file = "immutables-0.16-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:aa7bf572ae1e006104c584be70dc634849cf0dc62f42f4ee194774f97e7fd17d"}, 578 | {file = "immutables-0.16-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:50793a44ba0d228ed8cad4d0925e00dfd62ea32f44ddee8854f8066447272d05"}, 579 | {file = "immutables-0.16-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:799621dcdcdcbb2516546a40123b87bf88de75fe7459f7bd8144f079ace6ec3e"}, 580 | {file = "immutables-0.16-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7bcf52aeb983bd803b7c6106eae1b2d9a0c7ab1241bc6b45e2174ba2b7283031"}, 581 | {file = "immutables-0.16-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:734c269e82e5f307fb6e17945953b67659d1731e65309787b8f7ba267d1468f2"}, 582 | {file = "immutables-0.16-cp39-cp39-win32.whl", hash = "sha256:a454d5d3fee4b7cc627345791eb2ca4b27fa3bbb062ccf362ecaaa51679a07ed"}, 583 | {file = "immutables-0.16-cp39-cp39-win_amd64.whl", hash = "sha256:2505d93395d3f8ae4223e21465994c3bc6952015a38dc4f03cb3e07a2b8d8325"}, 584 | {file = "immutables-0.16.tar.gz", hash = "sha256:d67e86859598eed0d926562da33325dac7767b7b1eff84e232c22abea19f4360"}, 585 | ] 586 | importlib-metadata = [ 587 | {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, 588 | {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, 589 | ] 590 | importlib-resources = [ 591 | {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, 592 | {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, 593 | ] 594 | iniconfig = [ 595 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 596 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 597 | ] 598 | mako = [ 599 | {file = "Mako-1.1.5-py2.py3-none-any.whl", hash = "sha256:6804ee66a7f6a6416910463b00d76a7b25194cd27f1918500c5bd7be2a088a23"}, 600 | {file = "Mako-1.1.5.tar.gz", hash = "sha256:169fa52af22a91900d852e937400e79f535496191c63712e3b9fda5a9bed6fc3"}, 601 | ] 602 | markupsafe = [ 603 | {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, 604 | {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, 605 | {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, 606 | {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, 607 | {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"}, 608 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, 609 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, 610 | {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, 611 | {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, 612 | {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, 613 | {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, 614 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, 615 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, 616 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, 617 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, 618 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, 619 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, 620 | {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, 621 | {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"}, 622 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, 623 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, 624 | {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, 625 | {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, 626 | {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, 627 | {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, 628 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, 629 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, 630 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, 631 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, 632 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, 633 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, 634 | {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, 635 | {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"}, 636 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, 637 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, 638 | {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, 639 | {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, 640 | {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, 641 | {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, 642 | {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, 643 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, 644 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, 645 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, 646 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, 647 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, 648 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, 649 | {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, 650 | {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"}, 651 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, 652 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, 653 | {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, 654 | {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, 655 | {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, 656 | {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, 657 | {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, 658 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, 659 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, 660 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, 661 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, 662 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, 663 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, 664 | {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, 665 | {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"}, 666 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, 667 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, 668 | {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, 669 | {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, 670 | {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, 671 | {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, 672 | ] 673 | packaging = [ 674 | {file = "packaging-21.2-py3-none-any.whl", hash = "sha256:14317396d1e8cdb122989b916fa2c7e9ca8e2be9e8060a6eff75b6b7b4d8a7e0"}, 675 | {file = "packaging-21.2.tar.gz", hash = "sha256:096d689d78ca690e4cd8a89568ba06d07ca097e3306a4381635073ca91479966"}, 676 | ] 677 | pluggy = [ 678 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 679 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 680 | ] 681 | psycopg2 = [ 682 | {file = "psycopg2-2.9.2.tar.gz", hash = "sha256:a84da9fa891848e0270e8e04dcca073bc9046441eeb47069f5c0e36783debbea"}, 683 | ] 684 | py = [ 685 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 686 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 687 | ] 688 | pydantic = [ 689 | {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, 690 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, 691 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, 692 | {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, 693 | {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, 694 | {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, 695 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, 696 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, 697 | {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, 698 | {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, 699 | {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, 700 | {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, 701 | {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, 702 | {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, 703 | {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, 704 | {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, 705 | {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, 706 | {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, 707 | {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, 708 | {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, 709 | {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, 710 | {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, 711 | ] 712 | pyparsing = [ 713 | {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, 714 | {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, 715 | ] 716 | pytest = [ 717 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 718 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 719 | ] 720 | sniffio = [ 721 | {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, 722 | {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, 723 | ] 724 | sqlalchemy = [ 725 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, 726 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, 727 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, 728 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, 729 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, 730 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, 731 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, 732 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, 733 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, 734 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, 735 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, 736 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, 737 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, 738 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, 739 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, 740 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, 741 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, 742 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, 743 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, 744 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, 745 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, 746 | {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, 747 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, 748 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, 749 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, 750 | {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, 751 | {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, 752 | {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, 753 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, 754 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, 755 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, 756 | {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, 757 | {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, 758 | {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, 759 | ] 760 | starlette = [ 761 | {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, 762 | {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, 763 | ] 764 | toml = [ 765 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 766 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 767 | ] 768 | typing-extensions = [ 769 | {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, 770 | {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, 771 | {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, 772 | ] 773 | uvicorn = [ 774 | {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, 775 | {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, 776 | ] 777 | zipp = [ 778 | {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, 779 | {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, 780 | ] 781 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Poetry and should not be changed by hand. 2 | 3 | [[package]] 4 | name = "anyio" 5 | version = "3.6.2" 6 | description = "High level compatibility layer for multiple asynchronous event loop implementations" 7 | category = "main" 8 | optional = false 9 | python-versions = ">=3.6.2" 10 | files = [ 11 | {file = "anyio-3.6.2-py3-none-any.whl", hash = "sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3"}, 12 | {file = "anyio-3.6.2.tar.gz", hash = "sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421"}, 13 | ] 14 | 15 | [package.dependencies] 16 | contextvars = {version = "*", markers = "python_version < \"3.7\""} 17 | dataclasses = {version = "*", markers = "python_version < \"3.7\""} 18 | idna = ">=2.8" 19 | sniffio = ">=1.1" 20 | typing-extensions = {version = "*", markers = "python_version < \"3.8\""} 21 | 22 | [package.extras] 23 | doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] 24 | test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] 25 | trio = ["trio (>=0.16,<0.22)"] 26 | 27 | [[package]] 28 | name = "asyncpg" 29 | version = "0.26.0" 30 | description = "An asyncio PostgreSQL driver" 31 | category = "main" 32 | optional = false 33 | python-versions = ">=3.6.0" 34 | files = [ 35 | {file = "asyncpg-0.26.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ed3880b3aec8bda90548218fe0914d251d641f798382eda39a17abfc4910af0"}, 36 | {file = "asyncpg-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5bd99ee7a00e87df97b804f178f31086e88c8106aca9703b1d7be5078999e68"}, 37 | {file = "asyncpg-0.26.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:868a71704262834065ca7113d80b1f679609e2df77d837747e3d92150dd5a39b"}, 38 | {file = "asyncpg-0.26.0-cp310-cp310-win32.whl", hash = "sha256:838e4acd72da370ad07243898e886e93d3c0c9413f4444d600ba60a5cc206014"}, 39 | {file = "asyncpg-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:a254d09a3a989cc1839ba2c34448b879cdd017b528a0cda142c92fbb6c13d957"}, 40 | {file = "asyncpg-0.26.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:3ecbe8ed3af4c739addbfbd78f7752866cce2c4e9cc3f953556e4960349ae360"}, 41 | {file = "asyncpg-0.26.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3ce7d8c0ab4639bbf872439eba86ef62dd030b245ad0e17c8c675d93d7a6b2d"}, 42 | {file = "asyncpg-0.26.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7129bd809990fd119e8b2b9982e80be7712bb6041cd082be3e415e60e5e2e98f"}, 43 | {file = "asyncpg-0.26.0-cp36-cp36m-win32.whl", hash = "sha256:03f44926fa7ff7ccd59e98f05c7e227e9de15332a7da5bbcef3654bf468ee597"}, 44 | {file = "asyncpg-0.26.0-cp36-cp36m-win_amd64.whl", hash = "sha256:b1f7b173af649b85126429e11a628d01a5b75973d2a55d64dba19ad8f0e9f904"}, 45 | {file = "asyncpg-0.26.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe056fd22fc6ed5c1ab353b6510808409566daac4e6f105e2043797f17b8dad"}, 46 | {file = "asyncpg-0.26.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d96cf93e01df9fb03cef5f62346587805e6c0ca6f654c23b8d35315bdc69af59"}, 47 | {file = "asyncpg-0.26.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:235205b60d4d014921f7b1cdca0e19669a9a8978f7606b3eb8237ca95f8e716e"}, 48 | {file = "asyncpg-0.26.0-cp37-cp37m-win32.whl", hash = "sha256:0de408626cfc811ef04f372debfcdd5e4ab5aeb358f2ff14d1bdc246ed6272b5"}, 49 | {file = "asyncpg-0.26.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f92d501bf213b16fabad4fbb0061398d2bceae30ddc228e7314c28dcc6641b79"}, 50 | {file = "asyncpg-0.26.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9acb22a7b6bcca0d80982dce3d67f267d43e960544fb5dd934fd3abe20c48014"}, 51 | {file = "asyncpg-0.26.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e550d8185f2c4725c1e8d3c555fe668b41bd092143012ddcc5343889e1c2a13d"}, 52 | {file = "asyncpg-0.26.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:050e339694f8c5d9aebcf326ca26f6622ef23963a6a3a4f97aeefc743954afd5"}, 53 | {file = "asyncpg-0.26.0-cp38-cp38-win32.whl", hash = "sha256:b0c3f39ebfac06848ba3f1e280cb1fada7cc1229538e3dad3146e8d1f9deb92a"}, 54 | {file = "asyncpg-0.26.0-cp38-cp38-win_amd64.whl", hash = "sha256:49fc7220334cc31d14866a0b77a575d6a5945c0fa3bb67f17304e8b838e2a02b"}, 55 | {file = "asyncpg-0.26.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d156e53b329e187e2dbfca8c28c999210045c45ef22a200b50de9b9e520c2694"}, 56 | {file = "asyncpg-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b4051012ca75defa9a1dc6b78185ca58cdc3a247187eb76a6bcf55dfaa2fad4"}, 57 | {file = "asyncpg-0.26.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d60f15a0ac18c54a6ca6507c28599c06e2e87a0901e7b548f15243d71905b18"}, 58 | {file = "asyncpg-0.26.0-cp39-cp39-win32.whl", hash = "sha256:ede1a3a2c377fe12a3930f4b4dd5340e8b32929541d5db027a21816852723438"}, 59 | {file = "asyncpg-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:8e1e79f0253cbd51fc43c4d0ce8804e46ee71f6c173fdc75606662ad18756b52"}, 60 | {file = "asyncpg-0.26.0.tar.gz", hash = "sha256:77e684a24fee17ba3e487ca982d0259ed17bae1af68006f4cf284b23ba20ea2c"}, 61 | ] 62 | 63 | [package.dependencies] 64 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} 65 | 66 | [package.extras] 67 | dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "flake8 (>=3.9.2,<3.10.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "uvloop (>=0.15.3)"] 68 | docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] 69 | test = ["flake8 (>=3.9.2,<3.10.0)", "pycodestyle (>=2.7.0,<2.8.0)", "uvloop (>=0.15.3)"] 70 | 71 | [[package]] 72 | name = "atomicwrites" 73 | version = "1.4.1" 74 | description = "Atomic file writes." 75 | category = "dev" 76 | optional = false 77 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 78 | files = [ 79 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, 80 | ] 81 | 82 | [[package]] 83 | name = "attrs" 84 | version = "22.2.0" 85 | description = "Classes Without Boilerplate" 86 | category = "dev" 87 | optional = false 88 | python-versions = ">=3.6" 89 | files = [ 90 | {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, 91 | {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, 92 | ] 93 | 94 | [package.extras] 95 | cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] 96 | dev = ["attrs[docs,tests]"] 97 | docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] 98 | tests = ["attrs[tests-no-zope]", "zope.interface"] 99 | tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] 100 | 101 | [[package]] 102 | name = "black" 103 | version = "22.8.0" 104 | description = "The uncompromising code formatter." 105 | category = "dev" 106 | optional = false 107 | python-versions = ">=3.6.2" 108 | files = [ 109 | {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, 110 | {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, 111 | {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, 112 | {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, 113 | {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, 114 | {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, 115 | {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, 116 | {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, 117 | {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, 118 | {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, 119 | {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, 120 | {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, 121 | {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, 122 | {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, 123 | {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, 124 | {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, 125 | {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, 126 | {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, 127 | {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, 128 | {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, 129 | {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, 130 | {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, 131 | {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, 132 | ] 133 | 134 | [package.dependencies] 135 | click = ">=8.0.0" 136 | dataclasses = {version = ">=0.6", markers = "python_version < \"3.7\""} 137 | mypy-extensions = ">=0.4.3" 138 | pathspec = ">=0.9.0" 139 | platformdirs = ">=2" 140 | tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 141 | typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} 142 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 143 | 144 | [package.extras] 145 | colorama = ["colorama (>=0.4.3)"] 146 | d = ["aiohttp (>=3.7.4)"] 147 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 148 | uvloop = ["uvloop (>=0.15.2)"] 149 | 150 | [[package]] 151 | name = "certifi" 152 | version = "2022.12.7" 153 | description = "Python package for providing Mozilla's CA Bundle." 154 | category = "dev" 155 | optional = false 156 | python-versions = ">=3.6" 157 | files = [ 158 | {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, 159 | {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, 160 | ] 161 | 162 | [[package]] 163 | name = "charset-normalizer" 164 | version = "2.0.12" 165 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 166 | category = "dev" 167 | optional = false 168 | python-versions = ">=3.5.0" 169 | files = [ 170 | {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, 171 | {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, 172 | ] 173 | 174 | [package.extras] 175 | unicode-backport = ["unicodedata2"] 176 | 177 | [[package]] 178 | name = "click" 179 | version = "8.0.4" 180 | description = "Composable command line interface toolkit" 181 | category = "dev" 182 | optional = false 183 | python-versions = ">=3.6" 184 | files = [ 185 | {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, 186 | {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, 187 | ] 188 | 189 | [package.dependencies] 190 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 191 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 192 | 193 | [[package]] 194 | name = "colorama" 195 | version = "0.4.5" 196 | description = "Cross-platform colored terminal text." 197 | category = "dev" 198 | optional = false 199 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 200 | files = [ 201 | {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, 202 | {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, 203 | ] 204 | 205 | [[package]] 206 | name = "contextlib2" 207 | version = "21.6.0" 208 | description = "Backports and enhancements for the contextlib module" 209 | category = "main" 210 | optional = false 211 | python-versions = ">=3.6" 212 | files = [ 213 | {file = "contextlib2-21.6.0-py2.py3-none-any.whl", hash = "sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f"}, 214 | {file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"}, 215 | ] 216 | 217 | [[package]] 218 | name = "contextvars" 219 | version = "2.4" 220 | description = "PEP 567 Backport" 221 | category = "main" 222 | optional = false 223 | python-versions = "*" 224 | files = [ 225 | {file = "contextvars-2.4.tar.gz", hash = "sha256:f38c908aaa59c14335eeea12abea5f443646216c4e29380d7bf34d2018e2c39e"}, 226 | ] 227 | 228 | [package.dependencies] 229 | immutables = ">=0.9" 230 | 231 | [[package]] 232 | name = "coverage" 233 | version = "6.2" 234 | description = "Code coverage measurement for Python" 235 | category = "dev" 236 | optional = false 237 | python-versions = ">=3.6" 238 | files = [ 239 | {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, 240 | {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, 241 | {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, 242 | {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, 243 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, 244 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, 245 | {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, 246 | {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, 247 | {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, 248 | {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, 249 | {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, 250 | {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, 251 | {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, 252 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, 253 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, 254 | {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, 255 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, 256 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, 257 | {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, 258 | {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, 259 | {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, 260 | {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, 261 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, 262 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, 263 | {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, 264 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, 265 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, 266 | {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, 267 | {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, 268 | {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, 269 | {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, 270 | {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, 271 | {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, 272 | {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, 273 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, 274 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, 275 | {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, 276 | {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, 277 | {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, 278 | {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, 279 | {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, 280 | {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, 281 | {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, 282 | {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, 283 | {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, 284 | {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, 285 | {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, 286 | ] 287 | 288 | [package.dependencies] 289 | tomli = {version = "*", optional = true, markers = "extra == \"toml\""} 290 | 291 | [package.extras] 292 | toml = ["tomli"] 293 | 294 | [[package]] 295 | name = "dataclasses" 296 | version = "0.8" 297 | description = "A backport of the dataclasses module for Python 3.6" 298 | category = "main" 299 | optional = false 300 | python-versions = ">=3.6, <3.7" 301 | files = [ 302 | {file = "dataclasses-0.8-py3-none-any.whl", hash = "sha256:0201d89fa866f68c8ebd9d08ee6ff50c0b255f8ec63a71c16fda7af82bb887bf"}, 303 | {file = "dataclasses-0.8.tar.gz", hash = "sha256:8479067f342acf957dc82ec415d355ab5edb7e7646b90dc6e2fd1d96ad084c97"}, 304 | ] 305 | 306 | [[package]] 307 | name = "distlib" 308 | version = "0.3.6" 309 | description = "Distribution utilities" 310 | category = "dev" 311 | optional = false 312 | python-versions = "*" 313 | files = [ 314 | {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, 315 | {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, 316 | ] 317 | 318 | [[package]] 319 | name = "exceptiongroup" 320 | version = "1.1.0" 321 | description = "Backport of PEP 654 (exception groups)" 322 | category = "dev" 323 | optional = false 324 | python-versions = ">=3.7" 325 | files = [ 326 | {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, 327 | {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, 328 | ] 329 | 330 | [package.extras] 331 | test = ["pytest (>=6)"] 332 | 333 | [[package]] 334 | name = "execnet" 335 | version = "1.9.0" 336 | description = "execnet: rapid multi-Python deployment" 337 | category = "dev" 338 | optional = false 339 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 340 | files = [ 341 | {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, 342 | {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, 343 | ] 344 | 345 | [package.extras] 346 | testing = ["pre-commit"] 347 | 348 | [[package]] 349 | name = "filelock" 350 | version = "3.4.1" 351 | description = "A platform independent file lock." 352 | category = "dev" 353 | optional = false 354 | python-versions = ">=3.6" 355 | files = [ 356 | {file = "filelock-3.4.1-py3-none-any.whl", hash = "sha256:a4bc51381e01502a30e9f06dd4fa19a1712eab852b6fb0f84fd7cce0793d8ca3"}, 357 | {file = "filelock-3.4.1.tar.gz", hash = "sha256:0f12f552b42b5bf60dba233710bf71337d35494fc8bdd4fd6d9f6d082ad45e06"}, 358 | ] 359 | 360 | [package.extras] 361 | docs = ["furo (>=2021.8.17b43)", "sphinx (>=4.1)", "sphinx-autodoc-typehints (>=1.12)"] 362 | testing = ["covdefaults (>=1.2.0)", "coverage (>=4)", "pytest (>=4)", "pytest-cov", "pytest-timeout (>=1.4.2)"] 363 | 364 | [[package]] 365 | name = "gino" 366 | version = "1.0.1" 367 | description = "GINO Is Not ORM - a Python asyncio ORM on SQLAlchemy core." 368 | category = "main" 369 | optional = false 370 | python-versions = ">=3.5,<4.0" 371 | files = [ 372 | {file = "gino-1.0.1-py3-none-any.whl", hash = "sha256:56df57cfdefbaf897a7c4897c265a0e91a8cca80716fb64f7d3cf6d501fdfb3d"}, 373 | {file = "gino-1.0.1.tar.gz", hash = "sha256:fe4189e82fe9d20c4a5f03fc775fb91c168061c5176b4c95623caeef22316150"}, 374 | ] 375 | 376 | [package.dependencies] 377 | asyncpg = ">=0.18,<1.0" 378 | contextvars = {version = ">=2.4,<3.0", markers = "python_version < \"3.7\""} 379 | importlib_metadata = {version = ">=1.3.0,<2.0.0", markers = "python_version < \"3.8\""} 380 | SQLAlchemy = ">=1.2.16,<1.4" 381 | 382 | [package.extras] 383 | aiohttp = ["gino-aiohttp (>=0.1.0,<0.2.0)"] 384 | quart = ["gino-quart (>=0.1.0,<0.2.0)"] 385 | sanic = ["gino-sanic (>=0.1.0,<0.2.0)"] 386 | starlette = ["gino-starlette (>=0.1.1,<0.2.0)"] 387 | tornado = ["gino-tornado (>=0.1.0,<0.2.0)"] 388 | 389 | [[package]] 390 | name = "idna" 391 | version = "3.4" 392 | description = "Internationalized Domain Names in Applications (IDNA)" 393 | category = "main" 394 | optional = false 395 | python-versions = ">=3.5" 396 | files = [ 397 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 398 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 399 | ] 400 | 401 | [[package]] 402 | name = "immutables" 403 | version = "0.19" 404 | description = "Immutable Collections" 405 | category = "main" 406 | optional = false 407 | python-versions = ">=3.6" 408 | files = [ 409 | {file = "immutables-0.19-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fef6743f8c3098ae46d9a2a3606b04a91c62e216487d91e90ce5c7419da3f803"}, 410 | {file = "immutables-0.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cfb62119b7302a37cb4a1db44234dab9acda60ba93e3c28489969722e85237b7"}, 411 | {file = "immutables-0.19-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d55b886e92ef5abfc4b066f404d956ca5789a2f8f738d448300fba40930a631"}, 412 | {file = "immutables-0.19-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f1c3ab3ae690a55a2f61039705a110f0e23717d6d8a62a84600fc7cf5934dc"}, 413 | {file = "immutables-0.19-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f3096afb376b9b3651a3b92affd1896b4dcefde209f412572f7e3924f6749a49"}, 414 | {file = "immutables-0.19-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:85bcb5a7c33100c1b2eeb8c71e5f80acab4c9dde074b2c2ca8e3dfb6830ce813"}, 415 | {file = "immutables-0.19-cp310-cp310-win_amd64.whl", hash = "sha256:620c166e76030ca4772ea64e5190f8347a730a0af85b743820d351f211004397"}, 416 | {file = "immutables-0.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c1774f298db9d460e50c40dfc9cfe7dd8a0de22c22f1de9a1f9a468daa1201dc"}, 417 | {file = "immutables-0.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:24dbdc28779a2b75e06224609f4fc850ba61b7e1b74e32ec808c6430a535be2d"}, 418 | {file = "immutables-0.19-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b8c0a4264e3ba2f025f4517ce67f0d0869106a625dbda08758cbf4dd6b6dd1f"}, 419 | {file = "immutables-0.19-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28d1ee66424c2db998d27ebe0a331c7e09627e54a402848b2897cb6ef4dc4d7e"}, 420 | {file = "immutables-0.19-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6f857aec0e0455986fd1f41234c867c3daf5a89ff7f54d493d4eb3c233d36d3c"}, 421 | {file = "immutables-0.19-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:119c60a05cb35add45c1e592e23a5cbb9db03161bb89d1596b920d9341173982"}, 422 | {file = "immutables-0.19-cp311-cp311-win_amd64.whl", hash = "sha256:3fbad255e404b4cbcf3477b384a1e400bd8f28cbbfc2df8d3885abe3bfc7b909"}, 423 | {file = "immutables-0.19-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:6660e185354a1cb59ecc130f2b85b50d666d4417be668ce6ba83d4be79f55d34"}, 424 | {file = "immutables-0.19-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37de95c1d79707d95f50d0ab79e067bee52381afc967ff031ac4c822c14f43a8"}, 425 | {file = "immutables-0.19-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed61dbc963251bec7281cdb0c148176bbd70519d21fd05bce4c484632cdc3b2c"}, 426 | {file = "immutables-0.19-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:7da9356a163993e01785a211b47c6a0038b48d1235b68479a0053c2c4c3cf666"}, 427 | {file = "immutables-0.19-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:41d8cae52ea527f9c6dccdf1e1553106c482496acc140523034f91877ccbc103"}, 428 | {file = "immutables-0.19-cp36-cp36m-win_amd64.whl", hash = "sha256:e95f0826f184920adb3cdf830f409f1c1d4e943e4dc50242538c4df9d51eea72"}, 429 | {file = "immutables-0.19-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:50608784e33c88da8c0e06e75f6725865cf2e345c8f3eeb83cb85111f737e986"}, 430 | {file = "immutables-0.19-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cbd4d9dc531ee24b2387141a5968e923bb6174d13695e730cde0887aadda557"}, 431 | {file = "immutables-0.19-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eed8988dc4ebde8d527dbe4dea68cb9fe6d43bc56df60d6015130dc4abd2ab34"}, 432 | {file = "immutables-0.19-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c830c9afc6fcb4a7d6d74230d6290987e664418026a15488ad00d8a3dc5ec743"}, 433 | {file = "immutables-0.19-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7c6cce2e87cd5369234b199037631cfed08e43813a1fdd750807d14404de195b"}, 434 | {file = "immutables-0.19-cp37-cp37m-win_amd64.whl", hash = "sha256:10774f73af07b1648fa02f45f6ff88b3391feda65d4f640159e6eeec10540ece"}, 435 | {file = "immutables-0.19-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a208a945ea817b1455b5b0f9c33c097baf6443b50d749a3dc32ff445e41b81d2"}, 436 | {file = "immutables-0.19-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25a6225efb5e96fc95d84b2d280e35d8a82a1ae72a12857177d48cc289ac1e03"}, 437 | {file = "immutables-0.19-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c0cf0d94b08e58896acf250cbc4682499c8a256fc6d0ee5c63d76a759a6a228"}, 438 | {file = "immutables-0.19-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64c74c5171f3a97b178b880746743a07b08e7d7f6055370bf04a94d50aea0643"}, 439 | {file = "immutables-0.19-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8ababf72ed2a956b28f151d605a7bb1d4e1c59113f53bf2be4a586da3977b319"}, 440 | {file = "immutables-0.19-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:52a91917c65e6b9cfef7a2d2c3b0e00432a153aa8650785b7ee0897d80226278"}, 441 | {file = "immutables-0.19-cp38-cp38-win_amd64.whl", hash = "sha256:bbe65c23779e12e0ecc3dec2c709ad22b7cc8b163895327bc173ae06a8b73425"}, 442 | {file = "immutables-0.19-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:480cc5d62efcac66f9737ae0820acd39d39e516e6fdbcf46cbdc26f11b429fd7"}, 443 | {file = "immutables-0.19-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2d88ff44e131508def4740964076c3da273baeeb406c1fe139f18373ea4196dd"}, 444 | {file = "immutables-0.19-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fa3148393101b0c4571da523929ae90a5b4bfc933c270a11b802a34a921c608"}, 445 | {file = "immutables-0.19-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0575190a90c3fce6862ccdb09be3344741ff97a96e559893541886d372139f1c"}, 446 | {file = "immutables-0.19-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3754b26ef18b5d1009ffdeafc17fbd877a79f0a126e1423069bd8ef51c54302d"}, 447 | {file = "immutables-0.19-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:648142e16d49f5207ae52ee1b28dfa148206471967b9c9eaa5a9592fd32d5cef"}, 448 | {file = "immutables-0.19-cp39-cp39-win_amd64.whl", hash = "sha256:199db9070ffa1a037e6650ddd63159907a210e4998f932bdf50e70615629db0c"}, 449 | {file = "immutables-0.19.tar.gz", hash = "sha256:df17942d60e8080835fcc5245aa6928ef4c1ed567570ec019185798195048dcf"}, 450 | ] 451 | 452 | [package.dependencies] 453 | typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} 454 | 455 | [package.extras] 456 | test = ["flake8 (>=5.0.4,<5.1.0)", "mypy (==0.971)", "pycodestyle (>=2.9.1,<2.10.0)", "pytest (>=6.2.4,<6.3.0)"] 457 | 458 | [[package]] 459 | name = "importlib-metadata" 460 | version = "1.7.0" 461 | description = "Read metadata from Python packages" 462 | category = "main" 463 | optional = false 464 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 465 | files = [ 466 | {file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"}, 467 | {file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"}, 468 | ] 469 | 470 | [package.dependencies] 471 | zipp = ">=0.5" 472 | 473 | [package.extras] 474 | docs = ["rst.linker", "sphinx"] 475 | testing = ["importlib-resources (>=1.3)", "packaging", "pep517"] 476 | 477 | [[package]] 478 | name = "importlib-resources" 479 | version = "5.4.0" 480 | description = "Read resources from Python packages" 481 | category = "dev" 482 | optional = false 483 | python-versions = ">=3.6" 484 | files = [ 485 | {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"}, 486 | {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"}, 487 | ] 488 | 489 | [package.dependencies] 490 | zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} 491 | 492 | [package.extras] 493 | docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] 494 | testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] 495 | 496 | [[package]] 497 | name = "iniconfig" 498 | version = "1.1.1" 499 | description = "iniconfig: brain-dead simple config-ini parsing" 500 | category = "dev" 501 | optional = false 502 | python-versions = "*" 503 | files = [ 504 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 505 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 506 | ] 507 | 508 | [[package]] 509 | name = "iniconfig" 510 | version = "2.0.0" 511 | description = "brain-dead simple config-ini parsing" 512 | category = "dev" 513 | optional = false 514 | python-versions = ">=3.7" 515 | files = [ 516 | {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, 517 | {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, 518 | ] 519 | 520 | [[package]] 521 | name = "mock" 522 | version = "5.0.0" 523 | description = "Rolling backport of unittest.mock for all Pythons" 524 | category = "dev" 525 | optional = false 526 | python-versions = ">=3.6" 527 | files = [ 528 | {file = "mock-5.0.0-py3-none-any.whl", hash = "sha256:335ef0bf9bcd27505c0c1720d4eac2783f18d07d6f45ac49542b57885a1996dd"}, 529 | {file = "mock-5.0.0.tar.gz", hash = "sha256:fd552787228eb2ab8352f270470fa93c9ad8b9cbc565c5558ee3faed8edb3853"}, 530 | ] 531 | 532 | [package.extras] 533 | build = ["blurb", "twine", "wheel"] 534 | docs = ["sphinx"] 535 | test = ["pytest", "pytest-cov"] 536 | 537 | [[package]] 538 | name = "mypy-extensions" 539 | version = "0.4.3" 540 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 541 | category = "dev" 542 | optional = false 543 | python-versions = "*" 544 | files = [ 545 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 546 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 547 | ] 548 | 549 | [[package]] 550 | name = "packaging" 551 | version = "21.3" 552 | description = "Core utilities for Python packages" 553 | category = "dev" 554 | optional = false 555 | python-versions = ">=3.6" 556 | files = [ 557 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 558 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 559 | ] 560 | 561 | [package.dependencies] 562 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 563 | 564 | [[package]] 565 | name = "packaging" 566 | version = "23.0" 567 | description = "Core utilities for Python packages" 568 | category = "dev" 569 | optional = false 570 | python-versions = ">=3.7" 571 | files = [ 572 | {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, 573 | {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, 574 | ] 575 | 576 | [[package]] 577 | name = "path" 578 | version = "16.2.0" 579 | description = "A module wrapper for os.path" 580 | category = "dev" 581 | optional = false 582 | python-versions = ">=3.6" 583 | files = [ 584 | {file = "path-16.2.0-py3-none-any.whl", hash = "sha256:340054c5bb459fc9fd40e7eb6768c5989f3e599d18224238465b5333bc8faa7d"}, 585 | {file = "path-16.2.0.tar.gz", hash = "sha256:2de925e8d421f93bcea80d511b81accfb6a7e6b249afa4a5559557b0cf817097"}, 586 | ] 587 | 588 | [package.extras] 589 | docs = ["jaraco.packaging (>=8.2)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] 590 | testing = ["appdirs", "packaging", "pygments", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy", "pywin32"] 591 | 592 | [[package]] 593 | name = "path-py" 594 | version = "12.5.0" 595 | description = "A module wrapper for os.path" 596 | category = "dev" 597 | optional = false 598 | python-versions = ">=3.5" 599 | files = [ 600 | {file = "path.py-12.5.0-py3-none-any.whl", hash = "sha256:a43e82eb2c344c3fd0b9d6352f6b856f40b8b7d3d65cc05978b42c3715668496"}, 601 | {file = "path.py-12.5.0.tar.gz", hash = "sha256:8d885e8b2497aed005703d94e0fd97943401f035e42a136810308bff034529a8"}, 602 | ] 603 | 604 | [package.dependencies] 605 | path = "*" 606 | 607 | [package.extras] 608 | docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] 609 | testing = ["appdirs", "packaging", "pygments", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8"] 610 | 611 | [[package]] 612 | name = "pathspec" 613 | version = "0.9.0" 614 | description = "Utility library for gitignore style pattern matching of file paths." 615 | category = "dev" 616 | optional = false 617 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" 618 | files = [ 619 | {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, 620 | {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, 621 | ] 622 | 623 | [[package]] 624 | name = "platformdirs" 625 | version = "2.4.0" 626 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 627 | category = "dev" 628 | optional = false 629 | python-versions = ">=3.6" 630 | files = [ 631 | {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, 632 | {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, 633 | ] 634 | 635 | [package.extras] 636 | docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] 637 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 638 | 639 | [[package]] 640 | name = "pluggy" 641 | version = "1.0.0" 642 | description = "plugin and hook calling mechanisms for python" 643 | category = "dev" 644 | optional = false 645 | python-versions = ">=3.6" 646 | files = [ 647 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 648 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 649 | ] 650 | 651 | [package.dependencies] 652 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 653 | 654 | [package.extras] 655 | dev = ["pre-commit", "tox"] 656 | testing = ["pytest", "pytest-benchmark"] 657 | 658 | [[package]] 659 | name = "py" 660 | version = "1.11.0" 661 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 662 | category = "dev" 663 | optional = false 664 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 665 | files = [ 666 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 667 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 668 | ] 669 | 670 | [[package]] 671 | name = "pyparsing" 672 | version = "3.0.7" 673 | description = "Python parsing module" 674 | category = "dev" 675 | optional = false 676 | python-versions = ">=3.6" 677 | files = [ 678 | {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, 679 | {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, 680 | ] 681 | 682 | [package.extras] 683 | diagrams = ["jinja2", "railroad-diagrams"] 684 | 685 | [[package]] 686 | name = "pytest" 687 | version = "6.2.5" 688 | description = "pytest: simple powerful testing with Python" 689 | category = "dev" 690 | optional = false 691 | python-versions = ">=3.6" 692 | files = [ 693 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 694 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 695 | ] 696 | 697 | [package.dependencies] 698 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 699 | attrs = ">=19.2.0" 700 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 701 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 702 | iniconfig = "*" 703 | packaging = "*" 704 | pluggy = ">=0.12,<2.0" 705 | py = ">=1.8.2" 706 | toml = "*" 707 | 708 | [package.extras] 709 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 710 | 711 | [[package]] 712 | name = "pytest" 713 | version = "7.2.0" 714 | description = "pytest: simple powerful testing with Python" 715 | category = "dev" 716 | optional = false 717 | python-versions = ">=3.7" 718 | files = [ 719 | {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, 720 | {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, 721 | ] 722 | 723 | [package.dependencies] 724 | attrs = ">=19.2.0" 725 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 726 | exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} 727 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 728 | iniconfig = "*" 729 | packaging = "*" 730 | pluggy = ">=0.12,<2.0" 731 | tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} 732 | 733 | [package.extras] 734 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] 735 | 736 | [[package]] 737 | name = "pytest-asyncio" 738 | version = "0.15.1" 739 | description = "Pytest support for asyncio." 740 | category = "dev" 741 | optional = false 742 | python-versions = ">= 3.6" 743 | files = [ 744 | {file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"}, 745 | {file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"}, 746 | ] 747 | 748 | [package.dependencies] 749 | pytest = ">=5.4.0" 750 | 751 | [package.extras] 752 | testing = ["coverage", "hypothesis (>=5.7.1)"] 753 | 754 | [[package]] 755 | name = "pytest-cov" 756 | version = "3.0.0" 757 | description = "Pytest plugin for measuring coverage." 758 | category = "dev" 759 | optional = false 760 | python-versions = ">=3.6" 761 | files = [ 762 | {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, 763 | {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, 764 | ] 765 | 766 | [package.dependencies] 767 | coverage = {version = ">=5.2.1", extras = ["toml"]} 768 | pytest = ">=4.6" 769 | 770 | [package.extras] 771 | testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] 772 | 773 | [[package]] 774 | name = "pytest-fixture-config" 775 | version = "1.7.0" 776 | description = "Fixture configuration utils for py.test" 777 | category = "dev" 778 | optional = false 779 | python-versions = "*" 780 | files = [ 781 | {file = "pytest-fixture-config-1.7.0.tar.gz", hash = "sha256:41a17417721f6862ce6b40e3280fddd8e1659b2c306ec46b237d7021fec5218e"}, 782 | {file = "pytest_fixture_config-1.7.0-py2.py3-none-any.whl", hash = "sha256:a0e35e239e70fa12614bbe9ca51d3238fbeb89519deb80cd365b487665a666b0"}, 783 | ] 784 | 785 | [package.dependencies] 786 | pytest = "*" 787 | 788 | [package.extras] 789 | tests = ["six"] 790 | 791 | [[package]] 792 | name = "pytest-mock" 793 | version = "3.6.1" 794 | description = "Thin-wrapper around the mock package for easier use with pytest" 795 | category = "dev" 796 | optional = false 797 | python-versions = ">=3.6" 798 | files = [ 799 | {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, 800 | {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, 801 | ] 802 | 803 | [package.dependencies] 804 | pytest = ">=5.0" 805 | 806 | [package.extras] 807 | dev = ["pre-commit", "pytest-asyncio", "tox"] 808 | 809 | [[package]] 810 | name = "pytest-shutil" 811 | version = "1.7.0" 812 | description = "A goodie-bag of unix shell and environment tools for py.test" 813 | category = "dev" 814 | optional = false 815 | python-versions = "*" 816 | files = [ 817 | {file = "pytest-shutil-1.7.0.tar.gz", hash = "sha256:d8165261de76e7508505c341d94c02b113dc963f274543abca74dbfabd021261"}, 818 | {file = "pytest_shutil-1.7.0-py2.py3-none-any.whl", hash = "sha256:b3568a675cb092c9b15c789ebd3046b79cfaca476868939748729d14557a98ff"}, 819 | ] 820 | 821 | [package.dependencies] 822 | contextlib2 = "*" 823 | execnet = "*" 824 | mock = "*" 825 | "path.py" = "*" 826 | pytest = "*" 827 | six = "*" 828 | termcolor = "*" 829 | 830 | [package.extras] 831 | tests = ["pytest"] 832 | 833 | [[package]] 834 | name = "pytest-virtualenv" 835 | version = "1.7.0" 836 | description = "Virtualenv fixture for py.test" 837 | category = "dev" 838 | optional = false 839 | python-versions = "*" 840 | files = [ 841 | {file = "pytest-virtualenv-1.7.0.tar.gz", hash = "sha256:2270ee8822111ec25db48e9d9f2efec32e68483a015b14cd0d92aeccc6ff820f"}, 842 | {file = "pytest_virtualenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:fee44d423701d6ab550b202aa8e45ccda77bfe8e72c4318a8f43e6af553ad502"}, 843 | ] 844 | 845 | [package.dependencies] 846 | pytest = "*" 847 | pytest-fixture-config = "*" 848 | pytest-shutil = "*" 849 | virtualenv = "*" 850 | 851 | [package.extras] 852 | tests = ["mock"] 853 | 854 | [[package]] 855 | name = "requests" 856 | version = "2.27.1" 857 | description = "Python HTTP for Humans." 858 | category = "dev" 859 | optional = false 860 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 861 | files = [ 862 | {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, 863 | {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, 864 | ] 865 | 866 | [package.dependencies] 867 | certifi = ">=2017.4.17" 868 | charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} 869 | idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} 870 | urllib3 = ">=1.21.1,<1.27" 871 | 872 | [package.extras] 873 | socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] 874 | use-chardet-on-py3 = ["chardet (>=3.0.2,<5)"] 875 | 876 | [[package]] 877 | name = "six" 878 | version = "1.16.0" 879 | description = "Python 2 and 3 compatibility utilities" 880 | category = "dev" 881 | optional = false 882 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" 883 | files = [ 884 | {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, 885 | {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, 886 | ] 887 | 888 | [[package]] 889 | name = "sniffio" 890 | version = "1.2.0" 891 | description = "Sniff out which async library your code is running under" 892 | category = "main" 893 | optional = false 894 | python-versions = ">=3.5" 895 | files = [ 896 | {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, 897 | {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, 898 | ] 899 | 900 | [package.dependencies] 901 | contextvars = {version = ">=2.1", markers = "python_version < \"3.7\""} 902 | 903 | [[package]] 904 | name = "sqlalchemy" 905 | version = "1.3.24" 906 | description = "Database Abstraction Library" 907 | category = "main" 908 | optional = false 909 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 910 | files = [ 911 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, 912 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, 913 | {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, 914 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, 915 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, 916 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, 917 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, 918 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, 919 | {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, 920 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, 921 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, 922 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, 923 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, 924 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, 925 | {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, 926 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, 927 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, 928 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, 929 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, 930 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, 931 | {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, 932 | {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, 933 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, 934 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, 935 | {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, 936 | {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, 937 | {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, 938 | {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, 939 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, 940 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, 941 | {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, 942 | {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, 943 | {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, 944 | {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, 945 | ] 946 | 947 | [package.extras] 948 | mssql = ["pyodbc"] 949 | mssql-pymssql = ["pymssql"] 950 | mssql-pyodbc = ["pyodbc"] 951 | mysql = ["mysqlclient"] 952 | oracle = ["cx_oracle"] 953 | postgresql = ["psycopg2"] 954 | postgresql-pg8000 = ["pg8000 (<1.16.6)"] 955 | postgresql-psycopg2binary = ["psycopg2-binary"] 956 | postgresql-psycopg2cffi = ["psycopg2cffi"] 957 | pymysql = ["pymysql", "pymysql (<1)"] 958 | 959 | [[package]] 960 | name = "starlette" 961 | version = "0.19.1" 962 | description = "The little ASGI library that shines." 963 | category = "main" 964 | optional = false 965 | python-versions = ">=3.6" 966 | files = [ 967 | {file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"}, 968 | {file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"}, 969 | ] 970 | 971 | [package.dependencies] 972 | anyio = ">=3.4.0,<5" 973 | contextlib2 = {version = ">=21.6.0", markers = "python_version < \"3.7\""} 974 | typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} 975 | 976 | [package.extras] 977 | full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] 978 | 979 | [[package]] 980 | name = "termcolor" 981 | version = "1.1.0" 982 | description = "ANSII Color formatting for output in terminal." 983 | category = "dev" 984 | optional = false 985 | python-versions = "*" 986 | files = [ 987 | {file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"}, 988 | ] 989 | 990 | [[package]] 991 | name = "toml" 992 | version = "0.10.2" 993 | description = "Python Library for Tom's Obvious, Minimal Language" 994 | category = "dev" 995 | optional = false 996 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 997 | files = [ 998 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 999 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "tomli" 1004 | version = "1.2.3" 1005 | description = "A lil' TOML parser" 1006 | category = "dev" 1007 | optional = false 1008 | python-versions = ">=3.6" 1009 | files = [ 1010 | {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, 1011 | {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, 1012 | ] 1013 | 1014 | [[package]] 1015 | name = "typed-ast" 1016 | version = "1.5.4" 1017 | description = "a fork of Python 2 and 3 ast modules with type comment support" 1018 | category = "dev" 1019 | optional = false 1020 | python-versions = ">=3.6" 1021 | files = [ 1022 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, 1023 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, 1024 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, 1025 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, 1026 | {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, 1027 | {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, 1028 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, 1029 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, 1030 | {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, 1031 | {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, 1032 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, 1033 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, 1034 | {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, 1035 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, 1036 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, 1037 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, 1038 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, 1039 | {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, 1040 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, 1041 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, 1042 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, 1043 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, 1044 | {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, 1045 | {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "typing-extensions" 1050 | version = "4.1.1" 1051 | description = "Backported and Experimental Type Hints for Python 3.6+" 1052 | category = "main" 1053 | optional = false 1054 | python-versions = ">=3.6" 1055 | files = [ 1056 | {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, 1057 | {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, 1058 | ] 1059 | 1060 | [[package]] 1061 | name = "urllib3" 1062 | version = "1.26.13" 1063 | description = "HTTP library with thread-safe connection pooling, file post, and more." 1064 | category = "dev" 1065 | optional = false 1066 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" 1067 | files = [ 1068 | {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, 1069 | {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, 1070 | ] 1071 | 1072 | [package.extras] 1073 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] 1074 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] 1075 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 1076 | 1077 | [[package]] 1078 | name = "virtualenv" 1079 | version = "20.16.2" 1080 | description = "Virtual Python Environment builder" 1081 | category = "dev" 1082 | optional = false 1083 | python-versions = ">=3.6" 1084 | files = [ 1085 | {file = "virtualenv-20.16.2-py2.py3-none-any.whl", hash = "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3"}, 1086 | {file = "virtualenv-20.16.2.tar.gz", hash = "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db"}, 1087 | ] 1088 | 1089 | [package.dependencies] 1090 | distlib = ">=0.3.1,<1" 1091 | filelock = ">=3.2,<4" 1092 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 1093 | importlib-resources = {version = ">=1.0", markers = "python_version < \"3.7\""} 1094 | platformdirs = ">=2,<3" 1095 | 1096 | [package.extras] 1097 | docs = ["proselint (>=0.10.2)", "sphinx (>=3)", "sphinx-argparse (>=0.2.5)", "sphinx-rtd-theme (>=0.4.3)", "towncrier (>=21.3)"] 1098 | testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)", "packaging (>=20.0)", "pytest (>=4)", "pytest-env (>=0.6.2)", "pytest-freezegun (>=0.4.1)", "pytest-mock (>=2)", "pytest-randomly (>=1)", "pytest-timeout (>=1)"] 1099 | 1100 | [[package]] 1101 | name = "zipp" 1102 | version = "3.6.0" 1103 | description = "Backport of pathlib-compatible object wrapper for zip files" 1104 | category = "main" 1105 | optional = false 1106 | python-versions = ">=3.6" 1107 | files = [ 1108 | {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, 1109 | {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, 1110 | ] 1111 | 1112 | [package.extras] 1113 | docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] 1114 | testing = ["func-timeout", "jaraco.itertools", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] 1115 | 1116 | [metadata] 1117 | lock-version = "2.0" 1118 | python-versions = ">=3.6.2,<4.0" # fresh black requires at least 3.6.2 so we can't use ^3.6 1119 | content-hash = "50d7a1f7269c430bb613cc9efaebee12f2045d191be47d1104ee54ac1986d95a" 1120 | --------------------------------------------------------------------------------