[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,14 +1,27 @@
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
try:
if not hasattr(m_router, 'ROUTES'): if not hasattr(m_router, 'ROUTES'):
routes = {'':{}} routes = {'':{}}
acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None acls = getattr(m_router, 'ACLS') if hasattr(m_router, 'ACLS') else None
@ -16,6 +29,7 @@ def read_router(m_router: ModuleType) -> Dict:
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()):
# verb in function names are lowercase
continue continue
""" There is a "verb" route in the router """ There is a "verb" route in the router
@ -41,4 +55,17 @@ def read_router(m_router: ModuleType) -> Dict:
else: else:
routes = getattr(m_router, 'ROUTES') routes = getattr(m_router, 'ROUTES')
try:
ROUTER_SCHEMA.validate(routes)
except SchemaError as exc:
logger.error(routes)
raise exc
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 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()
} }
}] }]
}, },