[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 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
from schema import Schema, Optional
from schema import Schema, Optional, Or
from .. import __version__
VERBS = ('GET', 'POST', 'PUT', 'PATCH', 'DELETE')
ITERABLE_STR = Or([ str ], { str }, ( str ))
ACLS_SCHEMA = Schema([{
'acl': str,
Optional('args'): {
Optional('required'): [ str ],
Optional('optional'): [ str ]
Optional('required'): ITERABLE_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(
r'^(([a-zA-Z_])+\.?)*:[a-zA-Z_]+$', 'ab_c.TEST:get')
@ -48,3 +59,11 @@ API_SCHEMA = Schema({
'domain': DOMAIN_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 sys
import subprocess
from types import ModuleType
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:
"""
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'):
routes = {'':{}}
acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None
try:
if not hasattr(m_router, 'ROUTES'):
routes = {'':{}}
acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None
if acls is not None:
for verb in VERBS:
if not hasattr(m_router, verb.lower()):
continue
if acls is not None:
for verb in VERBS:
if not hasattr(m_router, verb.lower()):
# 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:
continue
try:
ROUTER_SCHEMA.validate(routes)
except SchemaError as exc:
logger.error(routes)
raise exc
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')
return routes
return routes
except ImportError as exc:
# TODO: Proper exception handling
raise exc
except FileNotFoundError as exc:
# TODO: Proper exception handling
logger.error(m_path)
raise exc

View File

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

View File

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