[wip][responses] allow to change return format with "format" route argument, add ODSResponse

This commit is contained in:
Maxime Alves LIRMM@home 2021-12-01 21:16:19 +01:00
parent 20cada4fa0
commit a8e5cfc0ff
2 changed files with 68 additions and 27 deletions

View File

@ -17,7 +17,7 @@ import yaml
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from halfapi.lib import acl from halfapi.lib import acl
from halfapi.lib.responses import ORJSONResponse from halfapi.lib.responses import ORJSONResponse, ODSResponse
from halfapi.lib.router import read_router from halfapi.lib.router import read_router
from halfapi.lib.constants import VERBS from halfapi.lib.constants import VERBS
@ -46,7 +46,6 @@ class NoDomainsException(Exception):
def route_decorator(fct: FunctionType, ret_type: str = 'json') -> Coroutine: def route_decorator(fct: FunctionType, ret_type: str = 'json') -> Coroutine:
""" Returns an async function that can be mounted on a router """ Returns an async function that can be mounted on a router
""" """
if ret_type == 'json':
@wraps(fct) @wraps(fct)
@acl.args_check @acl.args_check
async def wrapped(request, *args, **kwargs): async def wrapped(request, *args, **kwargs):
@ -66,8 +65,22 @@ def route_decorator(fct: FunctionType, ret_type: str = 'json') -> Coroutine:
if 'data' in fct_args_spec: if 'data' in fct_args_spec:
fct_args['data'] = kwargs.get('data') fct_args['data'] = kwargs.get('data')
""" If format argument is specified (either by get or by post param)
"""
ret_type = fct_args.get('data', {}).get('format', 'json')
try: try:
if ret_type == 'json':
return ORJSONResponse(fct(**fct_args)) return ORJSONResponse(fct(**fct_args))
elif ret_type == 'ods':
res = fct(**fct_args)
assert isinstance(res, list)
for elt in res:
assert isinstance(elt, dict)
return ODSResponse(res)
else:
raise NotImplementedError
except NotImplementedError as exc: except NotImplementedError as exc:
raise HTTPException(501) from exc raise HTTPException(501) from exc
except Exception as exc: except Exception as exc:
@ -76,10 +89,6 @@ def route_decorator(fct: FunctionType, ret_type: str = 'json') -> Coroutine:
raise HTTPException(500) from exc raise HTTPException(500) from exc
raise exc raise exc
else:
raise Exception('Return type not available')
return wrapped return wrapped

View File

@ -13,10 +13,13 @@ Classes :
- PlainTextResponse - PlainTextResponse
- ServiceUnavailableResponse - ServiceUnavailableResponse
- UnauthorizedResponse - UnauthorizedResponse
- ODSResponse
""" """
from datetime import date
import decimal import decimal
import typing import typing
from io import BytesIO
import orjson import orjson
# asgi framework # asgi framework
@ -110,3 +113,32 @@ class HJSONResponse(ORJSONResponse):
""" """
def render(self, content: typing.Generator): def render(self, content: typing.Generator):
return super().render(list(content)) return super().render(list(content))
class ODSResponse(Response):
def __init__(self, d_rows: typing.List[typing.Dict]):
try:
import pyexcel as pe
except ImportError:
""" ODSResponse is not handled
"""
super().__init__(content=
'pyexcel is not installed, ods format not available'
)
return
with BytesIO() as ods_file:
# rows.insert(0, rownames)
self.sheet = pe.Sheet(d_rows)
self.sheet.save_to_memory(
file_type='ods',
stream=ods_file)
filename = f'{date.today()}.ods'
super().__init__(
content=ods_file.getvalue(),
headers={
'Content-Type': 'application/vnd.oasis.opendocument.spreadsheet; charset=UTF-8',
'Content-Disposition': f'attachment; filename="{filename}"'},
status_code = 200)