Skip to content
Snippets Groups Projects
Commit f2110de4 authored by Matthias Stefan Bodenbenner's avatar Matthias Stefan Bodenbenner
Browse files

added query parameter to choose response data format

parent 45aea013
No related branches found
No related tags found
No related merge requests found
[![Build](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/lava/unified-device-interface/python/badges/master/pipeline.svg)](https://git-ce.rwth-aachen.de/wzl-mq-ms/forschung-lehre/lava/unified-device-interface/python/commits/master)
# Python Unified Device Interface
Current stable version: 8.0.1
Current stable version: 8.1.0
Stable legacy version: 5.2.7 **SHOULD NOT BE USED ANYMORE!**
## Installation
......@@ -65,6 +65,11 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation)
## Recent changes
**8.1.0** - 2023-03-15
- the desired dataformat of the response can be specified with a query parameter now, e.g.,
- ../MEA-Temperature?format=json
- ../MEA-Temperature?format=xml
**8.0.1** - 2023-03-14
- bug fixes
- fixed DELETE endpoint for dynamic components
......
from setuptools import setup, find_packages
setup(name='wzl-udi',
version='8.0.1',
version='8.1.0',
url='https://git-ce.rwth-aachen.de/wzl-mq-public/soil/python',
author='Matthias Bodenbenner',
author_email='m.bodenbenner@wzl.mq.rwth-aachen.de',
......
......@@ -7,6 +7,7 @@ from typing import Dict
from aiohttp import web
from aiohttp.web import middleware
from aiohttp.web_request import Request
from multidict import MultiDict
from wzl.utilities import root_logger
from .error import ServerException
......@@ -113,10 +114,22 @@ class HTTPServer(object):
uuid_list.remove('')
return uuid_list
def prepare_response(self, body: Dict, element: Element, status: int = 200):
if self._dataformat == 'json':
def _filter_query(self, query: MultiDict):
queried_attributes = []
for key in query:
if key in ['uuid', 'name', 'description', 'datatype', 'range', 'value', 'constant', 'timestamp',
'dimension', 'unit', 'covariance', 'label', 'children', 'arguments', 'returns', 'ontology']:
queried_attributes += [key]
return queried_attributes
def prepare_response(self, body: Dict, element: Element, status: int = 200, query: MultiDict = None):
dataformat = self._dataformat
if query is not None and 'format' in query and query['format'] in ['json', 'xml']:
dataformat = query['format']
if dataformat == 'json':
return web.json_response(body, status=status)
elif self._dataformat == 'xml':
elif dataformat == 'xml':
if element is not None and 200 <= status <= 300:
root = ''
if isinstance(element, Component):
......@@ -136,6 +149,7 @@ class HTTPServer(object):
logger.info("GET Request from {}".format(request.url))
logger.debug('Request: {}'.format(request))
logger.debug('Query Parameters: {}'.format(request.query_string))
keys = self._filter_query(request.query)
try:
item = self.root[HTTPServer.parse_uuids(request)]
......@@ -143,12 +157,8 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if request.query_string == "":
keys = []
else:
keys = [x.split('=')[0] for x in request.query_string.split('&')]
try:
response = item.serialize(keys, self._legacy_mode, HTTP_GET)
status = 200
......@@ -158,7 +168,7 @@ class HTTPServer(object):
response = {'error': str(e)}
status = 500
logger.error('Response: {}'.format(response))
return self.prepare_response(response, item, status=status)
return self.prepare_response(response, item, status=status, query=request.query)
async def post(self, request):
logger.info("POST Request from {}".format(request.url))
......@@ -173,7 +183,7 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if isinstance(item, Function):
try:
......@@ -189,7 +199,7 @@ class HTTPServer(object):
response, status = {}, 405
logger.error('Response: {}'.format(response))
return self.prepare_response(response, item, status=status)
return self.prepare_response(response, item, status=status, query=request.query)
async def delete(self, request):
logger.info("DELETE Request from {}".format(request.url))
......@@ -202,12 +212,12 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if not isinstance(item, Component):
return self.prepare_response({}, None, status=405)
return self.prepare_response({}, None, status=405, query=request.query)
try:
component_name = await self.loop.run_in_executor(None, functools.partial(item.remove, uuids[-1]))
await self.loop.run_in_executor(None, functools.partial(item.remove, uuids[-1]))
if self._scheduler is not None:
self._scheduler.remove_jobs('/'.join(uuids))
......@@ -223,12 +233,13 @@ class HTTPServer(object):
response = {'error': str(e)}
status = 500
logger.error('Response: {}'.format(response))
return self.prepare_response(response, item, status=status)
return self.prepare_response(response, item, status=status, query=request.query)
async def options(self, request):
logger.info("HEAD Request from {}".format(request.url))
logger.debug('Request: {}'.format(request))
logger.debug('Query Parameters: {}'.format(request.query_string))
keys = self._filter_query(request.query)
try:
item = self.root[HTTPServer.parse_uuids(request)]
......@@ -236,18 +247,14 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if not isinstance(item, Figure):
return self.prepare_response({}, None, status=405)
return self.prepare_response({}, None, status=405, query=request.query)
if request.query_string == "":
keys = []
else:
keys = [x.split('=')[0] for x in request.query_string.split('&')]
response = item.serialize(keys, self._legacy_mode, HTTP_OPTIONS)
logger.info('Response: {}'.format(response))
return self.prepare_response(response, item)
return self.prepare_response(response, item, query=request.query)
async def patch(self, request):
logger.info("PATCH Request from {}".format(request.url))
......@@ -261,7 +268,7 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if isinstance(item, Parameter):
try:
......@@ -281,7 +288,7 @@ class HTTPServer(object):
else:
response, status = {}, 405
logger.error('Response: {}'.format(response))
return self.prepare_response(response, item, status=status)
return self.prepare_response(response, item, status=status, query=request.query)
async def put(self, request):
logger.info("PUT Request from {}".format(request.url))
......@@ -296,10 +303,10 @@ class HTTPServer(object):
logger.error(traceback.format_exc())
response = {'error': str(e)}
logger.error('Response: {}'.format(response))
return self.prepare_response(response, None, status=404)
return self.prepare_response(response, None, status=404, query=request.query)
if not isinstance(item, Component):
return self.prepare_response({}, None, status=405)
return self.prepare_response({}, None, status=405, query=request.query)
try:
implementation = await self.loop.run_in_executor(None,
functools.partial(item.add, uuids[-1], data['class_name'],
......@@ -315,4 +322,4 @@ class HTTPServer(object):
response = {'error': str(e)}
status = 500
logger.error('Response: {}'.format(response))
return self.prepare_response(response, item, status=status)
return self.prepare_response(response, item, status=status, query=request.query)
......@@ -58,8 +58,8 @@ class Parameter(Figure):
:param method: ???
:return: the value of the attribute indicated by 'item'.
"""
if item == "edit":
return self._setter is not None
if item == "constant":
return self._setter is None
return super().__getitem__(item, method)
def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
......@@ -71,7 +71,7 @@ class Parameter(Figure):
"""
# list is empty provide all attributes of the default-serialization
if not keys:
keys = ['uuid', 'name', 'description', 'datatype', 'value', 'dimension', 'range', 'edit', 'ontology']
keys = ['uuid', 'name', 'description', 'datatype', 'value', 'dimension', 'range', 'constant', 'ontology']
# get all attribute values
dictionary = {}
for key in keys:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment