diff --git a/Dockerfile b/Dockerfile index 3bf5999..1d0f9b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ RUN apt-get update && apt-get install -y git #RUN pip install apihub COPY . /code -RUN pip install /code/dist/apihub-0.1.0-py3-none-any.whl +RUN curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python - # expose port for prometheus EXPOSE 8000 @@ -14,4 +14,4 @@ EXPOSE 5000 ENV PORT 5000 -CMD ["apihub_server"] +CMD ["poetry", "apihub_server"] diff --git a/Makefile b/Makefile index ea3d8f7..cb7ac8a 100644 --- a/Makefile +++ b/Makefile @@ -19,6 +19,25 @@ pdb: mypy: poetry run mypy --ignore-missing-imports apihub +.PHONY: result +result: + PYTHONPATH=../pipeline/src poetry run python apihub/result.py \ + --in-kind FILE --in-filename tests/fixtures/result_input.txt \ + --out-kind FILE --out-filename - \ + --debug + +.PHONY: redis-result +redis-result: + PYTHONPATH=../pipeline/src poetry run python apihub/result.py \ + --in-kind LREDIS --in-redis redis://localhost:6379/1 \ + --in-topic result --in-namespace apihub \ + --debug + +.PHONY: server +server: + PYTHONPATH=../pipeline/src poetry run python apihub/server.py \ + --out-kind LREDIS --debug + .PHONY: pre-commit pre-commit: pre-commit run --all-files diff --git a/README.rst b/README.rst index f5abd29..1134802 100644 --- a/README.rst +++ b/README.rst @@ -20,7 +20,7 @@

- Logo + Logo

APIHub

