[lib.schemas] router schema update

This commit is contained in:
Maxime Alves LIRMM@home 2021-12-01 13:07:01 +01:00
parent 238bd99bd3
commit 1ccfa0d10e
5 changed files with 87 additions and 36 deletions

View File

@ -99,3 +99,10 @@ def args_check(fct):
return await fct(req, *args, **kwargs) return await fct(req, *args, **kwargs)
return caller return caller
# ACLS list for doc and priorities
# Write your own constant in your domain or import this one
ACLS = (
('private', public.__doc__, 0),
('public', public.__doc__, 999)
)

View File

@ -1,17 +1,28 @@
import re import re
from schema import Schema, Optional from schema import Schema, Optional, Or
from .. import __version__ from .. import __version__
VERBS = ('GET', 'POST', 'PUT', 'PATCH', 'DELETE') VERBS = ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')
ITERABLE_STR = Or([ str ], { str }, ( str ))
ACLS_SCHEMA = Schema([{ ACLS_SCHEMA = Schema([{
'acl': str, 'acl': str,
Optional('args'): { Optional('args'): {
Optional('required'): [ str ], Optional('required'): ITERABLE_STR,
Optional('optional'): [ str ] Optional('optional'): ITERABLE_STR
}, },
Optional('out'): [ str ] Optional('out'): ITERABLE_STR
}]) }])
ROUTER_ACLS_SCHEMA = Schema([{
'acl': lambda n: callable(n),
Optional('args'): {
Optional('required'): ITERABLE_STR,
Optional('optional'): ITERABLE_STR
},
Optional('out'): ITERABLE_STR
}])
is_callable_dotted_notation = lambda x: re.match( is_callable_dotted_notation = lambda x: re.match(
r'^(([a-zA-Z_])+\.?)*:[a-zA-Z_]+$', 'ab_c.TEST:get') r'^(([a-zA-Z_])+\.?)*:[a-zA-Z_]+$', 'ab_c.TEST:get')
@ -48,3 +59,11 @@ API_SCHEMA = Schema({
'domain': DOMAIN_SCHEMA, 'domain': DOMAIN_SCHEMA,
'paths': ROUTE_SCHEMA 'paths': ROUTE_SCHEMA
}) })
ROUTER_SCHEMA = Schema({
Or('', str): {
# Optional('GET'): [],#ACLS_SCHEMA,
Optional(Or(*VERBS)): ROUTER_ACLS_SCHEMA,
Optional('SUBROUTES'): [Optional(str)]
}
})

View File

@ -1,44 +1,71 @@
import os import os
import sys
import subprocess
from types import ModuleType from types import ModuleType
from typing import Dict from typing import Dict
from pprint import pprint
from halfapi.lib.constants import VERBS from schema import SchemaError
from .constants import VERBS, ROUTER_SCHEMA
from ..logging import logger
def read_router(m_router: ModuleType) -> Dict: def read_router(m_router: ModuleType) -> Dict:
""" """
Reads a module and returns a router dict Reads a module and returns a router dict
If the module has a "ROUTES" constant, it just returns this constant,
Else, if the module has an "ACLS" constant, it builds the accurate dict
TODO: May be another thing, may be not a part of halfAPI
""" """
m_path = None
if not hasattr(m_router, 'ROUTES'): try:
routes = {'':{}} if not hasattr(m_router, 'ROUTES'):
acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None routes = {'':{}}
acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None
if acls is not None: if acls is not None:
for verb in VERBS: for verb in VERBS:
if not hasattr(m_router, verb.lower()): if not hasattr(m_router, verb.lower()):
continue # verb in function names are lowercase
continue
""" There is a "verb" route in the router """ There is a "verb" route in the router
"""
if verb.upper() not in acls:
continue
routes[''][verb.upper()] = []
routes[''][verb.upper()] = acls[verb.upper()].copy()
routes['']['SUBROUTES'] = []
if hasattr(m_router, '__path__'):
""" Module is a package
""" """
m_path = getattr(m_router, '__path__')
if isinstance(m_path, list) and len(m_path) == 1:
routes['']['SUBROUTES'] = [
elt.name
for elt in os.scandir(m_path[0])
if elt.is_dir()
]
else:
routes = getattr(m_router, 'ROUTES')
if verb.upper() not in acls: try:
continue ROUTER_SCHEMA.validate(routes)
except SchemaError as exc:
logger.error(routes)
raise exc
routes[''][verb.upper()] = [] return routes
routes[''][verb.upper()] = acls[verb.upper()].copy() except ImportError as exc:
# TODO: Proper exception handling
routes['']['SUBROUTES'] = [] raise exc
if hasattr(m_router, '__path__'): except FileNotFoundError as exc:
""" Module is a package # TODO: Proper exception handling
""" logger.error(m_path)
m_path = getattr(m_router, '__path__') raise exc
if isinstance(m_path, list) and len(m_path) == 1:
routes['']['SUBROUTES'] = [
elt.name
for elt in os.scandir(m_path[0])
if elt.is_dir()
]
else:
routes = getattr(m_router, 'ROUTES')
return routes

View File

@ -48,8 +48,6 @@ def JSONRoute(data: Any) -> Coroutine:
return wrapped return wrapped
def gen_domain_routes(m_domain: ModuleType): def gen_domain_routes(m_domain: ModuleType):
""" """
Yields the Route objects for a domain Yields the Route objects for a domain

View File

@ -16,7 +16,7 @@ ROUTES = {
'acl': acl.public, 'acl': acl.public,
'args': { 'args': {
'required': {'foo', 'bar'}, 'required': {'foo', 'bar'},
'optional': {} 'optional': set()
} }
}] }]
}, },