[release][0.1.0] First HalfAPI release
Squashed commit of the following: commit 68032dc55a07565ccd17a188407d9ac2537b62e6 Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 15:40:26 2020 +0200 [release][0.1.0] First HalfAPI release commit a046a81114a3ae22bbc84a53f1e85217a0954dbc Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 15:26:15 2020 +0200 [doc] màj du readme commit ed45b3011125c071aa53df8087d28bfa1150b373 Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 11:03:17 2020 +0200 [wip] rm apidb commit 7df4b9bacf3d26f09ea07856587505f74284cab4 Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 10:58:46 2020 +0200 [db] forgot foreign key router->domain commit 604b9a90f405121725e4b2126d73a5a83eec398f Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 10:51:01 2020 +0200 [wip] routes mounting fixed commit c50a5572633d7dcc3cad48ef79c5ea1ca098284d Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Thu Jul 23 10:29:09 2020 +0200 [wip][db][nf] http_verb, fct_name are in api.route commit 2b5b78db2f9c280dd5eb9d8bafc9174d9afc092f Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Wed Jul 22 17:37:21 2020 +0200 [wip] refactor du 22 juillet 2222 commit d019b7e333ab37f106895c84521cef1bfe768caa Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Wed Jul 22 14:48:51 2020 +0200 [wip] remove "version" from app commit 98ccd61dcf369b8c4aac817a0c8409b6fed00f50 Author: Joël Maïzi <joel.maizi@lirmm.fr> Date: Wed Jul 22 14:45:28 2020 +0200 Remove api.version from database. commit aa0d4f8dbba8b8ec878835bb58b69facff7e675e Author: Maxime Alves LIRMM@home <maxime.alves@lirmm.fr> Date: Tue Jul 21 21:46:22 2020 +0200 [db] added router as api.acl primary_key part commit a97984e9de0e6a00bddca7dece0c715c9c16cbe1 Author: Maxime Alves LIRMM@home <maxime.alves@lirmm.fr> Date: Tue Jul 21 21:41:31 2020 +0200 [wip] moved all acl treatment to acl_caller_middleware, fix route mounting, fix typo in logs commit 3dd310e80aaf6cb32f6c4ac23c1e2a924cebfde1 Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 13:10:26 2020 +0200 [wip][nf] gestion des routes avec routers commit c2687c4a24126fbc3e57257bf23c267b334df522 Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 12:39:53 2020 +0200 [db] ajout de la table api.router commit 9a10f76cf7790f75f23b72e19b0a58978752565c Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 12:19:53 2020 +0200 [db] renommage des champs d'acl commit c4e8c26a24835559d2e9b251df0eb462fe7e667d Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 12:13:38 2020 +0200 [wip][nf] modification du systeme de montage des routes commit b7e8352ba1e427e9883797a44bb0f3da5edd576d Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 11:15:30 2020 +0200 [wip][dbupdate] insertion des routes au nouveau format commit 28947444c4c062e6ced74f9bfdef11a36ddc438b Author: Maxime Alves LIRMM <maxime.alves@lirmm.fr> Date: Tue Jul 21 10:32:57 2020 +0200 [wip][dbupdate] Suppression des routes hors domaine
This commit is contained in:
parent
5d9f4631be
commit
0282da6e3d
|
@ -0,0 +1,8 @@
|
||||||
|
# HalfAPI
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
|
||||||
|
- Mounts domain routers with their ACLs as decorator
|
||||||
|
- Configuration example files for systemd and a system-wide halfapi install
|
||||||
|
- Runs projects
|
||||||
|
- Handles JWT authentication middleware
|
|
@ -0,0 +1,14 @@
|
||||||
|
Copyright (c) 2015-2020 Joël Maïzi <joel.maizi@collorg.org>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
28
README.md
28
README.md
|
@ -1,7 +1,6 @@
|
||||||
# HalfAPI
|
# HalfAPI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
This Python-based ASGI application aims to provide the core functionality to
|
This Python-based ASGI application aims to provide the core functionality to
|
||||||
multiple API domains.
|
multiple API domains.
|
||||||
|
|
||||||
|
@ -13,33 +12,27 @@ The name "halfAPI" comes from the deep relationship between it and
|
||||||
|
|
||||||
You'll need a database with the API details. You can find the database model in halfapi/models/api.sql
|
You'll need a database with the API details. You can find the database model in halfapi/models/api.sql
|
||||||
|
|
||||||
With halfORM's "hop" command, we generate the models that describe the database from the database schema itself. You can find the details in [hop_api](https://gite.lirmm.fr/newsi/db/hop_api) repository.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**NOTE : The authentication module is deeply linked with [auth_lirmm](https://gite.lirmm.fr/newsi/auth_lirmm), so if you need to use the acl.connected function, you will need a running auth_lirmm server to get a token.**
|
**NOTE : The authentication module is deeply linked with [auth_lirmm](https://gite.lirmm.fr/newsi/auth_lirmm), so if you need to use the acl.connected function, you will need a running auth_lirmm server to get a token.**
|
||||||
|
|
||||||
**TODO :** include a token generation tool for testing purpose.
|
**TODO :** include a token generation tool for testing purpose.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- python3
|
- python3
|
||||||
- python3-pip
|
- python3-pip
|
||||||
- python3-virtualenv
|
|
||||||
- python3-venv
|
|
||||||
|
|
||||||
|
|
||||||
### pip
|
|
||||||
|
|
||||||
- poetry
|
- poetry
|
||||||
|
- uvicorn
|
||||||
|
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
As the project uses the [poetry]() package manager, you first have to install it globally. It will replace virtualenv, pip, etc...
|
`pip install .`
|
||||||
|
|
||||||
|
As the project uses the [poetry]() package manager, you first have to install it
|
||||||
|
for the current user. Be sur to have pip binary directory ($HOME/.local/bin)
|
||||||
|
included in your PATH.
|
||||||
|
|
||||||
|
|
||||||
`pip3 install poetry`
|
`pip3 install poetry`
|
||||||
|
@ -47,15 +40,6 @@ As the project uses the [poetry]() package manager, you first have to install it
|
||||||
|
|
||||||
Be sur to include the bin directory of pip in your PATH.
|
Be sur to include the bin directory of pip in your PATH.
|
||||||
|
|
||||||
### Virtual Environment (optional)
|
|
||||||
Then, cd in the halfapi repo, and chose your python version :
|
|
||||||
|
|
||||||
|
|
||||||
`POETRY_VIRTUALENVS_PATH=$HOME/.pyvenv poetry env use 3.7`
|
|
||||||
|
|
||||||
|
|
||||||
**NOTE : The virtualenv will be automatically be activated each time you run a command with the `poetry` tool. If you want to do it the classical way, or even without virtual environment, it's up to your choice.**
|
|
||||||
|
|
||||||
|
|
||||||
Installation of the deps :
|
Installation of the deps :
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
GUNICORN_CMD_ARGS="--daemon \
|
||||||
|
--bind unix:/var/lib/halfapi/example_api.sock \
|
||||||
|
--max-requests 200 \
|
||||||
|
--max-requests-jitter 20 \
|
||||||
|
--workers 4 \
|
||||||
|
--log-syslog-facility daemon \
|
||||||
|
--worker-class uvicorn.workers.UvicornWorker
|
||||||
|
|
||||||
|
HALFORM_CONF_DIR=/etc/half_orm
|
||||||
|
HALFAPI_CONF_DIR=/etc/half_api
|
|
@ -0,0 +1,19 @@
|
||||||
|
[Unit]
|
||||||
|
Description=HalfAPI - Project : Example API Service
|
||||||
|
Requires=halfapi_example_api.socket
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=halfapi
|
||||||
|
Group=halfapi
|
||||||
|
WorkingDirectory=/var/lib/halfapi/example_api
|
||||||
|
EnvironmentFile=/etc/default/gunicorn/halfapi_example_api
|
||||||
|
ExecStart=/usr/bin/env gunicorn halfapi
|
||||||
|
ExecReload=/bin/kill -s HUP $MAINPID
|
||||||
|
KillMode=mixed
|
||||||
|
TimeoutStopSec=5
|
||||||
|
PrivateTmp=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -1,10 +1,10 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=uvicorn socket
|
Description=HalfAPI - Project : Example API Socket
|
||||||
|
|
||||||
[Socket]
|
[Socket]
|
||||||
ListenStream=/var/lib/api/lirmm_api.sock
|
ListenStream=/var/lib/halfapi/example_api.sock
|
||||||
User=api
|
User=halfapi
|
||||||
SocketUser=api
|
SocketUser=halfapi
|
||||||
SocketGroup=www-data
|
SocketGroup=www-data
|
||||||
# Optionally restrict the socket permissions even more.
|
# Optionally restrict the socket permissions even more.
|
||||||
# Mode=600
|
# Mode=600
|
|
@ -1,26 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=LIRMM API daemon
|
|
||||||
Requires=lirmm_api.socket
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
# the specific user that our service will run as
|
|
||||||
User=api
|
|
||||||
Group=www-data
|
|
||||||
# another option for an even more restricted service is
|
|
||||||
# DynamicUser=yes
|
|
||||||
# see http://0pointer.net/blog/dynamic-users-with-systemd.html
|
|
||||||
RuntimeDirectory=api
|
|
||||||
WorkingDirectory=/var/lib/api/halfapi
|
|
||||||
EnvironmentFile=/var/lib/api/halfapi/conf/env.merles-dev
|
|
||||||
ExecStart=/var/lib/api/.pyvenv/halfapi-MLzQW5Lp-py3.7/bin/uvicorn \
|
|
||||||
--uds /var/lib/api/lirmm_api.sock \
|
|
||||||
halfapi.app:app
|
|
||||||
ExecReload=/bin/kill -s HUP $MAINPID
|
|
||||||
KillMode=mixed
|
|
||||||
TimeoutStopSec=5
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
|
@ -1 +1,48 @@
|
||||||
__version__ = '0.0.0'
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
from os import environ
|
||||||
|
from configparser import ConfigParser
|
||||||
|
|
||||||
|
__version__ = '0.1.0'
|
||||||
|
print(f'HalfAPI version:{__version__}')
|
||||||
|
|
||||||
|
config = ConfigParser(defaults={
|
||||||
|
'project': {
|
||||||
|
'host': '127.0.0.1',
|
||||||
|
'port': '8000',
|
||||||
|
'secret': None,
|
||||||
|
'base_dir': None,
|
||||||
|
'production': False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
config.read(filenames=['.halfapiconfig'])
|
||||||
|
PROJECT_NAME = config.get('project', 'name')
|
||||||
|
|
||||||
|
CONF_DIR = environ.get('HALFAPI_CONF_DIR', '/etc/halfapi')
|
||||||
|
|
||||||
|
config.read(filenames=[os.path.join(
|
||||||
|
CONF_DIR,
|
||||||
|
PROJECT_NAME
|
||||||
|
)])
|
||||||
|
|
||||||
|
HOST = config.get('project', 'host')
|
||||||
|
PORT = config.getint('project', 'port')
|
||||||
|
|
||||||
|
DB_NAME = f'halfapi_{PROJECT_NAME}'
|
||||||
|
with open(config.get('project', 'secret')) as secret_file:
|
||||||
|
SECRET = secret_file.read()
|
||||||
|
|
||||||
|
PRODUCTION = config.getboolean('project', 'production')
|
||||||
|
BASE_DIR = config.get('project', 'base_dir')
|
||||||
|
|
||||||
|
# DB
|
||||||
|
from half_orm.model import Model
|
||||||
|
db = Model(DB_NAME)
|
||||||
|
Domain = db.get_relation_class('api.domain')
|
||||||
|
APIRouter = db.get_relation_class('api.router')
|
||||||
|
APIRoute = db.get_relation_class('api.route')
|
||||||
|
AclFunction = db.get_relation_class('api.acl_function')
|
||||||
|
Acl = db.get_relation_class('api.acl')
|
||||||
|
RouteACL = db.get_relation_class('api.view.acl')
|
||||||
|
|
||||||
|
from halfapi.app import application
|
||||||
|
|
109
halfapi/app.py
109
halfapi/app.py
|
@ -1,108 +1,22 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# builtins
|
|
||||||
import importlib
|
|
||||||
import sys
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
# asgi framework
|
# asgi framework
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.authentication import UnauthenticatedUser
|
from starlette.authentication import UnauthenticatedUser
|
||||||
from starlette.middleware import Middleware
|
from starlette.middleware import Middleware
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.responses import Response, JSONResponse
|
from starlette.responses import Response, JSONResponse
|
||||||
from starlette.routing import Route
|
from starlette.routing import Route
|
||||||
from starlette.types import ASGIApp
|
|
||||||
from starlette.middleware.authentication import AuthenticationMiddleware
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
|
|
||||||
# typing
|
# typing
|
||||||
from typing import Any, Awaitable, Callable, MutableMapping
|
from typing import Any, Awaitable, Callable, MutableMapping
|
||||||
RequestResponseEndpoint = Callable[ [Request], Awaitable[Response] ]
|
|
||||||
|
|
||||||
# hop-generated classes
|
|
||||||
from .models.api.domain import Domain
|
|
||||||
|
|
||||||
# module libraries
|
# module libraries
|
||||||
from .config import CONFIG
|
from halfapi import HOST, PORT, DB_NAME, SECRET, PRODUCTION
|
||||||
from .lib.jwt_middleware import JWTAuthenticationBackend
|
|
||||||
from .lib.acl_caller_middleware import AclCallerMiddleware
|
|
||||||
|
|
||||||
from .lib.responses import *
|
from halfapi.lib.jwt_middleware import JWTAuthenticationBackend
|
||||||
|
|
||||||
|
from halfapi.lib.responses import *
|
||||||
def mount_domains(app: ASGIApp, domains: list):
|
from halfapi.lib.routes import get_routes
|
||||||
""" Procedure to mount the registered domains on their prefixes
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
|
|
||||||
- app (ASGIApp): The Starlette instance
|
|
||||||
- domains (list): The domains to mount, retrieved from the database
|
|
||||||
with their attributes "version", "name"
|
|
||||||
|
|
||||||
Returns: Nothing
|
|
||||||
"""
|
|
||||||
|
|
||||||
for domain in domains:
|
|
||||||
if 'name' not in domain.keys() or 'version' not in domain.keys():
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Retrieve domain app according to domain details
|
|
||||||
try:
|
|
||||||
print(f'Will import {domain["name"]}.app:app')
|
|
||||||
# @TODO 4-configuration
|
|
||||||
# Store domain-specific information in a configuration file
|
|
||||||
|
|
||||||
domain_mod = importlib.import_module(
|
|
||||||
f'{domain["name"]}.app')
|
|
||||||
domain_app = domain_mod.app
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
sys.stderr.write(
|
|
||||||
f'Could not find module *{domain["name"]}* in sys.path\n')
|
|
||||||
continue
|
|
||||||
except ImportError:
|
|
||||||
sys.stderr.write(f'Could not import *app* from *{domain}*')
|
|
||||||
continue
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f'Error in import *{domain["name"]}*\n')
|
|
||||||
print(e)
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
|
||||||
# Alter the openapi_url so the /docs page doesn't try to get
|
|
||||||
# /openapi.json (@TODO : report the bug to FastAPI)
|
|
||||||
domain_app.openapi_url = '/api/{version}/{name}/openapi.json'.format(**domain)
|
|
||||||
|
|
||||||
# Mount the domain app on the prefix
|
|
||||||
# e.g. : /v4/organigramme
|
|
||||||
try:
|
|
||||||
app.mount('/{version}/{name}'.format(**domain), app=domain_app)
|
|
||||||
except Exception as e:
|
|
||||||
print(f'Failed to mount *{domain}*\n')
|
|
||||||
|
|
||||||
|
|
||||||
def startup():
|
|
||||||
# This function is called at the instanciation of *app*
|
|
||||||
global app
|
|
||||||
|
|
||||||
# Mount the registered domains
|
|
||||||
try:
|
|
||||||
domains_list = [elt for elt in Domain().select()]
|
|
||||||
mount_domains(app, domains_list)
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write('Error in the *domains* retrieval\n')
|
|
||||||
raise e
|
|
||||||
|
|
||||||
if not CONFIG['HALFORM_SECRET']:
|
|
||||||
try:
|
|
||||||
CONFIG['HALFORM_SECRET'] = open('/etc/half_orm/secret').read()
|
|
||||||
print('Missing HALFORM_SECRET variable from configuration, \
|
|
||||||
read it from /etc/half_orm/secret')
|
|
||||||
except FileNotFoundError:
|
|
||||||
print('No HALFORM_SECRET variable set, and /etc/half_orm/secret \
|
|
||||||
inaccessible.')
|
|
||||||
sys.exit(1)
|
|
||||||
except PermissionError:
|
|
||||||
print("You don't have the right to read /etc/half_orm/secret")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
debug_routes = [
|
debug_routes = [
|
||||||
|
@ -113,22 +27,19 @@ debug_routes = [
|
||||||
else JSONResponse({'user':False})),
|
else JSONResponse({'user':False})),
|
||||||
Route('/payload', lambda request, *args, **kwargs:
|
Route('/payload', lambda request, *args, **kwargs:
|
||||||
JSONResponse({'payload':str(request.payload)}))
|
JSONResponse({'payload':str(request.payload)}))
|
||||||
] if CONFIG['DEBUG'] else []
|
] if not PRODUCTION else []
|
||||||
|
|
||||||
|
application = Starlette(
|
||||||
app = Starlette(
|
debug=not PRODUCTION,
|
||||||
debug=CONFIG['DEBUG'],
|
routes=debug_routes + get_routes(),
|
||||||
routes=debug_routes,
|
|
||||||
middleware=[
|
middleware=[
|
||||||
Middleware(AuthenticationMiddleware,
|
Middleware(AuthenticationMiddleware,
|
||||||
backend=JWTAuthenticationBackend(secret_key=CONFIG['HALFORM_SECRET'])),
|
backend=JWTAuthenticationBackend(secret_key=SECRET))
|
||||||
Middleware(AclCallerMiddleware),
|
|
||||||
],
|
],
|
||||||
exception_handlers={
|
exception_handlers={
|
||||||
401: UnauthorizedResponse,
|
401: UnauthorizedResponse,
|
||||||
404: NotFoundResponse,
|
404: NotFoundResponse,
|
||||||
500: InternalServerErrorResponse,
|
500: InternalServerErrorResponse,
|
||||||
501: NotImplementedResponse
|
501: NotImplementedResponse
|
||||||
},
|
}
|
||||||
on_startup=[startup],
|
|
||||||
)
|
)
|
||||||
|
|
208
halfapi/cli.py
208
halfapi/cli.py
|
@ -1,4 +1,12 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
from halfapi import (PROJECT_NAME, HOST, PORT,
|
||||||
|
PRODUCTION,
|
||||||
|
BASE_DIR,
|
||||||
|
Domain,
|
||||||
|
APIRouter,
|
||||||
|
APIRoute,
|
||||||
|
AclFunction,
|
||||||
|
Acl)
|
||||||
|
|
||||||
# builtins
|
# builtins
|
||||||
import click
|
import click
|
||||||
|
@ -6,22 +14,10 @@ import uvicorn
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import importlib
|
import importlib
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
# database
|
|
||||||
import psycopg2
|
|
||||||
|
|
||||||
# hop-generated classes
|
|
||||||
from apidb.api.version import Version
|
|
||||||
from apidb.api.domain import Domain
|
|
||||||
from apidb.api.route import Route
|
|
||||||
from apidb.api.acl_function import AclFunction
|
|
||||||
from apidb.api.acl import Acl
|
|
||||||
|
|
||||||
|
|
||||||
HALFORM_DSN=''
|
|
||||||
HALFORM_SECRET=''
|
|
||||||
CONTEXT_SETTINGS={
|
CONTEXT_SETTINGS={
|
||||||
'default_map':{'run': {'port': 8000}}
|
'default_map':{'run': {}}
|
||||||
}
|
}
|
||||||
|
|
||||||
@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
|
@click.group(invoke_without_command=True, context_settings=CONTEXT_SETTINGS)
|
||||||
|
@ -30,111 +26,53 @@ def cli(ctx):
|
||||||
if ctx.invoked_subcommand is None:
|
if ctx.invoked_subcommand is None:
|
||||||
return run()
|
return run()
|
||||||
|
|
||||||
@click.option('--envfile', default=None)
|
|
||||||
@click.option('--host', default='127.0.0.1')
|
|
||||||
@click.option('--port', default='8000')
|
|
||||||
@cli.command()
|
|
||||||
def run(envfile, host, port):
|
|
||||||
local_env = {}
|
|
||||||
if envfile:
|
|
||||||
try:
|
|
||||||
with open(envfile) as f:
|
|
||||||
click.echo('Will use the following env parameters :')
|
|
||||||
local_env = dict([ tuple(line.strip().split('=', 1))
|
|
||||||
for line in f.readlines() ])
|
|
||||||
click.echo(local_env)
|
|
||||||
except FileNotFoundError:
|
|
||||||
click.echo(f'No file named {envfile}')
|
|
||||||
envfile = None
|
|
||||||
|
|
||||||
if 'DEV' in local_env.keys():
|
@click.option('--host', default=HOST)
|
||||||
debug = True
|
@click.option('--port', default=PORT)
|
||||||
reload = True
|
@cli.command()
|
||||||
log_level = 'debug'
|
def run(host, port):
|
||||||
else:
|
debug = reload = not PRODUCTION
|
||||||
reload = False
|
log_level = 'info' if PRODUCTION else 'debug'
|
||||||
log_level = 'info'
|
|
||||||
|
|
||||||
click.echo('Launching application')
|
click.echo('Launching application')
|
||||||
|
|
||||||
sys.path.insert(0, os.getcwd())
|
sys.path.insert(0, BASE_DIR)
|
||||||
click.echo(f'current python_path : {sys.path}')
|
click.echo(f'current python_path : {sys.path}')
|
||||||
|
|
||||||
uvicorn.run('halfapi.app:app',
|
uvicorn.run('halfapi.app:app',
|
||||||
env_file=envfile,
|
|
||||||
host=host,
|
host=host,
|
||||||
port=int(port),
|
port=int(port),
|
||||||
log_level=log_level,
|
log_level=log_level,
|
||||||
reload=reload)
|
reload=reload)
|
||||||
|
|
||||||
@click.option('--dbname', default='api')
|
|
||||||
@click.option('--host', default='127.0.0.1')
|
def delete_domain(domain):
|
||||||
@click.option('--port', default=5432)
|
d = Domain(name=domain)
|
||||||
@click.option('--apihost', default='127.0.0.1')
|
if len(d) != 1:
|
||||||
@click.option('--apiport', default=8080)
|
return False
|
||||||
@click.option('--user', default='api')
|
|
||||||
@click.option('--password', default='')
|
d.delete(delete_all=True)
|
||||||
@click.option('--domain', default='organigramme')
|
return True
|
||||||
@click.option('--drop', is_flag=True, default=False)
|
|
||||||
|
|
||||||
|
@click.option('--domain', default=None)
|
||||||
@cli.command()
|
@cli.command()
|
||||||
def dbupdate(dbname, host, port, apihost, apiport, user, password, domain, drop):
|
def dbupdate(domain):
|
||||||
|
|
||||||
def dropdb():
|
|
||||||
if not click.confirm(f'will now drop database {dbname}', default=True):
|
|
||||||
return False
|
|
||||||
|
|
||||||
conn = psycopg2.connect({
|
|
||||||
'dbname': dbname,
|
|
||||||
'host': host,
|
|
||||||
'port': port,
|
|
||||||
'user': user,
|
|
||||||
'password': password
|
|
||||||
})
|
|
||||||
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
cur.execute(f'drop database {dbname};')
|
|
||||||
conn.commit()
|
|
||||||
cur.close()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def delete_domain():
|
|
||||||
d = Domain(name=domain)
|
|
||||||
if len(d) < 1:
|
|
||||||
return False
|
|
||||||
|
|
||||||
acl = Acl(domain=domain)
|
|
||||||
acl.delete()
|
|
||||||
|
|
||||||
fct = AclFunction(domain=domain)
|
|
||||||
fct.delete()
|
|
||||||
|
|
||||||
route = Route(domain=domain)
|
|
||||||
route.delete()
|
|
||||||
|
|
||||||
d.delete()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def add_acl_fct(fct):
|
def add_acl_fct(fct):
|
||||||
acl = AclFunction()
|
acl = AclFunction()
|
||||||
acl.version = version
|
|
||||||
acl.domain = domain
|
acl.domain = domain
|
||||||
acl.name = fct.__name__
|
acl.name = fct.__name__
|
||||||
if len(acl) == 0:
|
if len(acl) == 0:
|
||||||
acl.insert()
|
acl.insert()
|
||||||
|
|
||||||
def add_acl(name, **kwargs):
|
|
||||||
acl = Acl()
|
def add_acls(acls, **route):
|
||||||
acl.version = version
|
route.pop('fct_name')
|
||||||
acl.domain = domain
|
acl = Acl(**route)
|
||||||
acl.name = name
|
|
||||||
acl.path = kwargs['path']
|
for fct in acls:
|
||||||
acl.http_verb = kwargs['verb']
|
acl.acl_fct_name = fct.__name__
|
||||||
for fct in kwargs['acl']:
|
|
||||||
acl.function = fct.__name__
|
|
||||||
|
|
||||||
if len(acl) == 0:
|
if len(acl) == 0:
|
||||||
if fct is not None:
|
if fct is not None:
|
||||||
|
@ -146,38 +84,55 @@ def dbupdate(dbname, host, port, apihost, apiport, user, password, domain, drop)
|
||||||
acl.delete()
|
acl.delete()
|
||||||
|
|
||||||
|
|
||||||
def add_route(name, **kwargs):
|
def get_fct_name(http_verb, path):
|
||||||
click.echo(f'Adding route {version}/{domain}/{name}')
|
if path[0] != '/':
|
||||||
route = Route()
|
raise Exception('Malformed path')
|
||||||
route.version = version
|
|
||||||
|
elts = path[1:].split('/')
|
||||||
|
|
||||||
|
fct_name = [http_verb.lower()]
|
||||||
|
for elt in elts:
|
||||||
|
if elt[0] == '{':
|
||||||
|
fct_name.append(elt[1:-1].split(':')[0].upper())
|
||||||
|
else:
|
||||||
|
fct_name.append(elt)
|
||||||
|
|
||||||
|
return '_'.join(fct_name)
|
||||||
|
|
||||||
|
|
||||||
|
def add_router(name):
|
||||||
|
router = APIRouter()
|
||||||
|
router.name = name
|
||||||
|
router.domain = domain
|
||||||
|
|
||||||
|
if len(router) == 0:
|
||||||
|
router.insert()
|
||||||
|
|
||||||
|
|
||||||
|
def add_route(http_verb, path, router, acls):
|
||||||
|
click.echo(f'Adding route /{domain}/{router}{path}')
|
||||||
|
route = APIRoute()
|
||||||
|
route.http_verb = http_verb
|
||||||
|
route.path = path
|
||||||
|
route.fct_name = get_fct_name(http_verb, path)
|
||||||
|
route.router = router
|
||||||
route.domain = domain
|
route.domain = domain
|
||||||
route.path = kwargs['path']
|
|
||||||
if len(route) == 0:
|
if len(route) == 0:
|
||||||
route.insert()
|
route.insert()
|
||||||
|
|
||||||
def add_routes_and_acl(routes):
|
add_acls(acls, **route.to_dict())
|
||||||
for name, route_params in routes.items():
|
|
||||||
add_route(name, **route_params)
|
|
||||||
add_acl(name, **route_params)
|
|
||||||
|
|
||||||
|
|
||||||
def add_domain():
|
def add_domain():
|
||||||
new_version = Version(name=version, server=apihost, port=apiport)
|
|
||||||
if len(new_version) == 0:
|
|
||||||
click.echo(f'New version : {version}')
|
|
||||||
new_version.insert()
|
|
||||||
|
|
||||||
new_domain = Domain(name=domain)
|
new_domain = Domain(name=domain)
|
||||||
new_domain.version = version
|
|
||||||
if len(new_domain) == 0:
|
if len(new_domain) == 0:
|
||||||
click.echo(f'New domain {domain}')
|
click.echo(f'New domain {domain}')
|
||||||
new_domain.insert()
|
new_domain.insert()
|
||||||
|
|
||||||
|
sys.path.insert(0, BASE_DIR)
|
||||||
|
|
||||||
if drop:
|
delete_domain(domain)
|
||||||
dropdb()
|
|
||||||
|
|
||||||
delete_domain()
|
|
||||||
|
|
||||||
acl_set = set()
|
acl_set = set()
|
||||||
|
|
||||||
|
@ -186,19 +141,20 @@ def dbupdate(dbname, host, port, apihost, apiport, user, password, domain, drop)
|
||||||
# module retrieval
|
# module retrieval
|
||||||
dom_mod = importlib.import_module(domain)
|
dom_mod = importlib.import_module(domain)
|
||||||
|
|
||||||
version = dom_mod.API_VERSION
|
|
||||||
add_domain()
|
add_domain()
|
||||||
|
|
||||||
# add main routes
|
|
||||||
ROUTES = dom_mod.ROUTES
|
|
||||||
add_routes_and_acl(dom_mod.ROUTES)
|
|
||||||
|
|
||||||
# add sub routers
|
# add sub routers
|
||||||
ROUTERS = dom_mod.ROUTERS
|
ROUTERS = dom_mod.ROUTERS
|
||||||
|
|
||||||
for router_name in dom_mod.ROUTERS:
|
for router_name in dom_mod.ROUTERS:
|
||||||
router_mod = importlib.import_module(f'.routers.{router_name}', domain)
|
router_mod = importlib.import_module(f'.routers.{router_name}', domain)
|
||||||
add_routes_and_acl(router_mod.ROUTES)
|
add_router(router_name)
|
||||||
|
|
||||||
|
pprint(router_mod.ROUTES)
|
||||||
|
for route_path, route_params in router_mod.ROUTES.items():
|
||||||
|
for http_verb, acls in route_params.items():
|
||||||
|
add_route(http_verb, route_path, router_name, acls)
|
||||||
|
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
click.echo(f'The domain {domain} has no *ROUTES* variable', err=True)
|
click.echo(f'The domain {domain} has no *ROUTES* variable', err=True)
|
||||||
|
@ -206,9 +162,5 @@ def dbupdate(dbname, host, port, apihost, apiport, user, password, domain, drop)
|
||||||
click.echo(e, err=True)
|
click.echo(e, err=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
cli()
|
cli()
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
CONFIG={}
|
|
||||||
CONFIG['DEBUG'] = environ.get('DEBUG', False)
|
|
||||||
CONFIG['DEBUG_ACL'] = environ.get('DEBUG_ACL', False)
|
|
||||||
CONFIG['HALFORM_SECRET'] = environ.get('HALFORM_SECRET', False)
|
|
||||||
|
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from os import environ
|
|
||||||
|
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
|
||||||
from starlette.routing import Match, Mount
|
|
||||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
||||||
|
|
||||||
from halfapi.config import CONFIG
|
|
||||||
from halfapi.models.api.view.acl import Acl as AclView
|
|
||||||
|
|
||||||
class DebugRouteException(Exception):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(self)
|
|
||||||
|
|
||||||
def match_route(app: ASGIApp, scope: Scope):
|
|
||||||
""" Checks all routes from "app" and checks if it matches with the one from
|
|
||||||
scope
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
|
|
||||||
- app (ASGIApp): The Starlette instance
|
|
||||||
- scope (MutableMapping[str, Any]): The requests scope
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
- (dict, dict): The first dict of the tuple is the details on the
|
|
||||||
route, the second one is the path parameters
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
|
|
||||||
HTTPException
|
|
||||||
"""
|
|
||||||
|
|
||||||
""" The *result* variable is fitted to the filter that will be applied when
|
|
||||||
searching the route in the database.
|
|
||||||
Refer to the database documentation for more details on the api.route
|
|
||||||
table.
|
|
||||||
"""
|
|
||||||
|
|
||||||
result = {
|
|
||||||
'domain': None,
|
|
||||||
'name': None,
|
|
||||||
'http_verb': None,
|
|
||||||
'version': None
|
|
||||||
}
|
|
||||||
|
|
||||||
if 'DEBUG' in CONFIG.keys() and len(scope['path'].split('/')) <= 3:
|
|
||||||
raise DebugRouteException()
|
|
||||||
|
|
||||||
try:
|
|
||||||
""" Identification of the parts of the path
|
|
||||||
|
|
||||||
Examples :
|
|
||||||
version : v4
|
|
||||||
domain : organigramme
|
|
||||||
path : laboratoire/personnel
|
|
||||||
"""
|
|
||||||
_, result['domain'], path = scope['path'].split('/', 2)
|
|
||||||
except ValueError as e:
|
|
||||||
#404 Not found
|
|
||||||
raise HTTPException(404)
|
|
||||||
# Prefix the path with "/"
|
|
||||||
path = f'/{path}'
|
|
||||||
|
|
||||||
for route in app.routes:
|
|
||||||
|
|
||||||
if type(route) != Mount:
|
|
||||||
""" The root app should not have exposed routes,
|
|
||||||
only the mounted domains have some.
|
|
||||||
"""
|
|
||||||
continue
|
|
||||||
|
|
||||||
""" Clone the scope to assign the path to the path without the
|
|
||||||
matching domain, be careful to the "root_path" of the mounted domain.
|
|
||||||
|
|
||||||
@TODO
|
|
||||||
Also, improper array unpacking may make crash the program without any
|
|
||||||
explicit error, we may have to improve this as we only rely on this
|
|
||||||
function to accomplish all the routing
|
|
||||||
"""
|
|
||||||
subscope = scope.copy()
|
|
||||||
_, result['domain'], subpath = path.split('/', 2)
|
|
||||||
subscope['path'] = f'/{subpath}'
|
|
||||||
|
|
||||||
for mount_route in route.routes:
|
|
||||||
# Parse all domain routes
|
|
||||||
submatch = mount_route.matches(subscope)
|
|
||||||
if submatch[0] != Match.FULL:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Route matches
|
|
||||||
try:
|
|
||||||
result['name'] = submatch[1]['endpoint'].__name__
|
|
||||||
result['http_verb'] = scope['method']
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
|
|
||||||
return result, submatch[1]['path_params']
|
|
||||||
|
|
||||||
raise HTTPException(404)
|
|
||||||
|
|
||||||
|
|
||||||
class AclCallerMiddleware(BaseHTTPMiddleware):
|
|
||||||
async def __call__(self, scope:Scope, receive: Receive, send: Send) -> None:
|
|
||||||
""" Points out to the domain which ACL function it should call
|
|
||||||
|
|
||||||
Parameters :
|
|
||||||
|
|
||||||
- request (Request): The current request
|
|
||||||
|
|
||||||
- call_next (RequestResponseEndpoint): The next middleware/route function
|
|
||||||
|
|
||||||
Return:
|
|
||||||
Response
|
|
||||||
"""
|
|
||||||
print('Hit AclCallerMiddleware of API')
|
|
||||||
|
|
||||||
if scope['type'] != 'http':
|
|
||||||
await self.app(scope, receive, send)
|
|
||||||
return
|
|
||||||
|
|
||||||
app = self.app
|
|
||||||
while True:
|
|
||||||
if not hasattr(app, 'app'):
|
|
||||||
break
|
|
||||||
app = app.app
|
|
||||||
|
|
||||||
if scope['path'].split('/')[-1] not in ['docs','openapi.json','redoc']:
|
|
||||||
# routes in the the database, the others being
|
|
||||||
# docs/openapi.json/redoc
|
|
||||||
|
|
||||||
try:
|
|
||||||
d_match, path_params = match_route(app, scope)
|
|
||||||
scope['acls'] = []
|
|
||||||
for acl in AclView(**d_match).select():
|
|
||||||
# retrieve related ACLs
|
|
||||||
|
|
||||||
if ('acl_function_name' not in acl.keys()
|
|
||||||
or 'domain' not in acl.keys()):
|
|
||||||
continue
|
|
||||||
|
|
||||||
scope['acls'].append(acl['acl_function_name'])
|
|
||||||
|
|
||||||
except StopIteration:
|
|
||||||
# TODO : No ACL sur une route existante, prevenir l'admin?
|
|
||||||
print("No ACL")
|
|
||||||
pass
|
|
||||||
except DebugRouteException:
|
|
||||||
print("Debug route")
|
|
||||||
if 'DEBUG_ACL' in environ.keys():
|
|
||||||
scope['acls'] = environ['DEBUG_ACL'].split(':')
|
|
||||||
else:
|
|
||||||
scope['acls'] = []
|
|
||||||
|
|
||||||
elif CONFIG['DEBUG']:
|
|
||||||
scope['dev_route'] = True
|
|
||||||
|
|
||||||
res = await self.app(scope, receive, send)
|
|
|
@ -1,45 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from starlette.requests import Request
|
|
||||||
from starlette.exceptions import HTTPException
|
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
|
||||||
|
|
||||||
|
|
||||||
class AclMiddleware(BaseHTTPMiddleware):
|
|
||||||
def __init__(self, app, acl_module):
|
|
||||||
super().__init__(app)
|
|
||||||
self.acl_module = acl_module
|
|
||||||
async def dispatch(self, request: Request, call_next):
|
|
||||||
""" Checks the "acls" key in the scope and applies the
|
|
||||||
corresponding functions in the current module's acl lib.
|
|
||||||
|
|
||||||
Raises an exception if no acl function returns True
|
|
||||||
"""
|
|
||||||
print(f'Hit acl {__name__} middleware')
|
|
||||||
|
|
||||||
if 'dev_route' in request.scope.keys():
|
|
||||||
print('[DEBUG] Dev route, no ACL')
|
|
||||||
return await call_next(request)
|
|
||||||
|
|
||||||
if not('acls' in request.scope.keys()
|
|
||||||
and type(request.scope['acls']) == list):
|
|
||||||
|
|
||||||
print('BUG : scope["acls"] does not exist or is not a list')
|
|
||||||
raise HTTPException(500)
|
|
||||||
|
|
||||||
for acl_fct_name in request.scope['acls']:
|
|
||||||
print(f'Will apply {acl_fct_name}')
|
|
||||||
try:
|
|
||||||
fct = getattr(self.acl_module, acl_fct_name)
|
|
||||||
if fct(request) is True:
|
|
||||||
return await call_next(request)
|
|
||||||
|
|
||||||
except AttributeError as e:
|
|
||||||
print(f'No ACL function "{acl_fct_name}" in {__name__} module')
|
|
||||||
print(e)
|
|
||||||
break
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
raise HTTPException(500)
|
|
||||||
|
|
||||||
raise HTTPException(401)
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from functools import wraps
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from halfapi import (PROJECT_NAME, HOST, PORT,
|
||||||
|
PRODUCTION,
|
||||||
|
Domain,
|
||||||
|
APIRouter,
|
||||||
|
APIRoute,
|
||||||
|
AclFunction,
|
||||||
|
Acl)
|
||||||
|
from halfapi.lib.responses import *
|
||||||
|
from starlette.exceptions import HTTPException
|
||||||
|
from starlette.routing import Mount, Route
|
||||||
|
from starlette.requests import Request
|
||||||
|
|
||||||
|
def get_routes(domains=None):
|
||||||
|
""" Procedure to mount the registered domains on their prefixes
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- app (ASGIApp): The Starlette instance
|
||||||
|
- domains (list): The domains to mount, retrieved from the database
|
||||||
|
with their attributes "name"
|
||||||
|
|
||||||
|
Returns: Nothing
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def route_decorator(fct, acls_mod, acls):
|
||||||
|
@wraps(fct)
|
||||||
|
def caller(req: Request, *args, **kwargs):
|
||||||
|
for acl_fct_name in acls:
|
||||||
|
acl_fct = getattr(acls_mod, acl_fct_name)
|
||||||
|
if acl_fct(req, *args, **kwargs):
|
||||||
|
return func(req, *args, **kwargs)
|
||||||
|
|
||||||
|
raise HTTPException(401)
|
||||||
|
|
||||||
|
return caller
|
||||||
|
|
||||||
|
app_routes = []
|
||||||
|
for domain in Domain(name=domains).select():
|
||||||
|
domain_acl_mod = importlib.import_module(f'{domain["name"]}.acl')
|
||||||
|
domain_routes = []
|
||||||
|
for router in APIRouter(domain=domain['name']).select():
|
||||||
|
router_routes = []
|
||||||
|
|
||||||
|
router_mod = importlib.import_module(
|
||||||
|
'{domain}.routers.{name}'.format(**router))
|
||||||
|
|
||||||
|
with APIRoute(domain=domain['name'],
|
||||||
|
router=router['name']) as routes:
|
||||||
|
for route in routes.select():
|
||||||
|
fct_name = route.pop('fct_name')
|
||||||
|
acls = [ list(elt.values()).pop()
|
||||||
|
for elt in Acl(**route).select('acl_fct_name') ]
|
||||||
|
|
||||||
|
router_routes.append(
|
||||||
|
Route(route['path'],
|
||||||
|
route_decorator(
|
||||||
|
getattr(router_mod, fct_name),
|
||||||
|
domain_acl_mod,
|
||||||
|
acls
|
||||||
|
), methods=[route['http_verb']])
|
||||||
|
)
|
||||||
|
|
||||||
|
domain_routes.append(
|
||||||
|
Mount('/{name}'.format(**router), routes=router_routes))
|
||||||
|
|
||||||
|
app_routes.append(Mount('/{name}'.format(**domain),
|
||||||
|
routes=domain_routes))
|
||||||
|
return app_routes
|
|
@ -1,11 +0,0 @@
|
||||||
"""This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'api',
|
|
||||||
'db_connector'
|
|
||||||
]
|
|
|
@ -2,72 +2,73 @@ create schema api;
|
||||||
|
|
||||||
create type verb as enum ('POST', 'GET', 'PUT', 'DELETE');
|
create type verb as enum ('POST', 'GET', 'PUT', 'DELETE');
|
||||||
|
|
||||||
create table api.version (
|
create table api.domain (
|
||||||
name text primary key,
|
name text,
|
||||||
server cidr not null default '127.0.0.1',
|
primary key (name)
|
||||||
port integer not null
|
|
||||||
);
|
);
|
||||||
|
|
||||||
create table api.domain (
|
create table api.router (
|
||||||
version text references api.version(name),
|
|
||||||
name text,
|
name text,
|
||||||
primary key (version, name)
|
domain text,
|
||||||
|
primary key (name, domain)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
alter table api.router add constraint router_domain_fkey foreign key (domain) references api.domain(name) on update cascade on delete cascade;
|
||||||
|
|
||||||
create table api.route (
|
create table api.route (
|
||||||
path text, -- relative to /api/<version>/<domain>
|
http_verb verb,
|
||||||
version text,
|
path text, -- relative to /<domain>/<router>
|
||||||
|
fct_name text,
|
||||||
|
router text,
|
||||||
domain text,
|
domain text,
|
||||||
primary key (path, domain, version)
|
primary key (http_verb, path, router, domain)
|
||||||
);
|
);
|
||||||
|
|
||||||
alter table api.route add constraint route_domain_fkey foreign key (version, domain) references api.domain(version, name) on update cascade on delete cascade;
|
alter table api.route add constraint route_router_fkey foreign key (router, domain) references api.router(name, domain) on update cascade on delete cascade;
|
||||||
|
|
||||||
create table api.acl_function (
|
create table api.acl_function (
|
||||||
name text,
|
name text,
|
||||||
description text,
|
description text,
|
||||||
version text,
|
|
||||||
domain text,
|
domain text,
|
||||||
primary key (name, version, domain)
|
primary key (name, domain)
|
||||||
);
|
);
|
||||||
|
|
||||||
alter table api.acl_function add constraint acl_function_domain_fkey foreign key (version, domain) references api.domain(version, name) on update cascade on delete cascade;
|
alter table api.acl_function add constraint acl_function_domain_fkey foreign key (domain) references api.domain(name) on update cascade on delete cascade;
|
||||||
|
|
||||||
create table api.acl (
|
create table api.acl (
|
||||||
name text,
|
|
||||||
http_verb verb,
|
http_verb verb,
|
||||||
path text not null,
|
path text not null,
|
||||||
version text,
|
router text,
|
||||||
domain text not null,
|
domain text,
|
||||||
function text not null,
|
acl_fct_name text,
|
||||||
primary key (name, version, domain, function)
|
primary key (http_verb, path, router, domain, acl_fct_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
alter table api.acl add constraint acl_route_fkey foreign key (path, version, domain) references api.route(path, version, domain) on update cascade on delete cascade;
|
alter table api.acl add constraint acl_route_fkey foreign key (http_verb, path,
|
||||||
alter table api.acl add constraint acl_function_fkey foreign key (function, version, domain) references api.acl_function(name, version, domain) on update cascade on delete cascade;
|
router, domain) references api.route(http_verb, path, router, domain) on update cascade on delete cascade;
|
||||||
|
alter table api.acl add constraint acl_function_fkey foreign key (acl_fct_name, domain) references api.acl_function(name, domain) on update cascade on delete cascade;
|
||||||
|
|
||||||
create schema "api.view";
|
create schema "api.view";
|
||||||
|
|
||||||
create view "api.view".route as
|
create view "api.view".route as
|
||||||
select
|
select
|
||||||
route.*,
|
route.*,
|
||||||
version.name,
|
'/'::text || route.domain || '/'::text || route.router || route.path AS abs_path
|
||||||
version.server,
|
|
||||||
version.port,
|
|
||||||
'/'::text || route.domain || route.path AS abs_path
|
|
||||||
from
|
from
|
||||||
api.route
|
api.route
|
||||||
join api.domain on
|
join api.domain on
|
||||||
route.domain = domain.name
|
route.domain = domain.name
|
||||||
join api.version on
|
;
|
||||||
domain.version = version.name;
|
|
||||||
|
|
||||||
create view "api.view".acl as
|
create view "api.view".acl as
|
||||||
select
|
select
|
||||||
acl.*,
|
acl.*,
|
||||||
acl_function.name as acl_function_name,
|
'/'::text || route.domain || '/'::text || route.router || route.path AS abs_path
|
||||||
'/'::text || acl.domain || acl.path AS abs_path
|
|
||||||
from
|
from
|
||||||
api.acl
|
api.acl
|
||||||
join api.acl_function on
|
join api.acl_function on
|
||||||
acl.function = acl_function.name;
|
acl.acl_fct_name = acl_function.name
|
||||||
|
join api.route on
|
||||||
|
acl.domain = route.domain
|
||||||
|
and acl.router = route.router
|
||||||
|
and acl.path = route.path;
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
"""This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'acl',
|
|
||||||
'acl_function',
|
|
||||||
'domain',
|
|
||||||
'route',
|
|
||||||
'version',
|
|
||||||
'view'
|
|
||||||
]
|
|
|
@ -1,52 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.acl povides the Acl class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ..db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.acl')
|
|
||||||
|
|
||||||
class Acl( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.Table_ApiApiAcl'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
TABLE: "api"."api"."acl"
|
|
||||||
FIELDS:
|
|
||||||
- name: (text) PK
|
|
||||||
- http_verb: (verb)
|
|
||||||
- path: (text) NOT NULL
|
|
||||||
- version: (text) PK
|
|
||||||
- domain: (text) PK
|
|
||||||
- function: (text) PK
|
|
||||||
FOREIGN KEYS:
|
|
||||||
- acl_route_fkey: (path, version, domain)
|
|
||||||
↳ "api"."api"."route"(path, version, domain)
|
|
||||||
- acl_function_fkey: (function, version, domain)
|
|
||||||
↳ "api"."api"."acl_function"(name, version, domain)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Acl, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,50 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.acl_function povides the AclFunction class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ..db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.acl_function')
|
|
||||||
|
|
||||||
class AclFunction( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.Table_ApiApiAcl_function'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
TABLE: "api"."api"."acl_function"
|
|
||||||
FIELDS:
|
|
||||||
- name: (text) PK
|
|
||||||
- description: (text)
|
|
||||||
- version: (text) PK
|
|
||||||
- domain: (text) PK
|
|
||||||
FOREIGN KEYS:
|
|
||||||
- _reverse_fkey_api_api_acl_function_version_domain: (name, version, domain)
|
|
||||||
↳ "api"."api"."acl"(function, version, domain)
|
|
||||||
- acl_function_domain_fkey: (version, domain)
|
|
||||||
↳ "api"."api"."domain"(version, name)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(AclFunction, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,50 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.domain povides the Domain class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ..db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.domain')
|
|
||||||
|
|
||||||
class Domain( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.Table_ApiApiDomain'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
TABLE: "api"."api"."domain"
|
|
||||||
FIELDS:
|
|
||||||
- version: (text) PK
|
|
||||||
- name: (text) PK
|
|
||||||
FOREIGN KEYS:
|
|
||||||
- _reverse_fkey_api_api_acl_function_version_domain: (version, name)
|
|
||||||
↳ "api"."api"."acl_function"(version, domain)
|
|
||||||
- domain_version_fkey: (version)
|
|
||||||
↳ "api"."api"."version"(name)
|
|
||||||
- _reverse_fkey_api_api_route_version_domain: (version, name)
|
|
||||||
↳ "api"."api"."route"(version, domain)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Domain, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,49 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.route povides the Route class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ..db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.route')
|
|
||||||
|
|
||||||
class Route( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.Table_ApiApiRoute'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
TABLE: "api"."api"."route"
|
|
||||||
FIELDS:
|
|
||||||
- path: (text) PK
|
|
||||||
- version: (text) PK
|
|
||||||
- domain: (text) PK
|
|
||||||
FOREIGN KEYS:
|
|
||||||
- _reverse_fkey_api_api_acl_path_version_domain: (path, version, domain)
|
|
||||||
↳ "api"."api"."acl"(path, version, domain)
|
|
||||||
- route_domain_fkey: (version, domain)
|
|
||||||
↳ "api"."api"."domain"(version, name)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Route, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,47 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.version povides the Version class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ..db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.version')
|
|
||||||
|
|
||||||
class Version( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.Table_ApiApiVersion'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
TABLE: "api"."api"."version"
|
|
||||||
FIELDS:
|
|
||||||
- name: (text) PK
|
|
||||||
- server: (cidr) NOT NULL
|
|
||||||
- port: (int4) NOT NULL
|
|
||||||
FOREIGN KEY:
|
|
||||||
- _reverse_fkey_api_api_domain_version: (name)
|
|
||||||
↳ "api"."api"."domain"(version)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Version, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,11 +0,0 @@
|
||||||
"""This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
"""
|
|
||||||
|
|
||||||
__all__ = [
|
|
||||||
'acl',
|
|
||||||
'route'
|
|
||||||
]
|
|
|
@ -1,49 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.view.acl povides the Acl class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ...db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.view.acl')
|
|
||||||
|
|
||||||
class Acl( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.View_ApiApiviewAcl'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
VIEW: "api"."api.view"."acl"
|
|
||||||
FIELDS:
|
|
||||||
- name: (text)
|
|
||||||
- http_verb: (verb)
|
|
||||||
- path: (text)
|
|
||||||
- version: (text)
|
|
||||||
- domain: (text)
|
|
||||||
- function: (text)
|
|
||||||
- acl_function_name: (text)
|
|
||||||
- abs_path: (text)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Acl, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,48 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
# pylint: disable=wrong-import-order
|
|
||||||
|
|
||||||
"""The module apidb.api.view.route povides the Route class.
|
|
||||||
|
|
||||||
WARNING!
|
|
||||||
|
|
||||||
This file is part of the apidb package. It has been generated by the
|
|
||||||
command halfORM. To keep it in sync with your database structure, just rerun
|
|
||||||
halfORM.
|
|
||||||
|
|
||||||
More information on the half_orm library on https://github.com/collorg/halfORM.
|
|
||||||
|
|
||||||
|
|
||||||
DO NOT REMOVE OR MODIFY THE LINES BEGINING WITH:
|
|
||||||
#>>> PLACE YOUR CODE BELOW...
|
|
||||||
#<<< PLACE YOUR CODE ABOVE...
|
|
||||||
|
|
||||||
MAKE SURE YOU PLACE YOUR CODE BETWEEN THESE LINES OR AT THE END OF THE FILE.
|
|
||||||
halfORM ONLY PRESERVES THE CODE BETWEEN THESE MARKS WHEN IT IS RUN.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from ...db_connector import base_relation_class
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
#<<< PLACE YOUR CODE ABOVE THIS LINE. DO NOT REMOVE THIS LINE!
|
|
||||||
|
|
||||||
__RCLS = base_relation_class('api.view.route')
|
|
||||||
|
|
||||||
class Route( __RCLS):
|
|
||||||
"""
|
|
||||||
__RCLS: <class 'half_orm.relation.View_ApiApiviewRoute'>
|
|
||||||
This class allows you to manipulate the data in the PG relation:
|
|
||||||
VIEW: "api"."api.view"."route"
|
|
||||||
FIELDS:
|
|
||||||
- path: (text)
|
|
||||||
- version: (text)
|
|
||||||
- domain: (text)
|
|
||||||
- name: (text)
|
|
||||||
- server: (cidr)
|
|
||||||
- port: (int4)
|
|
||||||
- abs_path: (text)
|
|
||||||
"""
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
super(Route, self).__init__(**kwargs)
|
|
||||||
|
|
||||||
#>>> PLACE YOUR CODE BELLOW THIS LINE. DO NOT REMOVE THIS LINE!
|
|
|
@ -1,17 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""This module exports the fonction base_relation_class which is
|
|
||||||
imported by all modules in the package apidb.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from half_orm.model import Model
|
|
||||||
|
|
||||||
__all__ = ['base_relation_class']
|
|
||||||
|
|
||||||
MODEL = Model('api', scope=__name__)
|
|
||||||
|
|
||||||
def base_relation_class(qrn):
|
|
||||||
"""Returns the class corresponding to the QRN (qualified relation name).
|
|
||||||
"""
|
|
||||||
cls = MODEL.get_relation_class(qrn)
|
|
||||||
return cls
|
|
|
@ -1,848 +0,0 @@
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Package for api PG (apidb)"
|
|
||||||
name = "apidb"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.0.6"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
half_orm = "*"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
reference = "616cef51b8aa5b5c07a05c9c47c9a6ae9656ffa1"
|
|
||||||
type = "git"
|
|
||||||
url = "git@gite.lirmm.fr:newsi/db/hop_api.git"
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Atomic file writes."
|
|
||||||
marker = "sys_platform == \"win32\""
|
|
||||||
name = "atomicwrites"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "1.4.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Classes Without Boilerplate"
|
|
||||||
name = "attrs"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "19.3.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
|
|
||||||
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
|
|
||||||
docs = ["sphinx", "zope.interface"]
|
|
||||||
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Python package for providing Mozilla's CA Bundle."
|
|
||||||
name = "certifi"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "2020.6.20"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Universal encoding detector for Python 2 and 3"
|
|
||||||
name = "chardet"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "3.0.4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Composable command line interface toolkit"
|
|
||||||
name = "click"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
||||||
version = "7.1.2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Cross-platform colored terminal text."
|
|
||||||
marker = "sys_platform == \"win32\""
|
|
||||||
name = "colorama"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
||||||
version = "0.4.3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "XML bomb protection for Python stdlib modules"
|
|
||||||
name = "defusedxml"
|
|
||||||
optional = true
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
||||||
version = "0.6.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
|
||||||
name = "fastapi"
|
|
||||||
optional = true
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "0.59.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pydantic = ">=0.32.2,<2.0.0"
|
|
||||||
starlette = "0.13.4"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.6.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=3.0.0,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn (>=0.11.5,<0.12.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"]
|
|
||||||
dev = ["python-jose (>=3.1.0,<4.0.0)", "passlib (>=1.7.2,<2.0.0)", "autoflake (>=1.3.1,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn (>=0.11.5,<0.12.0)", "graphene (>=2.1.8,<3.0.0)"]
|
|
||||||
doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown-include (>=0.5.1,<0.6.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.2.0)", "typer (>=0.3.0,<0.4.0)", "typer-cli (>=0.0.9,<0.0.10)", "pyyaml (>=5.3.1,<6.0.0)"]
|
|
||||||
test = ["pytest (5.4.3)", "pytest-cov (2.10.0)", "mypy (0.782)", "black (19.10b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<2.0.0)", "peewee (>=3.13.3,<4.0.0)", "databases (>=0.3.2,<0.4.0)", "orjson (>=3.2.1,<4.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.6.0)", "flask (>=1.1.2,<2.0.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
|
||||||
name = "h11"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.9.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A simple ORM in Python only dealing with the DML part of SQL."
|
|
||||||
name = "half-orm"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.2.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
PyYAML = "*"
|
|
||||||
psycopg2-binary = "*"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
reference = "fe53195abb637d2192857e8b4878f4865b0fcce4"
|
|
||||||
type = "git"
|
|
||||||
url = "git@gite.lirmm.fr:newsi/halfORM.git"
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A collection of framework independent HTTP protocol utils."
|
|
||||||
marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\""
|
|
||||||
name = "httptools"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.1.1"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
test = ["Cython (0.29.14)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
|
||||||
name = "idna"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "2.10"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Read metadata from Python packages"
|
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
name = "importlib-metadata"
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
|
||||||
version = "1.7.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
zipp = ">=0.5"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["sphinx", "rst.linker"]
|
|
||||||
testing = ["packaging", "pep517", "importlib-resources (>=1.3)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Load me later. A lazy plugin management system."
|
|
||||||
name = "lml"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.0.9"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
|
|
||||||
name = "lxml"
|
|
||||||
optional = true
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
|
|
||||||
version = "4.5.2"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
cssselect = ["cssselect (>=0.7)"]
|
|
||||||
html5 = ["html5lib"]
|
|
||||||
htmlsoup = ["beautifulsoup4"]
|
|
||||||
source = ["Cython (>=0.29.7)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "More routines for operating on iterables, beyond itertools"
|
|
||||||
name = "more-itertools"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "8.4.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Python API and tools to manipulate OpenDocument files"
|
|
||||||
name = "odfpy"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "1.4.1"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
defusedxml = "*"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = ""
|
|
||||||
name = "organigramme"
|
|
||||||
optional = true
|
|
||||||
python-versions = "^3.7"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
fastapi = "^0"
|
|
||||||
half-orm = "branch master"
|
|
||||||
halfapi = "branch master"
|
|
||||||
pyexcel = "^0.6.2"
|
|
||||||
pyexcel-ods = "^0.5.6"
|
|
||||||
pyexcel-ods3 = "^0.5.3"
|
|
||||||
python-dotenv = "^0.14.0"
|
|
||||||
sidb = "branch master"
|
|
||||||
starlette = "^0"
|
|
||||||
uvicorn = "^0"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
reference = "41984a0f62ee0a951ae06647601dd4a7091c5299"
|
|
||||||
type = "git"
|
|
||||||
url = "git@gite.lirmm.fr:newsi/api/organigramme.git"
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Core utilities for Python packages"
|
|
||||||
name = "packaging"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "20.4"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pyparsing = ">=2.0.2"
|
|
||||||
six = "*"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "plugin and hook calling mechanisms for python"
|
|
||||||
name = "pluggy"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "0.13.1"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
[package.dependencies.importlib-metadata]
|
|
||||||
python = "<3.8"
|
|
||||||
version = ">=0.12"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dev = ["pre-commit", "tox"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
|
||||||
name = "psycopg2-binary"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
|
||||||
version = "2.8.5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
|
||||||
name = "py"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "1.9.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Data validation and settings management using python 3.6 type hinting"
|
|
||||||
name = "pydantic"
|
|
||||||
optional = true
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "1.6.1"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
|
||||||
email = ["email-validator (>=1.0.3)"]
|
|
||||||
typing_extensions = ["typing-extensions (>=3.7.2)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A wrapper library that provides one API to read, manipulate and writedata in different excel formats"
|
|
||||||
name = "pyexcel"
|
|
||||||
optional = true
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "0.6.2"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lml = ">=0.0.4"
|
|
||||||
pyexcel-io = ">=0.5.19"
|
|
||||||
texttable = ">=0.8.2"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
ods = ["pyexcel-ods3 (>=0.5.0)"]
|
|
||||||
xls = ["pyexcel-xls (>=0.5.0)"]
|
|
||||||
xlsx = ["pyexcel-xlsx (>=0.5.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A Python package to create/manipulate OpenDocumentFormat files"
|
|
||||||
name = "pyexcel-ezodf"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.3.4"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lxml = "*"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A python library to read and write structured data in csv, zipped csvformat and to/from databases"
|
|
||||||
name = "pyexcel-io"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.5.20"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lml = ">=0.0.4"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
ods = ["pyexcel-ods3 (>=0.5.0)"]
|
|
||||||
xls = ["pyexcel-xls (>=0.5.0)"]
|
|
||||||
xlsx = ["pyexcel-xlsx (>=0.5.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A wrapper library to read, manipulate and write data in ods format"
|
|
||||||
name = "pyexcel-ods"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.5.6"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
odfpy = ">=1.3.5"
|
|
||||||
pyexcel-io = ">=0.5.16"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "A wrapper library to read, manipulate and write data in ods format"
|
|
||||||
name = "pyexcel-ods3"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.5.3"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
lxml = "*"
|
|
||||||
pyexcel-ezodf = ">=0.3.3"
|
|
||||||
pyexcel-io = ">=0.5.10"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "JSON Web Token implementation in Python"
|
|
||||||
name = "pyjwt"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "1.7.1"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
crypto = ["cryptography (>=1.4)"]
|
|
||||||
flake8 = ["flake8", "flake8-import-order", "pep8-naming"]
|
|
||||||
test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Python parsing module"
|
|
||||||
name = "pyparsing"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
|
||||||
version = "2.4.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "pytest: simple powerful testing with Python"
|
|
||||||
name = "pytest"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "5.4.3"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
atomicwrites = ">=1.0"
|
|
||||||
attrs = ">=17.4.0"
|
|
||||||
colorama = "*"
|
|
||||||
more-itertools = ">=4.0.0"
|
|
||||||
packaging = "*"
|
|
||||||
pluggy = ">=0.12,<1.0"
|
|
||||||
py = ">=1.5.0"
|
|
||||||
wcwidth = "*"
|
|
||||||
|
|
||||||
[package.dependencies.importlib-metadata]
|
|
||||||
python = "<3.8"
|
|
||||||
version = ">=0.12"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
checkqa-mypy = ["mypy (v0.761)"]
|
|
||||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "py.test plugin that allows you to add environment variables."
|
|
||||||
name = "pytest-env"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.6.2"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
pytest = ">=2.6.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Add .env support to your django/flask apps in development and deployments"
|
|
||||||
name = "python-dotenv"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.14.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
cli = ["click (>=5.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "YAML parser and emitter for Python"
|
|
||||||
name = "pyyaml"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
||||||
version = "5.3.1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Python HTTP for Humans."
|
|
||||||
name = "requests"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
|
||||||
version = "2.24.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
certifi = ">=2017.4.17"
|
|
||||||
chardet = ">=3.0.2,<4"
|
|
||||||
idna = ">=2.5,<3"
|
|
||||||
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
|
||||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Package for si PG"
|
|
||||||
name = "sidb"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.0.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
half_orm = "*"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
reference = "d0f14a9631eecd29098d13a3f34e9cd533145f24"
|
|
||||||
type = "git"
|
|
||||||
url = "git@gite.lirmm.fr:newsi/sidb_halfORM.git"
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
|
||||||
name = "six"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
|
||||||
version = "1.15.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "The little ASGI library that shines."
|
|
||||||
name = "starlette"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "0.13.4"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "ujson"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "module for creating simple ASCII tables"
|
|
||||||
name = "texttable"
|
|
||||||
optional = true
|
|
||||||
python-versions = "*"
|
|
||||||
version = "1.6.2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
|
||||||
name = "urllib3"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
|
||||||
version = "1.25.9"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
brotli = ["brotlipy (>=0.6.0)"]
|
|
||||||
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
|
|
||||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "The lightning-fast ASGI server."
|
|
||||||
name = "uvicorn"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.11.6"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
click = ">=7.0.0,<8.0.0"
|
|
||||||
h11 = ">=0.8,<0.10"
|
|
||||||
httptools = ">=0.1.0,<0.2.0"
|
|
||||||
uvloop = ">=0.14.0"
|
|
||||||
websockets = ">=8.0.0,<9.0.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
watchgodreload = ["watchgod (>=0.6,<0.7)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Fast implementation of asyncio event loop on top of libuv"
|
|
||||||
marker = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\""
|
|
||||||
name = "uvloop"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.14.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Measures the displayed width of unicode strings in a terminal"
|
|
||||||
name = "wcwidth"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.2.5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
|
|
||||||
name = "websockets"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6.1"
|
|
||||||
version = "8.1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
name = "zipp"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
version = "3.1.0"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
|
||||||
testing = ["jaraco.itertools", "func-timeout"]
|
|
||||||
|
|
||||||
[extras]
|
|
||||||
organigramme = ["fastapi", "organigramme", "sidb", "pyexcel-ods3"]
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
content-hash = "826725e53dedda2a3acbf7f004594358246da3c67c5006586c67e408fb41bee7"
|
|
||||||
python-versions = "^3.7"
|
|
||||||
|
|
||||||
[metadata.files]
|
|
||||||
apidb = []
|
|
||||||
atomicwrites = [
|
|
||||||
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
|
||||||
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
|
||||||
]
|
|
||||||
attrs = [
|
|
||||||
{file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
|
|
||||||
{file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
|
|
||||||
]
|
|
||||||
certifi = [
|
|
||||||
{file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
|
|
||||||
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
|
|
||||||
]
|
|
||||||
chardet = [
|
|
||||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
|
||||||
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
|
||||||
]
|
|
||||||
click = [
|
|
||||||
{file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
|
|
||||||
{file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
|
|
||||||
]
|
|
||||||
colorama = [
|
|
||||||
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
|
|
||||||
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
|
|
||||||
]
|
|
||||||
defusedxml = [
|
|
||||||
{file = "defusedxml-0.6.0-py2.py3-none-any.whl", hash = "sha256:6687150770438374ab581bb7a1b327a847dd9c5749e396102de3fad4e8a3ef93"},
|
|
||||||
{file = "defusedxml-0.6.0.tar.gz", hash = "sha256:f684034d135af4c6cbb949b8a4d2ed61634515257a67299e5f940fbaa34377f5"},
|
|
||||||
]
|
|
||||||
fastapi = [
|
|
||||||
{file = "fastapi-0.59.0-py3-none-any.whl", hash = "sha256:50b58aa3e7d5bcb4a4404ac7e550cc53f0cf7ca0fd13c7fd515693dc23c9caef"},
|
|
||||||
{file = "fastapi-0.59.0.tar.gz", hash = "sha256:c04dacd3deed0fd0ffdcdb116b5a04ffa257656885be7fae7234f4f62ec4a0a9"},
|
|
||||||
]
|
|
||||||
h11 = [
|
|
||||||
{file = "h11-0.9.0-py2.py3-none-any.whl", hash = "sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"},
|
|
||||||
{file = "h11-0.9.0.tar.gz", hash = "sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1"},
|
|
||||||
]
|
|
||||||
half-orm = []
|
|
||||||
httptools = [
|
|
||||||
{file = "httptools-0.1.1-cp35-cp35m-macosx_10_13_x86_64.whl", hash = "sha256:a2719e1d7a84bb131c4f1e0cb79705034b48de6ae486eb5297a139d6a3296dce"},
|
|
||||||
{file = "httptools-0.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:fa3cd71e31436911a44620473e873a256851e1f53dee56669dae403ba41756a4"},
|
|
||||||
{file = "httptools-0.1.1-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:86c6acd66765a934e8730bf0e9dfaac6fdcf2a4334212bd4a0a1c78f16475ca6"},
|
|
||||||
{file = "httptools-0.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:bc3114b9edbca5a1eb7ae7db698c669eb53eb8afbbebdde116c174925260849c"},
|
|
||||||
{file = "httptools-0.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:ac0aa11e99454b6a66989aa2d44bca41d4e0f968e395a0a8f164b401fefe359a"},
|
|
||||||
{file = "httptools-0.1.1-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:96da81e1992be8ac2fd5597bf0283d832287e20cb3cfde8996d2b00356d4e17f"},
|
|
||||||
{file = "httptools-0.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:56b6393c6ac7abe632f2294da53f30d279130a92e8ae39d8d14ee2e1b05ad1f2"},
|
|
||||||
{file = "httptools-0.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:96eb359252aeed57ea5c7b3d79839aaa0382c9d3149f7d24dd7172b1bcecb009"},
|
|
||||||
{file = "httptools-0.1.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:fea04e126014169384dee76a153d4573d90d0cbd1d12185da089f73c78390437"},
|
|
||||||
{file = "httptools-0.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3592e854424ec94bd17dc3e0c96a64e459ec4147e6d53c0a42d0ebcef9cb9c5d"},
|
|
||||||
{file = "httptools-0.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:0a4b1b2012b28e68306575ad14ad5e9120b34fccd02a81eb08838d7e3bbb48be"},
|
|
||||||
{file = "httptools-0.1.1.tar.gz", hash = "sha256:41b573cf33f64a8f8f3400d0a7faf48e1888582b6f6e02b82b9bd4f0bf7497ce"},
|
|
||||||
]
|
|
||||||
idna = [
|
|
||||||
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
|
|
||||||
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
|
|
||||||
]
|
|
||||||
importlib-metadata = [
|
|
||||||
{file = "importlib_metadata-1.7.0-py2.py3-none-any.whl", hash = "sha256:dc15b2969b4ce36305c51eebe62d418ac7791e9a157911d58bfb1f9ccd8e2070"},
|
|
||||||
{file = "importlib_metadata-1.7.0.tar.gz", hash = "sha256:90bb658cdbbf6d1735b6341ce708fc7024a3e14e99ffdc5783edea9f9b077f83"},
|
|
||||||
]
|
|
||||||
lml = [
|
|
||||||
{file = "lml-0.0.9-py2.py3-none-any.whl", hash = "sha256:b1bef669dc077a1075fa64b99229b6341085b3b3a98d29c66df1853cc14e6c1a"},
|
|
||||||
{file = "lml-0.0.9.tar.gz", hash = "sha256:ea5ba817b4adc9e9f5c21725cd2475f912933b7e2dfdf0792aed80077154f63f"},
|
|
||||||
]
|
|
||||||
lxml = [
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:74f48ec98430e06c1fa8949b49ebdd8d27ceb9df8d3d1c92e1fdc2773f003f20"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e70d4e467e243455492f5de463b72151cc400710ac03a0678206a5f27e79ddef"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:7ad7906e098ccd30d8f7068030a0b16668ab8aa5cda6fcd5146d8d20cbaa71b5"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27m-win32.whl", hash = "sha256:92282c83547a9add85ad658143c76a64a8d339028926d7dc1998ca029c88ea6a"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27m-win_amd64.whl", hash = "sha256:05a444b207901a68a6526948c7cc8f9fe6d6f24c70781488e32fd74ff5996e3f"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:94150231f1e90c9595ccc80d7d2006c61f90a5995db82bccbca7944fd457f0f6"},
|
|
||||||
{file = "lxml-4.5.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:bea760a63ce9bba566c23f726d72b3c0250e2fa2569909e2d83cda1534c79443"},
|
|
||||||
{file = "lxml-4.5.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c3f511a3c58676147c277eff0224c061dd5a6a8e1373572ac817ac6324f1b1e0"},
|
|
||||||
{file = "lxml-4.5.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:59daa84aef650b11bccd18f99f64bfe44b9f14a08a28259959d33676554065a1"},
|
|
||||||
{file = "lxml-4.5.2-cp35-cp35m-win32.whl", hash = "sha256:9dc9006dcc47e00a8a6a029eb035c8f696ad38e40a27d073a003d7d1443f5d88"},
|
|
||||||
{file = "lxml-4.5.2-cp35-cp35m-win_amd64.whl", hash = "sha256:08fc93257dcfe9542c0a6883a25ba4971d78297f63d7a5a26ffa34861ca78730"},
|
|
||||||
{file = "lxml-4.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:121b665b04083a1e85ff1f5243d4a93aa1aaba281bc12ea334d5a187278ceaf1"},
|
|
||||||
{file = "lxml-4.5.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5591c4164755778e29e69b86e425880f852464a21c7bb53c7ea453bbe2633bbe"},
|
|
||||||
{file = "lxml-4.5.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cc411ad324a4486b142c41d9b2b6a722c534096963688d879ea6fa8a35028258"},
|
|
||||||
{file = "lxml-4.5.2-cp36-cp36m-win32.whl", hash = "sha256:786aad2aa20de3dbff21aab86b2fb6a7be68064cbbc0219bde414d3a30aa47ae"},
|
|
||||||
{file = "lxml-4.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:e1cacf4796b20865789083252186ce9dc6cc59eca0c2e79cca332bdff24ac481"},
|
|
||||||
{file = "lxml-4.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:80a38b188d20c0524fe8959c8ce770a8fdf0e617c6912d23fc97c68301bb9aba"},
|
|
||||||
{file = "lxml-4.5.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ecc930ae559ea8a43377e8b60ca6f8d61ac532fc57efb915d899de4a67928efd"},
|
|
||||||
{file = "lxml-4.5.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:a76979f728dd845655026ab991df25d26379a1a8fc1e9e68e25c7eda43004bed"},
|
|
||||||
{file = "lxml-4.5.2-cp37-cp37m-win32.whl", hash = "sha256:5a9c8d11aa2c8f8b6043d845927a51eb9102eb558e3f936df494e96393f5fd3e"},
|
|
||||||
{file = "lxml-4.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:4b4a111bcf4b9c948e020fd207f915c24a6de3f1adc7682a2d92660eb4e84f1a"},
|
|
||||||
{file = "lxml-4.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5dd20538a60c4cc9a077d3b715bb42307239fcd25ef1ca7286775f95e9e9a46d"},
|
|
||||||
{file = "lxml-4.5.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:2b30aa2bcff8e958cd85d907d5109820b01ac511eae5b460803430a7404e34d7"},
|
|
||||||
{file = "lxml-4.5.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:aa8eba3db3d8761db161003e2d0586608092e217151d7458206e243be5a43843"},
|
|
||||||
{file = "lxml-4.5.2-cp38-cp38-win32.whl", hash = "sha256:107781b213cf7201ec3806555657ccda67b1fccc4261fb889ef7fc56976db81f"},
|
|
||||||
{file = "lxml-4.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:f161af26f596131b63b236372e4ce40f3167c1b5b5d459b29d2514bd8c9dc9ee"},
|
|
||||||
{file = "lxml-4.5.2.tar.gz", hash = "sha256:cdc13a1682b2a6241080745b1953719e7fe0850b40a5c71ca574f090a1391df6"},
|
|
||||||
]
|
|
||||||
more-itertools = [
|
|
||||||
{file = "more-itertools-8.4.0.tar.gz", hash = "sha256:68c70cc7167bdf5c7c9d8f6954a7837089c6a36bf565383919bb595efb8a17e5"},
|
|
||||||
{file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
|
|
||||||
]
|
|
||||||
odfpy = [
|
|
||||||
{file = "odfpy-1.4.1-py2.7.egg", hash = "sha256:fc3b8d1bc098eba4a0fda865a76d9d1e577c4ceec771426bcb169a82c5e9dfe0"},
|
|
||||||
{file = "odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec"},
|
|
||||||
]
|
|
||||||
organigramme = []
|
|
||||||
packaging = [
|
|
||||||
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
|
|
||||||
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
|
|
||||||
]
|
|
||||||
pluggy = [
|
|
||||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
|
||||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
|
||||||
]
|
|
||||||
psycopg2-binary = [
|
|
||||||
{file = "psycopg2-binary-2.8.5.tar.gz", hash = "sha256:ccdc6a87f32b491129ada4b87a43b1895cf2c20fdb7f98ad979647506ffc41b6"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:96d3038f5bd061401996614f65d27a4ecb62d843eb4f48e212e6d129171a721f"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:08507efbe532029adee21b8d4c999170a83760d38249936038bd0602327029b5"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:b9a8b391c2b0321e0cd7ec6b4cfcc3dd6349347bd1207d48bcb752aa6c553a66"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27m-win32.whl", hash = "sha256:3286541b9d85a340ee4ed42732d15fc1bb441dc500c97243a768154ab8505bb5"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27m-win_amd64.whl", hash = "sha256:008da3ab51adc70a5f1cfbbe5db3a22607ab030eb44bcecf517ad11a0c2b3cac"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ba13346ff6d3eb2dca0b6fa0d8a9d999eff3dcd9b55f3a890f12b0b6362b2b38"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:c8830b7d5f16fd79d39b21e3d94f247219036b29b30c8270314c46bf8b732389"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp34-cp34m-win32.whl", hash = "sha256:51f7823f1b087d2020d8e8c9e6687473d3d239ba9afc162d9b2ab6e80b53f9f9"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp34-cp34m-win_amd64.whl", hash = "sha256:107d9be3b614e52a192719c6bf32e8813030020ea1d1215daa86ded9a24d8b04"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp35-cp35m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:930315ac53dc65cbf52ab6b6d27422611f5fb461d763c531db229c7e1af6c0b3"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:6bb2dd006a46a4a4ce95201f836194eb6a1e863f69ee5bab506673e0ca767057"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:3939cf75fc89c5e9ed836e228c4a63604dff95ad19aed2bbf71d5d04c15ed5ce"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp35-cp35m-win32.whl", hash = "sha256:a20299ee0ea2f9cca494396ac472d6e636745652a64a418b39522c120fd0a0a4"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp35-cp35m-win_amd64.whl", hash = "sha256:cc30cb900f42c8a246e2cb76539d9726f407330bc244ca7729c41a44e8d807fb"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp36-cp36m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:40abc319f7f26c042a11658bf3dd3b0b3bceccf883ec1c565d5c909a90204434"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:702f09d8f77dc4794651f650828791af82f7c2efd8c91ae79e3d9fe4bb7d4c98"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d1a8b01f6a964fec702d6b6dac1f91f2b9f9fe41b310cbb16c7ef1fac82df06d"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp36-cp36m-win32.whl", hash = "sha256:17a0ea0b0eabf07035e5e0d520dabc7950aeb15a17c6d36128ba99b2721b25b1"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp36-cp36m-win_amd64.whl", hash = "sha256:e004db88e5a75e5fdab1620fb9f90c9598c2a195a594225ac4ed2a6f1c23e162"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp37-cp37m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:a34826d6465c2e2bbe9d0605f944f19d2480589f89863ed5f091943be27c9de4"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:cac918cd7c4c498a60f5d2a61d4f0a6091c2c9490d81bc805c963444032d0dab"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:7b832d76cc65c092abd9505cc670c4e3421fd136fb6ea5b94efbe4c146572505"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp37-cp37m-win32.whl", hash = "sha256:bb0608694a91db1e230b4a314e8ed00ad07ed0c518f9a69b83af2717e31291a3"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp37-cp37m-win_amd64.whl", hash = "sha256:eb2f43ae3037f1ef5e19339c41cf56947021ac892f668765cd65f8ab9814192e"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp38-cp38-macosx_10_9_x86_64.macosx_10_9_intel.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:07cf82c870ec2d2ce94d18e70c13323c89f2f2a2628cbf1feee700630be2519a"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp38-cp38-manylinux1_i686.whl", hash = "sha256:a69970ee896e21db4c57e398646af9edc71c003bc52a3cc77fb150240fefd266"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7036ccf715925251fac969f4da9ad37e4b7e211b1e920860148a10c0de963522"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp38-cp38-win32.whl", hash = "sha256:8f74e631b67482d504d7e9cf364071fc5d54c28e79a093ff402d5f8f81e23bfa"},
|
|
||||||
{file = "psycopg2_binary-2.8.5-cp38-cp38-win_amd64.whl", hash = "sha256:fa466306fcf6b39b8a61d003123d442b23707d635a5cb05ac4e1b62cc79105cd"},
|
|
||||||
]
|
|
||||||
py = [
|
|
||||||
{file = "py-1.9.0-py2.py3-none-any.whl", hash = "sha256:366389d1db726cd2fcfc79732e75410e5fe4d31db13692115529d34069a043c2"},
|
|
||||||
{file = "py-1.9.0.tar.gz", hash = "sha256:9ca6883ce56b4e8da7e79ac18787889fa5206c79dcc67fb065376cd2fe03f342"},
|
|
||||||
]
|
|
||||||
pydantic = [
|
|
||||||
{file = "pydantic-1.6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:418b84654b60e44c0cdd5384294b0e4bc1ebf42d6e873819424f3b78b8690614"},
|
|
||||||
{file = "pydantic-1.6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:4900b8820b687c9a3ed753684337979574df20e6ebe4227381d04b3c3c628f99"},
|
|
||||||
{file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b49c86aecde15cde33835d5d6360e55f5e0067bb7143a8303bf03b872935c75b"},
|
|
||||||
{file = "pydantic-1.6.1-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:2de562a456c4ecdc80cf1a8c3e70c666625f7d02d89a6174ecf63754c734592e"},
|
|
||||||
{file = "pydantic-1.6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f769141ab0abfadf3305d4fcf36660e5cf568a666dd3efab7c3d4782f70946b1"},
|
|
||||||
{file = "pydantic-1.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2dc946b07cf24bee4737ced0ae77e2ea6bc97489ba5a035b603bd1b40ad81f7e"},
|
|
||||||
{file = "pydantic-1.6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:36dbf6f1be212ab37b5fda07667461a9219c956181aa5570a00edfb0acdfe4a1"},
|
|
||||||
{file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:1783c1d927f9e1366e0e0609ae324039b2479a1a282a98ed6a6836c9ed02002c"},
|
|
||||||
{file = "pydantic-1.6.1-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:cf3933c98cb5e808b62fae509f74f209730b180b1e3c3954ee3f7949e083a7df"},
|
|
||||||
{file = "pydantic-1.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:f8af9b840a9074e08c0e6dc93101de84ba95df89b267bf7151d74c553d66833b"},
|
|
||||||
{file = "pydantic-1.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:40d765fa2d31d5be8e29c1794657ad46f5ee583a565c83cea56630d3ae5878b9"},
|
|
||||||
{file = "pydantic-1.6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3fa799f3cfff3e5f536cbd389368fc96a44bb30308f258c94ee76b73bd60531d"},
|
|
||||||
{file = "pydantic-1.6.1-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:6c3f162ba175678218629f446a947e3356415b6b09122dcb364e58c442c645a7"},
|
|
||||||
{file = "pydantic-1.6.1-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:eb75dc1809875d5738df14b6566ccf9fd9c0bcde4f36b72870f318f16b9f5c20"},
|
|
||||||
{file = "pydantic-1.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:530d7222a2786a97bc59ee0e0ebbe23728f82974b1f1ad9a11cd966143410633"},
|
|
||||||
{file = "pydantic-1.6.1-py36.py37.py38-none-any.whl", hash = "sha256:b5b3489cb303d0f41ad4a7390cf606a5f2c7a94dcba20c051cd1c653694cb14d"},
|
|
||||||
{file = "pydantic-1.6.1.tar.gz", hash = "sha256:54122a8ed6b75fe1dd80797f8251ad2063ea348a03b77218d73ea9fe19bd4e73"},
|
|
||||||
]
|
|
||||||
pyexcel = [
|
|
||||||
{file = "pyexcel-0.6.2-py2.py3-none-any.whl", hash = "sha256:c3f918563073f0ef9a0f9e365ded074bd5baa73ef249b2783dc0d4361ed67d8b"},
|
|
||||||
{file = "pyexcel-0.6.2.tar.gz", hash = "sha256:408c67a8a2d62a2d6979a3f8d82d6ca80aa127a4b628d046d13cdbe35666b14a"},
|
|
||||||
]
|
|
||||||
pyexcel-ezodf = [
|
|
||||||
{file = "pyexcel-ezodf-0.3.4.tar.gz", hash = "sha256:972eeea9b0e4bab60dfc5cdcb7378cc7ba5e070a0b7282746c0182c5de011ff1"},
|
|
||||||
{file = "pyexcel_ezodf-0.3.4-py2.py3-none-any.whl", hash = "sha256:a74ac7636a015fff31d35c5350dc5ad347ba98ecb453de4dbcbb9a9168434e8c"},
|
|
||||||
]
|
|
||||||
pyexcel-io = [
|
|
||||||
{file = "pyexcel-io-0.5.20.tar.gz", hash = "sha256:08dfe39553b996359b143de3d9ec43e196f1138d47cabb73af04a16821b84d79"},
|
|
||||||
{file = "pyexcel_io-0.5.20-py2.py3-none-any.whl", hash = "sha256:2cba956814e72b66072d97b00ede4a084ad881ce72129088eb0dc3c7f3d670cd"},
|
|
||||||
]
|
|
||||||
pyexcel-ods = [
|
|
||||||
{file = "pyexcel-ods-0.5.6.tar.gz", hash = "sha256:3be52fd8aaddbd8bc9286f7eb148f4553d4c97252d695c3a9ec7b95e6666a223"},
|
|
||||||
{file = "pyexcel_ods-0.5.6-py2.py3-none-any.whl", hash = "sha256:e8d1137da99599e6053c056c21ca601d90f8e000b4db9db679302bbf55d15c0f"},
|
|
||||||
]
|
|
||||||
pyexcel-ods3 = [
|
|
||||||
{file = "pyexcel-ods3-0.5.3.tar.gz", hash = "sha256:3e5f8687a54a1b50d7327145cf4b777a16d9e074370bb24a1193d22cca312e76"},
|
|
||||||
{file = "pyexcel_ods3-0.5.3-py3-none-any.whl", hash = "sha256:62aa0207ab1074a578d8959bf7d7f7c3710b4bb81423a026d8c03bf0f16b6736"},
|
|
||||||
]
|
|
||||||
pyjwt = [
|
|
||||||
{file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"},
|
|
||||||
{file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"},
|
|
||||||
]
|
|
||||||
pyparsing = [
|
|
||||||
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
|
|
||||||
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
|
|
||||||
]
|
|
||||||
pytest = [
|
|
||||||
{file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
|
|
||||||
{file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
|
|
||||||
]
|
|
||||||
pytest-env = [
|
|
||||||
{file = "pytest-env-0.6.2.tar.gz", hash = "sha256:7e94956aef7f2764f3c147d216ce066bf6c42948bb9e293169b1b1c880a580c2"},
|
|
||||||
]
|
|
||||||
python-dotenv = [
|
|
||||||
{file = "python-dotenv-0.14.0.tar.gz", hash = "sha256:8c10c99a1b25d9a68058a1ad6f90381a62ba68230ca93966882a4dbc3bc9c33d"},
|
|
||||||
{file = "python_dotenv-0.14.0-py2.py3-none-any.whl", hash = "sha256:c10863aee750ad720f4f43436565e4c1698798d763b63234fb5021b6c616e423"},
|
|
||||||
]
|
|
||||||
pyyaml = [
|
|
||||||
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
|
|
||||||
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"},
|
|
||||||
{file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"},
|
|
||||||
{file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"},
|
|
||||||
{file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"},
|
|
||||||
{file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"},
|
|
||||||
{file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"},
|
|
||||||
{file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"},
|
|
||||||
{file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"},
|
|
||||||
{file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"},
|
|
||||||
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
|
|
||||||
]
|
|
||||||
requests = [
|
|
||||||
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
|
|
||||||
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
|
|
||||||
]
|
|
||||||
sidb = []
|
|
||||||
six = [
|
|
||||||
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
|
|
||||||
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
|
|
||||||
]
|
|
||||||
starlette = [
|
|
||||||
{file = "starlette-0.13.4-py3-none-any.whl", hash = "sha256:0fb4b38d22945b46acb880fedee7ee143fd6c0542992501be8c45c0ed737dd1a"},
|
|
||||||
{file = "starlette-0.13.4.tar.gz", hash = "sha256:04fe51d86fd9a594d9b71356ed322ccde5c9b448fc716ac74155e5821a922f8d"},
|
|
||||||
]
|
|
||||||
texttable = [
|
|
||||||
{file = "texttable-1.6.2-py2.py3-none-any.whl", hash = "sha256:7dc282a5b22564fe0fdc1c771382d5dd9a54742047c61558e071c8cd595add86"},
|
|
||||||
{file = "texttable-1.6.2.tar.gz", hash = "sha256:eff3703781fbc7750125f50e10f001195174f13825a92a45e9403037d539b4f4"},
|
|
||||||
]
|
|
||||||
urllib3 = [
|
|
||||||
{file = "urllib3-1.25.9-py2.py3-none-any.whl", hash = "sha256:88206b0eb87e6d677d424843ac5209e3fb9d0190d0ee169599165ec25e9d9115"},
|
|
||||||
{file = "urllib3-1.25.9.tar.gz", hash = "sha256:3018294ebefce6572a474f0604c2021e33b3fd8006ecd11d62107a5d2a963527"},
|
|
||||||
]
|
|
||||||
uvicorn = [
|
|
||||||
{file = "uvicorn-0.11.6-py3-none-any.whl", hash = "sha256:d19a20b17445708fd222e5a7cfc3eacfb31ac269bc8fefa4920833334e199782"},
|
|
||||||
{file = "uvicorn-0.11.6.tar.gz", hash = "sha256:467c333c743ec6a3eb545517a0e3cac603becfa40c73c65ed46c3a4bf1c8e2d0"},
|
|
||||||
]
|
|
||||||
uvloop = [
|
|
||||||
{file = "uvloop-0.14.0-cp35-cp35m-macosx_10_11_x86_64.whl", hash = "sha256:08b109f0213af392150e2fe6f81d33261bb5ce968a288eb698aad4f46eb711bd"},
|
|
||||||
{file = "uvloop-0.14.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:4544dcf77d74f3a84f03dd6278174575c44c67d7165d4c42c71db3fdc3860726"},
|
|
||||||
{file = "uvloop-0.14.0-cp36-cp36m-macosx_10_11_x86_64.whl", hash = "sha256:b4f591aa4b3fa7f32fb51e2ee9fea1b495eb75b0b3c8d0ca52514ad675ae63f7"},
|
|
||||||
{file = "uvloop-0.14.0-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:f07909cd9fc08c52d294b1570bba92186181ca01fe3dc9ffba68955273dd7362"},
|
|
||||||
{file = "uvloop-0.14.0-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:afd5513c0ae414ec71d24f6f123614a80f3d27ca655a4fcf6cabe50994cc1891"},
|
|
||||||
{file = "uvloop-0.14.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:e7514d7a48c063226b7d06617cbb12a14278d4323a065a8d46a7962686ce2e95"},
|
|
||||||
{file = "uvloop-0.14.0-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:bcac356d62edd330080aed082e78d4b580ff260a677508718f88016333e2c9c5"},
|
|
||||||
{file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"},
|
|
||||||
{file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"},
|
|
||||||
]
|
|
||||||
wcwidth = [
|
|
||||||
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
|
||||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
|
||||||
]
|
|
||||||
websockets = [
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:4f9f7d28ce1d8f1295717c2c25b732c2bc0645db3215cf757551c392177d7cb8"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:295359a2cc78736737dd88c343cd0747546b2174b5e1adc223824bcaf3e164cb"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:1d3f1bf059d04a4e0eb4985a887d49195e15ebabc42364f4eb564b1d065793f5"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-win32.whl", hash = "sha256:2db62a9142e88535038a6bcfea70ef9447696ea77891aebb730a333a51ed559a"},
|
|
||||||
{file = "websockets-8.1-cp36-cp36m-win_amd64.whl", hash = "sha256:0e4fb4de42701340bd2353bb2eee45314651caa6ccee80dbd5f5d5978888fed5"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:9b248ba3dd8a03b1a10b19efe7d4f7fa41d158fdaa95e2cf65af5a7b95a4f989"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ce85b06a10fc65e6143518b96d3dca27b081a740bae261c2fb20375801a9d56d"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:965889d9f0e2a75edd81a07592d0ced54daa5b0785f57dc429c378edbcffe779"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:751a556205d8245ff94aeef23546a1113b1dd4f6e4d102ded66c39b99c2ce6c8"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:3ef56fcc7b1ff90de46ccd5a687bbd13a3180132268c4254fc0fa44ecf4fc422"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-win32.whl", hash = "sha256:7ff46d441db78241f4c6c27b3868c9ae71473fe03341340d2dfdbe8d79310acc"},
|
|
||||||
{file = "websockets-8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:20891f0dddade307ffddf593c733a3fdb6b83e6f9eef85908113e628fa5a8308"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c1ec8db4fac31850286b7cd3b9c0e1b944204668b8eb721674916d4e28744092"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5c01fd846263a75bc8a2b9542606927cfad57e7282965d96b93c387622487485"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:9bef37ee224e104a413f0780e29adb3e514a5b698aabe0d969a6ba426b8435d1"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d705f8aeecdf3262379644e4b55107a3b55860eb812b673b28d0fbc347a60c55"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:c8a116feafdb1f84607cb3b14aa1418424ae71fee131642fc568d21423b51824"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-win32.whl", hash = "sha256:e898a0863421650f0bebac8ba40840fc02258ef4714cb7e1fd76b6a6354bda36"},
|
|
||||||
{file = "websockets-8.1-cp38-cp38-win_amd64.whl", hash = "sha256:f8a7bff6e8664afc4e6c28b983845c5bc14965030e3fb98789734d416af77c4b"},
|
|
||||||
{file = "websockets-8.1.tar.gz", hash = "sha256:5c65d2da8c6bce0fca2528f69f44b2f977e06954c8512a952222cea50dad430f"},
|
|
||||||
]
|
|
||||||
zipp = [
|
|
||||||
{file = "zipp-3.1.0-py3-none-any.whl", hash = "sha256:aa36550ff0c0b7ef7fa639055d797116ee891440eac1a56f378e2d3179e0320b"},
|
|
||||||
{file = "zipp-3.1.0.tar.gz", hash = "sha256:c599e4d75c98f6798c509911d08a22e6c021d074469042177c8c86fb92eefd96"},
|
|
||||||
]
|
|
|
@ -1,35 +0,0 @@
|
||||||
[tool.poetry]
|
|
||||||
name = "halfapi"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "The core module for an halfORM API"
|
|
||||||
authors = ["Joël Maizi <joel.maizi@lirmm.fr>", "Maxime Alves <maxime.alves@lirmm.fr>"]
|
|
||||||
homepage = "https://gite.lirmm.fr/newsi/api/halfapi"
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
click = "^7"
|
|
||||||
half-orm = { git = "git@gite.lirmm.fr:newsi/halfORM.git" }
|
|
||||||
PyJWT = "^1"
|
|
||||||
python = "^3.7"
|
|
||||||
starlette = "^0"
|
|
||||||
uvicorn = { version = "^0" }
|
|
||||||
apidb = { git = "git@gite.lirmm.fr:newsi/db/hop_api.git" }
|
|
||||||
fastapi = { version = "^0", optional = true }
|
|
||||||
organigramme = { git = "git@gite.lirmm.fr:newsi/api/organigramme.git", optional = true }
|
|
||||||
sidb = { git = "git@gite.lirmm.fr:newsi/sidb_halfORM.git", optional = true }
|
|
||||||
python-dotenv = "^0.14.0"
|
|
||||||
pyexcel-ods3 = { version = "^0.5.3", optional = true }
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
|
||||||
pytest = "^5"
|
|
||||||
requests = "^2"
|
|
||||||
pytest-env = "^0.6.2"
|
|
||||||
|
|
||||||
[tool.poetry.extras]
|
|
||||||
organigramme = [ "fastapi", "organigramme", "sidb", "pyexcel-ods3" ]
|
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
|
||||||
halfapi = 'halfapi.cli:cli'
|
|
||||||
[build-system]
|
|
||||||
requires = ["poetry>=0.12"]
|
|
||||||
build-backend = "poetry.masonry.api"
|
|
||||||
|
|
|
@ -2,4 +2,3 @@ starlette
|
||||||
uvicorn
|
uvicorn
|
||||||
jwt
|
jwt
|
||||||
half_orm @ git+ssh://git@gite.lirmm.fr/newsi/halfORM.git
|
half_orm @ git+ssh://git@gite.lirmm.fr/newsi/halfORM.git
|
||||||
organigramme @ git+ssh://git@gite.lirmm.fr/api/newsi/halfapi.git
|
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
|
def get_version(package):
|
||||||
|
"""
|
||||||
|
Return package version as listed in `__version__` in `init.py`.
|
||||||
|
"""
|
||||||
|
with open(os.path.join(package, "__init__.py")) as f:
|
||||||
|
return re.search("__version__ = ['\"]([^'\"]+)['\"]", f.read()).group(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_long_description():
|
||||||
|
"""
|
||||||
|
Return the README.
|
||||||
|
"""
|
||||||
|
with open("README.md", encoding="utf8") as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
|
def get_packages(package):
|
||||||
|
"""
|
||||||
|
Return root package and all sub-packages.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
dirpath
|
||||||
|
for dirpath, dirnames, filenames in os.walk(package)
|
||||||
|
if os.path.exists(os.path.join(dirpath, "__init__.py"))
|
||||||
|
]
|
||||||
|
|
||||||
|
module_name="halfapi"
|
||||||
|
setup(
|
||||||
|
name=module_name,
|
||||||
|
python_requires=">=3.7",
|
||||||
|
version=get_version(module_name),
|
||||||
|
url="https://gite.lirmm.fr/newsi/api/halfapi",
|
||||||
|
long_description=get_long_description(),
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
packages=get_packages(module_name),
|
||||||
|
package_data={
|
||||||
|
'halfapi': ['lib/*', 'models/*']
|
||||||
|
},
|
||||||
|
install_requires=[
|
||||||
|
"click",
|
||||||
|
"half_orm",
|
||||||
|
"jwt",
|
||||||
|
"starlette",
|
||||||
|
"uvicorn"],
|
||||||
|
extras_require={
|
||||||
|
"tests":["pytest", "requests"],
|
||||||
|
},
|
||||||
|
entry_points={
|
||||||
|
"console_scripts":[
|
||||||
|
"halfapi=halfapi.cli:cli"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
Loading…
Reference in New Issue