@@ -89,32 +89,26 @@ About The Project `[Product Name Screen Shot][product-screenshot] `__ -Here’s a blank template to get started: **To avoid retyping too much -info. Do a search and replace with your text editor for the following:** -``yifan``, ``apihub``, ``yifan2019``, ``email``, ``APIHub``, -``project_description`` + Features & TODOs ---------------- -:: - - [X] Security - [X] authenticate - [X] admin, manager, user - [X] user management - [X] rate limiter - [ ] register - [ ] social login - [ ] Subscription - [-] subscription - [-] quota - [X] application token - [-] daily usage record in redis - [ ] Async/sync API calls - [ ] api worker reports input/output: describe - [X] generic worker deployment - [ ] auto scaler for api workers +- |check| Security + |check| authenticate + |check| admin, manager, user + |check| user management + - |check| rate limiter + - |check| register + - |uncheck_| social login +- |check| Subscription + - |check| subscription + - |check| application token + - |check| daily usage record in redis +- |uncheck| Async/sync API calls + - |check| api worker reports input/output: describe + - |check| generic worker deployment + - |uncheck| auto scaler for api workers Built With ---------- @@ -276,6 +270,22 @@ Copyright (C) 2021, Qatar Computing Research Institute, HBKU +.. |check| raw:: html + + + +.. |check_| raw:: html + + + +.. |uncheck| raw:: html + + + +.. |uncheck_| raw:: html + + + .. |Contributors| image:: https://img.shields.io/github/contributors/yifan/apihub.svg?style=for-the-badge :target: https://github.com/yifan/apihub/graphs/contributors diff --git a/apihub/cli.py b/apihub/cli.py index 275a966..4be71a9 100644 --- a/apihub/cli.py +++ b/apihub/cli.py @@ -91,7 +91,7 @@ def create_subscription(admin, limit, days, recurring, username, application): "username": username, "application": application, "starts_at": datetime.now(), - "limit": limit, + "credit": limit, "expires_at": expires_at, "recurring": recurring, } diff --git a/apihub/result.py b/apihub/result.py index 8544893..694a65e 100644 --- a/apihub/result.py +++ b/apihub/result.py @@ -1,10 +1,8 @@ -import json - import redis from prometheus_client import Counter, Histogram from dotenv import load_dotenv -from pipeline import ProcessorSettings, Processor, Command, CommandActions +from pipeline import ProcessorSettings, Processor, Command, CommandActions, Definition from apihub.utils import Result, Status, RedisSettings, DEFINITION from apihub import __worker__, __version__ @@ -44,12 +42,17 @@ def setup(self) -> None: self.redis = redis.Redis.from_url(settings.redis) def process_command(self, command: Command) -> None: + self.logger.info("Processing COMMAND") if command.action == CommandActions.Define: - for k, v in command.content.items(): - self.redis.hset(DEFINITION, k, json.dumps(v)) - self.logger.info(f"{k} definition:\n{json.dumps(v, indent=2)}") + definition = Definition.parse_obj(command.content) + self.logger.info(definition) + self.redis.hset(DEFINITION, definition.source.topic, definition.json()) + self.logger.info( + f"{definition.source.topic} definition:\n{definition.json()}" + ) def process(self, message_content, message_id): + self.logger.info("Processing MESSAGE") result = Result.parse_obj(message_content) if result.status == Status.PROCESSED: result.result = { diff --git a/apihub/server.py b/apihub/server.py index 26e3e68..2cf7c60 100644 --- a/apihub/server.py +++ b/apihub/server.py @@ -1,5 +1,6 @@ import sys import functools +import logging from typing import Dict, Any from fastapi import FastAPI, HTTPException, Request, Query, Depends @@ -7,14 +8,15 @@ from pydantic import BaseModel, Field from fastapi_jwt_auth import AuthJWT from fastapi_jwt_auth.exceptions import AuthJWTException +from fastapi.openapi.utils import get_openapi from dotenv import load_dotenv -from pipeline import Message, Settings, Command, CommandActions, Monitor +from pipeline import Message, Settings, Command, CommandActions, Monitor, Definition from apihub_users.security.depends import RateLimiter, RateLimits, require_user from apihub_users.security.router import router as security_router from apihub_users.subscription.depends import require_subscription from apihub_users.subscription.router import router as application_router -from apihub.utils import State, make_topic, make_key, Result, Status +from apihub.utils import DEFINITION, State, make_topic, make_key, Result, Status from apihub import __worker__, __version__ @@ -30,7 +32,8 @@ @functools.lru_cache(maxsize=None) def get_state(): - return State() + logging.basicConfig(level=logging.DEBUG) + return State(logger=logging) def get_redis(): @@ -60,10 +63,12 @@ def jwt_get_config(): api.include_router( security_router, # prefix='/security', - # tags=['security'], + tags=["security"], dependencies=[Depends(ip_rate_limited)], ) -api.include_router(application_router, dependencies=[Depends(ip_rate_limited)]) +api.include_router( + application_router, tags=["subscription"], dependencies=[Depends(ip_rate_limited)] +) @api.exception_handler(AuthJWTException) @@ -91,6 +96,7 @@ async def root(): @api.get( "/define/{application}", + include_in_schema=False, dependencies=[Depends(ip_rate_limited)], ) async def define_service( @@ -101,9 +107,12 @@ async def define_service( get_state().write(make_topic(application), Command(action=CommandActions.Define)) + return {"define": f"application {application}"} + @api.post( "/async/{application}", + include_in_schema=False, response_model=AsyncAPIRequestResponse, dependencies=[Depends(ip_rate_limited)], ) @@ -144,7 +153,11 @@ async def async_service( return AsyncAPIRequestResponse(success=True, key=key) -@api.get("/async/{application}", dependencies=[Depends(ip_rate_limited)]) +@api.get( + "/async/{application}", + dependencies=[Depends(ip_rate_limited)], + include_in_schema=False, +) async def async_service_result( application: str, key: str = Query( @@ -194,13 +207,101 @@ async def async_service_result( ) -@api.post("/sync/{service_name}") +@api.post( + "/sync/{service_name}", + include_in_schema=False, +) async def sync_service(service_name: str): """generic synchronised api hendler""" # TODO synchronised service, basically it will wait and return results # when it is ready. It will have a timeout of 30 seconds +def get_paths(redis=get_redis()): + paths = {} + for name, dct_str in redis.hgetall(DEFINITION).items(): + name = name.decode("utf-8") + path = {} + definition = Definition.parse_raw(dct_str) + operation = {} + operation["tags"] = ["app"] + operation["summary"] = definition.description + operation["description"] = definition.description + parameters = {} + operation["requestBody"] = { + "content": { + "application/json": { + "schema": definition.input_schema, # ["properties"], + } + }, + "required": True, + } + operation["responses"] = { + "200": { + "description": "successful request", + "status_code": 200, + "content": { + "application/json": {"schema": AsyncAPIRequestResponse.schema()} + }, + } + } + path["post"] = operation + + operation = {} + operation["tags"] = ["app"] + operation["summary"] = "obtain results from previous post requests" + operation["description"] = definition.description + parameters = [ + { + "name": "key", + "in": "query", + "description": "the unique key obtained from post request", + "required": True, + "type": "string", + "format": "string", + } + ] + # a strange way to sort parameters maybe + operation["parameters"] = list( + {param["name"]: param for param in parameters}.values() + ) + operation["responses"] = { + "200": { + "description": "success", + "content": { + "application/json": { + "schema": definition.output_schema, + } + }, + } + } + path["get"] = operation + + paths[f"/async/{name}"] = path + return paths + + +def custom_openapi(app=api): + # if app.openapi_schema: + # return app.openapi_schema + + openapi_schema = get_openapi( + title="APIHub", + version="0.1.0", + description="API for AI", + routes=app.routes, + ) + openapi_schema["info"]["x-logo"] = { + "url": "https://raw.githubusercontent.com/yifan/apihub/master/images/APIHub-logo.png" + } + openapi_schema["paths"].update(get_paths()) + app.openapi_schema = openapi_schema + return app.openapi_schema + + +api.openapi = custom_openapi + + class ServerSettings(Settings): port: int = 5000 log_level: str = "debug" diff --git a/apihub/utils.py b/apihub/utils.py index b406510..888d722 100644 --- a/apihub/utils.py +++ b/apihub/utils.py @@ -30,8 +30,8 @@ class RedisSettings(Settings): class State: - def __init__(self): - self.pipeline = Pipeline() + def __init__(self, logger): + self.pipeline = Pipeline(logger=logger) settings = RedisSettings() settings.parse_args(args=[]) self.redis = redis.Redis.from_url(settings.redis) @@ -49,4 +49,4 @@ def make_key(): def make_topic(service_name: str): - return f"api-{service_name}" + return service_name diff --git a/images/APIHub-logo.png b/images/APIHub-logo.png new file mode 100644 index 0000000..b39d764 Binary files /dev/null and b/images/APIHub-logo.png differ diff --git a/poetry.lock b/poetry.lock index b49e06a..5c4577b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "apihub-users" -version = "0.1.1-alpha.1" +version = "0.1.1-alpha.5" description = "user and subscription management for APIHub" category = "main" optional = false @@ -21,8 +21,8 @@ uvicorn = "^0.13.4" [package.source] type = "git" url = "https://github.com/yifan/apihub-users" -reference = "master" -resolved_reference = "2f0995453f1038bc3802fd04e1c8bf76a9f00145" +reference = "develop" +resolved_reference = "0e103098cf2d4fee3113c6108b07d9387e08de4e" [[package]] name = "appdirs" @@ -54,6 +54,30 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "black" +version = "21.6b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +appdirs = "*" +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.8.1,<1" +regex = ">=2020.1.8" +toml = ">=0.10.1" +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + [[package]] name = "certifi" version = "2021.5.30" @@ -224,7 +248,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "4.5.0" +version = "4.6.0" description = "Read metadata from Python packages" category = "main" optional = false @@ -236,7 +260,8 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "more-itertools" @@ -289,9 +314,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "pathspec" +version = "0.8.1" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + [[package]] name = "pipeline" -version = "0.11.9" +version = "0.11.16" description = "data streaming on top of popular message queues" category = "main" optional = false @@ -314,7 +347,7 @@ pulsar = ["pulsar-client (>=2.5.0,<2.6.0)"] type = "git" url = "https://github.com/yifan/pipeline" reference = "develop" -resolved_reference = "191e3aec75ed5005b83b7da0348e4318002f3f4b" +resolved_reference = "9ec050a25a07807e03eb55189792892d4dcd4fc8" [[package]] name = "pluggy" @@ -520,6 +553,14 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] hiredis = ["hiredis (>=0.1.3)"] +[[package]] +name = "regex" +version = "2021.7.1" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + [[package]] name = "requests" version = "2.25.1" @@ -548,7 +589,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sqlalchemy" -version = "1.4.19" +version = "1.4.20" description = "Database Abstraction Library" category = "main" optional = false @@ -580,7 +621,7 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "sqlalchemy-utils" -version = "0.37.7" +version = "0.37.8" description = "Various utility functions for SQLAlchemy." category = "main" optional = false @@ -600,8 +641,8 @@ intervals = ["intervals (>=0.7.1)"] password = ["passlib (>=1.6,<2.0)"] pendulum = ["pendulum (>=2.0.5)"] phone = ["phonenumbers (>=5.9.2)"] -test = ["pytest (>=2.7.1)", "Pygments (>=1.2)", "Jinja2 (>=2.3)", "docutils (>=0.10)", "flexmock (>=0.9.7)", "mock (==2.0.0)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pg8000 (>=1.12.4)", "pytz (>=2014.2)", "python-dateutil (>=2.6)", "pymysql", "flake8 (>=2.4.0)", "isort (>=4.2.2)", "pyodbc"] -test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "anyjson (>=0.3.3)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"] +test = ["pytest (>=2.7.1)", "Pygments (>=1.2)", "Jinja2 (>=2.3)", "docutils (>=0.10)", "flexmock (>=0.9.7)", "mock (==2.0.0)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pg8000 (>=1.12.4)", "pytz (>=2014.2)", "python-dateutil (>=2.6)", "pymysql", "flake8 (>=2.4.0)", "isort (>=4.2.2)", "pyodbc", "backports.zoneinfo"] +test_all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "anyjson (>=0.3.3)", "arrow (>=0.3.4)", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "mock (==2.0.0)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (>=2.7.1)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)", "backports.zoneinfo"] timezone = ["python-dateutil"] url = ["furl (>=0.4.1)"] @@ -650,7 +691,7 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.5" +version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "dev" optional = false @@ -733,7 +774,7 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "443daa3b628e392109c343015bd2ec5cb1ffb0823fa4664fc16950e1b57fdf90" +content-hash = "a137b5fb25218585d068a77ea577d9def8be04e18927b2183687de18f85367af" [metadata.files] apihub-users = [] @@ -749,6 +790,10 @@ attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +black = [ + {file = "black-21.6b0-py3-none-any.whl", hash = "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7"}, + {file = "black-21.6b0.tar.gz", hash = "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04"}, +] certifi = [ {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, @@ -908,8 +953,8 @@ idna = [ {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.5.0-py3-none-any.whl", hash = "sha256:833b26fb89d5de469b24a390e9df088d4e52e4ba33b01dc5e0e4f41b81a16c00"}, - {file = "importlib_metadata-4.5.0.tar.gz", hash = "sha256:b142cc1dd1342f31ff04bb7d022492b09920cb64fed867cd3ea6f80fe3ebd139"}, + {file = "importlib_metadata-4.6.0-py3-none-any.whl", hash = "sha256:c6513572926a96458f8c8f725bf0e00108fba0c9583ade9bd15b869c9d726e33"}, + {file = "importlib_metadata-4.6.0.tar.gz", hash = "sha256:4a5611fea3768d3d967c447ab4e93f567d95db92225b43b7b238dbfb855d70bb"}, ] more-itertools = [ {file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"}, @@ -951,6 +996,10 @@ packaging = [ {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, ] +pathspec = [ + {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, + {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"}, +] pipeline = [] pluggy = [ {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, @@ -1092,6 +1141,45 @@ redis = [ {file = "redis-3.5.3-py2.py3-none-any.whl", hash = "sha256:432b788c4530cfe16d8d943a09d40ca6c16149727e4afe8c2c9d5580c59d9f24"}, {file = "redis-3.5.3.tar.gz", hash = "sha256:0e7e0cfca8660dea8b7d5cd8c4f6c5e29e11f31158c0b0ae91a397f00e5a05a2"}, ] +regex = [ + {file = "regex-2021.7.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:494d0172774dc0beeea984b94c95389143db029575f7ca908edd74469321ea99"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:8cf6728f89b071bd3ab37cb8a0e306f4de897553a0ed07442015ee65fbf53d62"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1806370b2bef4d4193eebe8ee59a9fd7547836a34917b7badbe6561a8594d9cb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:d0cf2651a8804f6325747c7e55e3be0f90ee2848e25d6b817aa2728d263f9abb"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:268fe9dd1deb4a30c8593cabd63f7a241dfdc5bd9dd0233906c718db22cdd49a"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:7743798dfb573d006f1143d745bf17efad39775a5190b347da5d83079646be56"}, + {file = "regex-2021.7.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:0e46c1191b2eb293a6912269ed08b4512e7e241bbf591f97e527492e04c77e93"}, + {file = "regex-2021.7.1-cp36-cp36m-win32.whl", hash = "sha256:b1dbeef938281f240347d50f28ae53c4b046a23389cd1fc4acec5ea0eae646a1"}, + {file = "regex-2021.7.1-cp36-cp36m-win_amd64.whl", hash = "sha256:6c72ebb72e64e9bd195cb35a9b9bbfb955fd953b295255b8ae3e4ad4a146b615"}, + {file = "regex-2021.7.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf819c5b77ff44accc9a24e31f1f7ceaaf6c960816913ed3ef8443b9d20d81b6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:e80d2851109e56420b71f9702ad1646e2f0364528adbf6af85527bc61e49f394"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a1b6a3f600d6aff97e3f28c34192c9ed93fee293bd96ef327b64adb51a74b2f6"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:ed77b97896312bc2deafe137ca2626e8b63808f5bedb944f73665c68093688a7"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a548bb51c4476332ce4139df8e637386730f79a92652a907d12c696b6252b64d"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:210c359e6ee5b83f7d8c529ba3c75ba405481d50f35a420609b0db827e2e3bb5"}, + {file = "regex-2021.7.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:1d386402ae7f3c9b107ae5863f7ecccb0167762c82a687ae6526b040feaa5ac6"}, + {file = "regex-2021.7.1-cp37-cp37m-win32.whl", hash = "sha256:5049d00dbb78f9d166d1c704e93934d42cce0570842bb1a61695123d6b01de09"}, + {file = "regex-2021.7.1-cp37-cp37m-win_amd64.whl", hash = "sha256:361be4d311ac995a8c7ad577025a3ae3a538531b1f2cf32efd8b7e5d33a13e5a"}, + {file = "regex-2021.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f32f47fb22c988c0b35756024b61d156e5c4011cb8004aa53d93b03323c45657"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:b024ee43ee6b310fad5acaee23e6485b21468718cb792a9d1693eecacc3f0b7e"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b092754c06852e8a8b022004aff56c24b06310189186805800d09313c37ce1f8"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:a8a5826d8a1b64e2ff9af488cc179e1a4d0f144d11ce486a9f34ea38ccedf4ef"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:444723ebaeb7fa8125f29c01a31101a3854ac3de293e317944022ae5effa53a4"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:fdad3122b69cdabdb3da4c2a4107875913ac78dab0117fc73f988ad589c66b66"}, + {file = "regex-2021.7.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4b1999ef60c45357598935c12508abf56edbbb9c380df6f336de38a6c3a294ae"}, + {file = "regex-2021.7.1-cp38-cp38-win32.whl", hash = "sha256:e07e92935040c67f49571779d115ecb3e727016d42fb36ee0d8757db4ca12ee0"}, + {file = "regex-2021.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:6b8b629f93246e507287ee07e26744beaffb4c56ed520576deac8b615bd76012"}, + {file = "regex-2021.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56bef6b414949e2c9acf96cb5d78de8b529c7b99752619494e78dc76f99fd005"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:78a2a885345a2d60b5e68099e877757d5ed12e46ba1e87507175f14f80892af3"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3f7a92e60930f8fca2623d9e326c173b7cf2c8b7e4fdcf984b75a1d2fb08114d"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4fc86b729ab88fe8ac3ec92287df253c64aa71560d76da5acd8a2e245839c629"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:59845101de68fd5d3a1145df9ea022e85ecd1b49300ea68307ad4302320f6f61"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ce269e903b00d1ab4746793e9c50a57eec5d5388681abef074d7b9a65748fca5"}, + {file = "regex-2021.7.1-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:c11f2fca544b5e30a0e813023196a63b1cb9869106ef9a26e9dae28bce3e4e26"}, + {file = "regex-2021.7.1-cp39-cp39-win32.whl", hash = "sha256:1ccbd41dbee3a31e18938096510b7d4ee53aa9fce2ee3dcc8ec82ae264f6acfd"}, + {file = "regex-2021.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:18040755606b0c21281493ec309214bd61e41a170509e5014f41d6a5a586e161"}, + {file = "regex-2021.7.1.tar.gz", hash = "sha256:849802379a660206277675aa5a5c327f5c910c690649535863ddf329b0ba8c87"}, +] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"}, @@ -1101,40 +1189,40 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sqlalchemy = [ - {file = "SQLAlchemy-1.4.19-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:ddbce8fe4d0190db21db602e38aaf4c158c540b49f1ef7475323ec682a9fbf2d"}, - {file = "SQLAlchemy-1.4.19-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:942ca49b7ec7449d2473a6587825c55ad99534ddfc4eee249dd42be3cc1aa8c9"}, - {file = "SQLAlchemy-1.4.19-cp27-cp27m-win32.whl", hash = "sha256:9c0945c79cbe507b49524e31a4bb8700060bbccb60bb553df6432e176baff3d5"}, - {file = "SQLAlchemy-1.4.19-cp27-cp27m-win_amd64.whl", hash = "sha256:6fd1b745ade2020a1a7bf1e22536d8afe86287882c81ca5d860bdf231d5854e9"}, - {file = "SQLAlchemy-1.4.19-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0fb3f73e5009f5a4c9b24469939d3d57cc3ad8099a09c0cfefc47fe45ab7ffbe"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:64eab458619ef759f16f0f82242813d3289e829f8557fbc7c212ca4eadf96472"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:311051c06f905774427b4a92dcb3924d6ee563dea3a88176da02fdfc572d0d1d"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a34a7fd3353ee61a1dca72fc0c3e38d4e56bdc2c343e712f60a8c70acd4ef5bf"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ace9ab2af9d7d7b0e2ff2178809941c56ab8921e38128278192a73a8a1c08a2"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-win32.whl", hash = "sha256:96d3d4a7ead376d738775a1fa9786dc17a31975ec664cea284e53735c79a5686"}, - {file = "SQLAlchemy-1.4.19-cp36-cp36m-win_amd64.whl", hash = "sha256:20f4bf1459548a74aade997cb045015e4d72f0fde1789b09b3bb380be28f6511"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:8cba69545246d16c6d2a12ce45865947cbdd814bacddf2e532fdd4512e70728c"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57ba8a96b6d058c7dcf44de8ac0955b7a787f7177a0221dd4b8016e0191268f5"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8f1e7f4de05c15d6b46af12f3cf0c2552f2940d201a49926703249a62402d851"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c92d9ebf4b38c22c0c9e4f203a80e101910a50dc555b4578816932015b97d7f"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-win32.whl", hash = "sha256:c6efc7477551ba9ce632d5c3b448b7de0277c86005eec190a1068fcc7115fd0e"}, - {file = "SQLAlchemy-1.4.19-cp37-cp37m-win_amd64.whl", hash = "sha256:e2761b925fda550debfd5a8bc3cef9debc9a23c6a280429c4ec3a07c35c6b4b3"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:58d4f79d119010fdced6e7fd7e4b9f2230dbf55a8235d7c58b1c8207ef74791b"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cefd44faca7c57534503261f6fab49bd47eb9c2945ee0bab09faaa8cb047c24f"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9133635edcec1e7fbfc16eba5dc2b5b3b11818d25b7a57cfcbfa8d3b3e9594fd"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3cf5f543d048a7c8da500133068c5c90c97a2c4bf0c027928a85028a519f33d"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-win32.whl", hash = "sha256:d04160462f874eaa4d88721a0d5ecca8ebf433616801efe779f252ef87b0e216"}, - {file = "SQLAlchemy-1.4.19-cp38-cp38-win_amd64.whl", hash = "sha256:45b0f773e195d8d51e2fd67cb5b5fb32f5a1f5e7f0752016207091bed108909a"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:93ba458b3c279581288a10a55df2aa6ac3509882228fcbad9d9d88069f899337"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6317701c06a829b066c794545512bb70b1a10a74574cfa5658a0aaf49f31aa93"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:95a9fd0a11f89a80d8815418eccba034f3fec8ea1f04c41b6b8decc5c95852e9"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9014fd1d8aebcb4eb6bc69a382dd149200e1d5924412b1d08b4443f6c1ce526f"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-win32.whl", hash = "sha256:fa05a77662c23226c9ec031638fd90ae767009e05cd092b948740f09d10645f0"}, - {file = "SQLAlchemy-1.4.19-cp39-cp39-win_amd64.whl", hash = "sha256:d7b21a4b62921cf6dca97e8f9dea1fbe2432aebbb09895a2bd4f527105af41a4"}, - {file = "SQLAlchemy-1.4.19.tar.gz", hash = "sha256:89a5a13dcf33b7e47c7a9404a297c836965a247c7f076a0fe0910cae2bee5ce2"}, + {file = "SQLAlchemy-1.4.20-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:525dd3c2205b11a2bc6d770bf1ec63bde0253fd754b4c19c399d27ddc9dad0d3"}, + {file = "SQLAlchemy-1.4.20-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4a67371752fd86d1d03a3b82d4e75404608f6f4d579b9676124079a22a40c79f"}, + {file = "SQLAlchemy-1.4.20-cp27-cp27m-win32.whl", hash = "sha256:7150e5b543b466f45f668b352f7abda27998cc8035f051d1b7e9524ca9eb2f5f"}, + {file = "SQLAlchemy-1.4.20-cp27-cp27m-win_amd64.whl", hash = "sha256:6da83225a23eaf7b3f48f3d5f53c91b2cf00fbfa48b24a7a758160112dd3e123"}, + {file = "SQLAlchemy-1.4.20-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9841762d114018c49483c089fa2d47f7e612e57666323f615913d7d7f46e9606"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:eaee5dd378f6f0d7c3ec49aeeb26564d55ac0ad73b9b4688bf29e66deabddf73"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb25bcf9161e2fcbe9eebe8e829719b2334e849183f0e496bf4b83722bcccfa"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8d860c62e3f51623ccd528d8fac44580501df557d4b467cc5581587fcf057719"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f6d467b67a7e5048f1408e8ea60d6caa70be5b386d0eebbf1185ab49cb8c7e4"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-win32.whl", hash = "sha256:ff8bebc7a9d297dff2003460e01db2c20c63818b45fb19170f388b1a72fe5a14"}, + {file = "SQLAlchemy-1.4.20-cp36-cp36m-win_amd64.whl", hash = "sha256:46361690f1e1c5385994a4caeb6e8126063ff593a5c635700bbc1245de793c1e"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:c0eb2cd3ad4967fcbdd9e066e8cd91fe2c23c671dbae9952f0b4d3d42832cc5f"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76fbc24311a3d039d6cd147d396719f606d96d1413f3816c028a48e29367f646"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f14acb0fd16d404fda9370f93aace682f284340c89c3442ac747c5466ac7e2b5"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcd84e4d46a86291495d131a7824ba38d2e8278bda9425c50661a04633174319"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-win32.whl", hash = "sha256:2f60a2e599cf5cf5e5327ce60f2918b897e42ad9f405d10dd01e37869c0ce6fc"}, + {file = "SQLAlchemy-1.4.20-cp37-cp37m-win_amd64.whl", hash = "sha256:f6fc526bd70898489d02bf52c8f0632ab377592ae954d0c0a5bb38d618dddaa9"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:25c0e0f3a7e8c19350086b3c0fe93c4def045cec053d749ef15da710c4d54c81"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d48456e1aa4f0537f9c9af7be71e1f0659ff68bc1cd538ebc785f6b007bd0d"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9675d5bc7e4f96a7bb2b54d14e9b269a5fb6e5d36ecc7d01f0f65bb9af3185f9"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b502b5e2f08500cc4b8d29bfc4f51d805adcbc00f8d149e98fda8aae85ddb644"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-win32.whl", hash = "sha256:aad3234a41340e9cf6184e621694e2a7233ba3f8aef9b1e6de8cba431b45ebd2"}, + {file = "SQLAlchemy-1.4.20-cp38-cp38-win_amd64.whl", hash = "sha256:6c8406c3d8c1c7d15da454de15d77f7bb48d14ede5db994f74226c348cf1050e"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:238d78b3110b7f7cffdb70bf9cda686e0d876a849bc78ba4d471aa7b1461f306"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:854a7b15750e617e16f8d65dbc004f065a7963544b253b923f16109557648777"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ff38ecf89c69a531a7326c2dae71982edfe2f805f3c016cdc5bfd1a04ebf80cb"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86c079732328f1add097b0b8079cd532b5d28e207fac93e9d6ea5f487506deef"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-win32.whl", hash = "sha256:46b99eab618cdc1c871ea707b7c52edc23cfea6c750740cd242ba62b5c84de7f"}, + {file = "SQLAlchemy-1.4.20-cp39-cp39-win_amd64.whl", hash = "sha256:b86d83fefc8a8c394f3490c37e1953bc16c311a3d1d1cf91518793bfb9847fb4"}, + {file = "SQLAlchemy-1.4.20.tar.gz", hash = "sha256:38ee3a266afef2978e82824650457f70c5d74ec0cadec1b10fe5ed6f038eb5d0"}, ] sqlalchemy-utils = [ - {file = "SQLAlchemy-Utils-0.37.7.tar.gz", hash = "sha256:716d9d9592258db9651a511d03e6b2553242c2a440855ee3f7d5812bbb55d9eb"}, - {file = "SQLAlchemy_Utils-0.37.7-py3-none-any.whl", hash = "sha256:afd204ed051f53302cd8789cc29c9b15bf458f8baef14a9052bf2823f855d2cb"}, + {file = "SQLAlchemy-Utils-0.37.8.tar.gz", hash = "sha256:a6aaee154f798be4e479af0ceffaa5034d35fcf6f40707c0947d21bde64e05e5"}, + {file = "SQLAlchemy_Utils-0.37.8-py3-none-any.whl", hash = "sha256:b1bf67d904fed16b16ef1dc07f03e5e93a6b23899f920f6b41c09be45fbb85f2"}, ] starlette = [ {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, @@ -1186,8 +1274,8 @@ typing-extensions = [ {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] urllib3 = [ - {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"}, - {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"}, + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, ] uvicorn = [ {file = "uvicorn-0.13.4-py3-none-any.whl", hash = "sha256:7587f7b08bd1efd2b9bad809a3d333e972f1d11af8a5e52a9371ee3a5de71524"}, diff --git a/pyproject.toml b/pyproject.toml index 424cdac..b869ac0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,7 +52,7 @@ psycopg2-binary = "^2.8.6" SQLAlchemy = "^1.4.15" SQLAlchemy-Utils = "^0.37.4" python-multipart = "^0.0.5" -apihub-users = {git = "https://github.com/yifan/apihub-users"} +apihub-users = {git = "https://github.com/yifan/apihub-users", rev = "develop"} pipeline = {git = "https://github.com/yifan/pipeline", rev = "develop", extras = ["redis"]} [tool.poetry.dev-dependencies] @@ -64,6 +64,7 @@ factory-boy = "^3.2.0" requests = "^2.25.1" mypy = "^0.812" python-dotenv = {extras = ["cli"], version = "^0.17.1"} +black = {version = "^21.6b0", allow-prereleases = true} [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/fixtures/result_input.txt b/tests/fixtures/result_input.txt index 8a67bcd..7c6e3c7 100644 --- a/tests/fixtures/result_input.txt +++ b/tests/fixtures/result_input.txt @@ -1,2 +1,3 @@ {"kind": "MESG", "id": "ab7fe542-bdf2-11eb-b401-f21898b454f0", "created": "2021-05-26T10:19:11.878161", "logs": [], "content": {"user": "user", "api": "test", "status": "accepted", "submission_time": "2021-05-26T07:19:11.926576"}} {"kind": "MESG", "id": "ab7fe542-bdf2-11eb-b401-f21898b454f0", "created": "2021-05-26T10:19:11.878161", "logs": [{"name": "mediaframeworker", "version": "0.5.0", "updated": ["generalframe"], "received": "2021-05-26T12:13:54.953091", "processed": "2021-05-26T12:13:54.954349", "elapsed": 0.0013907699999999856}], "content": {"text": "this is simple", "user": "user", "api": "test", "status": "processed", "submission_time": "2021-05-26T07:19:11.926576", "generalframe": "Cultural-identity"}} +{"kind": "COMD", "id": "2cae5cbeda8d11eb959ff21898b454f0", "created": "2021-07-01T19:55:43.980102", "logs": [{"name": "mediaframeworker", "version": "0.5.0", "updated": ["source", "name", "input_schema", "version", "output_schema", "destination", "description"], "received": "2021-07-01T19:55:44.107834", "processed": "2021-07-01T19:55:44.109527", "elapsed": 0.0018327369999999732}], "content": {"name": "mediaframeworker", "version": "0.5.0", "description": "predict the frame of reporting for news articles", "source": {"namespace": null, "topic": "in-topic", "timeout": 0, "filename": "fixtures/articles.json", "content_only": false}, "destination": {"namespace": null, "topic": "out-topic", "compress": false, "filename": "-", "overwrite": false, "content_only": false}, "input_schema": {"title": "Input", "type": "object", "properties": {"text": {"title": "article text", "description": "article text in a single string", "minLength": 1, "type": "string"}}, "required": ["text"]}, "output_schema": {"title": "Output", "type": "object", "properties": {"generalframe": {"title": "predicted frame", "type": "string"}}, "required": ["generalframe"]}}, "action": "DEFINE"}