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 @@
-
+
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"}