231 lines
6.4 KiB
Python
231 lines
6.4 KiB
Python
from collections import namedtuple
|
|
from typing import Tuple, Optional, Type
|
|
|
|
from biopro.util.json import *
|
|
|
|
RouterRule = namedtuple('RouterRule',
|
|
('path',
|
|
'method',
|
|
'func_name',
|
|
'func_para',
|
|
'cookie'))
|
|
|
|
|
|
class RouterHandle:
|
|
|
|
def __init__(self):
|
|
self.rule: List[RouterRule] = []
|
|
|
|
def append_rule(self,
|
|
path: str,
|
|
method: str,
|
|
name: str,
|
|
para: Dict[str, str],
|
|
cookie: Optional[Dict[str, str]] = None) -> RouterRule:
|
|
ret = RouterRule(path, method, name, para, cookie)
|
|
self.rule.append(ret)
|
|
return ret
|
|
|
|
def append_doc(self, path: str, method: str, doc: Optional[str]) -> Optional[str]:
|
|
if doc is None:
|
|
return doc
|
|
|
|
doc_line: List[str] = doc.split('\n')
|
|
|
|
for i, line in enumerate(doc_line):
|
|
if '**Request Url**' in line:
|
|
break
|
|
|
|
else:
|
|
return
|
|
|
|
leading = line[:len(line) - len(line.lstrip())]
|
|
|
|
doc_line.insert(i + 2, leading + '* ``' + method + '`` : ``' + path + '``')
|
|
doc_line.insert(i + 3, '')
|
|
|
|
return '\n'.join(doc_line)
|
|
|
|
def append_cookie_doc(self, doc: Optional[str], cookie: Tuple[str, ...]) -> Optional[str]:
|
|
if doc is None:
|
|
return doc
|
|
|
|
doc_line: List[str] = doc.split('\n')
|
|
|
|
for i, line in enumerate(doc_line):
|
|
if '**Used Cookie**' in line:
|
|
break
|
|
|
|
else:
|
|
return
|
|
|
|
leading = line[:len(line) - len(line.lstrip())]
|
|
|
|
doc_line.insert(i + 2, '')
|
|
|
|
for j, c in enumerate(cookie):
|
|
doc_line.insert(i + 2 + j, leading + '* ``' + c + '`` ')
|
|
|
|
return '\n'.join(doc_line)
|
|
|
|
|
|
# noinspection PyPep8Naming
|
|
def router(path: str,
|
|
GET: Dict[str, str] = None,
|
|
PUT: Dict[str, str] = None,
|
|
POST: Dict[str, str] = None,
|
|
DEL: Dict[str, str] = None,
|
|
COOKIE: Tuple[str, ...] = None):
|
|
"""**decorator** router mapper.
|
|
|
|
*method declaration*
|
|
|
|
for simplest GET mapping ::
|
|
|
|
@router('hello')
|
|
def hello(self):
|
|
\"""hello document
|
|
\"""
|
|
return 'hello'
|
|
|
|
# localhost/hello -> hello
|
|
|
|
for GET mapping with parameter in path ::
|
|
|
|
@router('hello/<str:name>')
|
|
def hello(self, name: str):
|
|
return 'hello ' + name
|
|
|
|
# localhost/hello/world -> hello world
|
|
|
|
for GET mapping with default parameter::
|
|
|
|
@router('hello/', GET=dict(name='guest'))
|
|
@router('hello/<str:name>')
|
|
def hello(self, name: str):
|
|
return 'hello ' + name
|
|
|
|
# localhost/hello -> hello guest
|
|
# localhost/hello/world -> hello world
|
|
|
|
for GET and POST mapping with restrict parameter in options. ::
|
|
|
|
@router('hello')
|
|
def hello(self, *, name: str = 'guest'):
|
|
return 'hello ' + name
|
|
|
|
# localhost/hello?name=world -> hello world
|
|
|
|
for GET and POST mapping with wired parameter in options. ::
|
|
|
|
@router('hello/')
|
|
def hello(self, **options: str):
|
|
return 'hello ' + str(options)
|
|
|
|
# localhost/hello?name=world -> hello {'name': 'world'}
|
|
|
|
for other mapping ::
|
|
|
|
@router('hello/',
|
|
GET=dict(name='get'),
|
|
PUT=dict(name='put'),
|
|
POST=dict(name='post'),
|
|
DEL=dict(name='delete'))
|
|
def hello(self, name: str):
|
|
return 'hello ' + name
|
|
|
|
for request body (for PUT, POST, DEL) ::
|
|
|
|
@router('hello/', PUT={})
|
|
def hello(self, content: str):
|
|
return 'hello ' + content
|
|
|
|
for cookie use ::
|
|
|
|
@router('hello', COOKIE=('user_session',))
|
|
def hello(self, *, user_session: Optional[str]):
|
|
return 'hello ' + str(user_session)
|
|
|
|
for cookie use and set ::
|
|
|
|
@router('hello', COOKIE=('user_session',))
|
|
def hello(self, *, user_session: Optional[str]):
|
|
if user_session is None:
|
|
user_session = 'guest'
|
|
|
|
response = ComplexResponse('hello ' + str(user_session))
|
|
response.set_cookie(user_session=user_session)
|
|
|
|
return response
|
|
|
|
|
|
*method document field*
|
|
|
|
* ``**Request Url**``
|
|
* ``**Request Body**``
|
|
* ``**Response Specification**``
|
|
* ``**Used Cookie**``
|
|
|
|
*special cookie*
|
|
|
|
* ``user_session``
|
|
|
|
:param path: router path
|
|
:param GET: method GET options
|
|
:param PUT: method PUT options
|
|
:param POST: method POST options
|
|
:param DEL: method DELETE options
|
|
:param COOKIE: cookie map
|
|
"""
|
|
|
|
def inner(f):
|
|
h = getattr(f, '_bps_router_', None)
|
|
|
|
if h is None:
|
|
h = RouterHandle()
|
|
setattr(f, '_bps_router_', h)
|
|
|
|
if GET is None and PUT is None and POST is None and DEL is None:
|
|
h.append_rule(path, 'GET', f.__name__, {}, COOKIE)
|
|
f.__doc__ = h.append_doc(path, 'GET', f.__doc__)
|
|
|
|
else:
|
|
if DEL is not None:
|
|
h.append_rule(path, 'DELETE', f.__name__, DEL, COOKIE)
|
|
f.__doc__ = h.append_doc(path, 'DELETE', f.__doc__)
|
|
|
|
if POST is not None:
|
|
h.append_rule(path, 'POST', f.__name__, POST, COOKIE)
|
|
f.__doc__ = h.append_doc(path, 'POST', f.__doc__)
|
|
|
|
if PUT is not None:
|
|
h.append_rule(path, 'PUT', f.__name__, PUT, COOKIE)
|
|
f.__doc__ = h.append_doc(path, 'PUT', f.__doc__)
|
|
|
|
if GET is not None:
|
|
h.append_rule(path, 'GET', f.__name__, GET, COOKIE)
|
|
f.__doc__ = h.append_doc(path, 'GET', f.__doc__)
|
|
|
|
if COOKIE is not None:
|
|
f.__doc__ = h.append_cookie_doc(f.__doc__, COOKIE)
|
|
|
|
return f
|
|
|
|
return inner
|
|
|
|
|
|
class Router(type):
|
|
def __new__(mcs, define_class_name: str, super_class: Tuple[Type, ...], class_attr: Dict[str, Any]):
|
|
router = []
|
|
|
|
for attr_name, attr_value in class_attr.items():
|
|
if callable(attr_value):
|
|
router_handle: RouterHandle = getattr(attr_value, '_bps_router_', None)
|
|
|
|
if router_handle is not None:
|
|
router.extend(router_handle.rule)
|
|
|
|
class_attr['_bps_router_rules_'] = router
|
|
|
|
return type(define_class_name, super_class, class_attr)
|