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

added flag to enable legacy mode for datatype identification

parent e4069a14
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: 7.0.0
Stable legacy version: 5.2.7
Current stable version: 7.1.0
Stable legacy version: 5.2.7 **SHOULD NOT BE USED ANYMORE!**
## Installation
1. Install the *WZL-Utilities* dependency via pip
......@@ -65,6 +65,11 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation)
## Recent changes
**7.1.0** - 2023-02-27
- added legacy flag as server parameter (default: false)
- if set, datatypes are serialized to the old string representation, i.e. "bool" instead of "boolean", and "double" instead of float
**7.0.2** - 2023-02-23
- fixed a bug in update-streams for non-scalar variables
......
from setuptools import setup, find_packages
setup(name='wzl-udi',
version='7.0.2',
version='7.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',
......
......@@ -57,7 +57,7 @@ class HTTPServer(object):
"""
def __init__(self, loop: asyncio.ProactorEventLoop, host: str, port: int, model: Component,
dataformat: str = 'json'):
dataformat: str = 'json', legacy_mode=False):
"""Constructor
Args:
......@@ -66,6 +66,7 @@ class HTTPServer(object):
port: Port the server should run at.
model: The root component of the SOIL model, should be initialized via Component.load(...)
dataformat: String specifying the dataformat of the responses of the server, either 'json' (default) or 'xml'.
legacy_mode: If true, the datatypes are serialized to "bool" and "float" (instead of "boolean" and "float").
"""
if dataformat not in ['json', 'xml']:
raise ValueError('Dataformat must be one of "json" or "xml".')
......@@ -75,6 +76,7 @@ class HTTPServer(object):
self.port = port
self.root = model
self._dataformat = dataformat
self._legacy_mode = legacy_mode
self.app = web.Application(loop=self.loop, middlewares=[cors])
......@@ -147,7 +149,7 @@ class HTTPServer(object):
else:
keys = [x.split('=')[0] for x in request.query_string.split('&')]
try:
response = item.serialize(keys, HTTP_GET)
response = item.serialize(keys, self._legacy_mode, HTTP_GET)
status = 200
logger.info('Response: {}'.format(response))
except (DeviceException, ServerException, UserException) as e:
......@@ -241,7 +243,7 @@ class HTTPServer(object):
keys = []
else:
keys = [x.split('=')[0] for x in request.query_string.split('&')]
response = item.serialize(keys, HTTP_OPTIONS)
response = item.serialize(keys, self._legacy_mode, HTTP_OPTIONS)
logger.info('Response: {}'.format(response))
return self.prepare_response(response, item)
......
......@@ -177,7 +177,7 @@ class Component(Element):
else:
super().__setitem__(key, value)
def serialize(self, keys: List[Any] = None, method: int = HTTP_GET) -> Dict[str, Any]:
def serialize(self, keys: List[Any] = None, legacy_mode: bool = False, method: int = HTTP_GET) -> Dict[str, Any]:
"""Serializes the component and all of it's data to a dictionary.
Calls the serialize method from all children recursively.
......@@ -197,17 +197,17 @@ class Component(Element):
keys = ['uuid', 'name', 'description', 'children', 'ontology']
if 'all' in keys: # serialize complete tree recursively (overrides all other keys)
dictionary = super().serialize([])
dictionary['measurements'] = list(map(lambda x: x.serialize([]), self._measurements))
dictionary['functions'] = list(map(lambda x: x.serialize(['all']), self._functions))
dictionary['components'] = list(map(lambda x: x.serialize(['all']), self._components))
dictionary['parameters'] = list(map(lambda x: x.serialize(['all']), self._parameters))
dictionary = super().serialize([], legacy_mode)
dictionary['measurements'] = list(map(lambda x: x.serialize([], legacy_mode), self._measurements))
dictionary['functions'] = list(map(lambda x: x.serialize(['all'], legacy_mode), self._functions))
dictionary['components'] = list(map(lambda x: x.serialize(['all'], legacy_mode), self._components))
dictionary['parameters'] = list(map(lambda x: x.serialize(['all'], legacy_mode), self._parameters))
return dictionary
dictionary = super().serialize(keys, method)
dictionary = super().serialize(keys, legacy_mode, method)
if 'children' in keys:
everything = self._components + self._measurements + self._parameters + self._functions
dictionary['children'] = list(map(lambda x: x.serialize(['name', 'uuid']), everything))
dictionary['children'] = list(map(lambda x: x.serialize(['name', 'uuid'], legacy_mode), everything))
return dictionary
@staticmethod
......
......@@ -27,6 +27,8 @@ class Datatype(enum.Enum):
return cls.ENUM
raise TypeException("Unknown type descriptor: {}".format(datatype))
def to_string(self) -> str:
def to_string(self, legacy_mode: bool = False) -> str:
if legacy_mode:
return ["bool", "int", "double", "string", "time", "enum"][self.value]
return ["boolean", "int", "float", "string", "time", "enum"][self.value]
......@@ -64,7 +64,7 @@ class Element(ABC):
raise KeyError(
"{}: Key error. No attribute is named '{}' or it should not be changed".format(self.uuid, key))
def serialize(self, keys: List[str], method: int = HTTP_GET) -> Dict:
def serialize(self, keys: List[str], legacy_mode: bool, method: int = HTTP_GET) -> Dict:
res = {'uuid': self._uuid}
for key in keys:
res[key] = self.__getitem__(key, method)
......
......@@ -118,7 +118,7 @@ class Figure(Element, ABC):
# """
# super().__setitem__(key, value)
def serialize(self, keys: [str], method=HTTP_GET):
def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
"""
Serializes an object of type Figure into a JSON-like dictionary.
:param keys: All attributes given in the "keys" array are serialized.
......@@ -134,7 +134,7 @@ class Figure(Element, ABC):
value = self.__getitem__(key, method)
if key == "datatype":
dictionary[key] = value.to_string()
dictionary[key] = value.to_string(legacy_mode)
else:
dictionary[key] = value
return dictionary
......
......@@ -124,17 +124,17 @@ class Function(Element):
return returns
def serialize(self, keys: List[str], method: int = HTTP_GET) -> Dict[str, Any]:
def serialize(self, keys: List[str], legacy_mode: bool, method: int = HTTP_GET) -> Dict[str, Any]:
if not keys or 'all' in keys:
keys = ['uuid', 'name', 'description', 'arguments', 'returns', 'ontology']
dictionary = super().serialize(keys)
dictionary = super().serialize(keys, legacy_mode)
if 'arguments' in keys:
dictionary['arguments'] = list(
map(lambda x: x.serialize(['name', 'uuid', 'description', 'datatype', 'value', 'dimension', 'range', 'ontology'], HTTP_OPTIONS),
map(lambda x: x.serialize(['name', 'uuid', 'description', 'datatype', 'value', 'dimension', 'range', 'ontology'], legacy_mode, HTTP_OPTIONS),
self._arguments))
if 'returns' in keys:
dictionary['returns'] = list(
map(lambda x: x.serialize(['name', 'uuid', 'description', 'datatype', 'dimension', 'ontology'], HTTP_OPTIONS), self._returns))
map(lambda x: x.serialize(['name', 'uuid', 'description', 'datatype', 'dimension', 'ontology'], legacy_mode, HTTP_OPTIONS), self._returns))
return dictionary
@staticmethod
......
......@@ -99,7 +99,7 @@ class Measurement(Figure):
else:
super().__setitem__(key, value)
def serialize(self, keys: [str], method=HTTP_GET):
def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
"""
Serializes an object of type Measurement into a JSON-like dictionary.
:param keys: All attributes given in the "keys" array are serialized.
......@@ -121,7 +121,7 @@ class Measurement(Figure):
if key == 'timestamp' or (key == 'value' and self._datatype == 'time'):
value = value.isoformat() + 'Z' if value is not None else ""
if key == "datatype":
dictionary[key] = value.to_string()
dictionary[key] = value.to_string(legacy_mode)
else:
dictionary[key] = value
......
......@@ -62,7 +62,7 @@ class Parameter(Figure):
return self._setter is not None
return super().__getitem__(item, method)
def serialize(self, keys: [str], method=HTTP_GET):
def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
"""
Seriealizes an object of type Figure into a JSON-like dictionary.
:param keys: All attributes given in the "keys" array are serialized.
......@@ -77,7 +77,7 @@ class Parameter(Figure):
for key in keys:
value = self.__getitem__(key, method)
if key == "datatype":
dictionary[key] = value.to_string()
dictionary[key] = value.to_string(legacy_mode)
else:
dictionary[key] = value
return dictionary
......
......@@ -79,7 +79,7 @@ class Variable(Figure):
else:
super().__setitem__(key, value)
def serialize(self, keys: [str], method=HTTP_GET):
def serialize(self, keys: [str], legacy_mode: bool, method=HTTP_GET):
"""
Serializes an object of type Variable into a JSON-like dictionary.
:param keys: All attributes given in the "keys" array are serialized.
......@@ -100,7 +100,7 @@ class Variable(Figure):
if key == 'timestamp' or (key == 'value' and self._datatype == 'time'):
value = value.isoformat() + 'Z' if value is not None else ""
if key == "datatype":
dictionary[key] = value.to_string()
dictionary[key] = value.to_string(legacy_mode)
else:
dictionary[key] = value
return dictionary
......
......@@ -121,7 +121,7 @@ def start(com_lasertracker: COMLasertracker, config: Dict, soil_model_file: str)
'signature': {'arguments': {}, 'returns': []}, 'mqtt_callback': mqtt.publish}
model = Component.load(soil_model_file, mapping['COM-Lasertracker'])
http = HTTPServer(loop, address, port, model, dataformat=config['dataformat'])
http = HTTPServer(loop, address, port, model, dataformat=config['dataformat'], legacy_mode=True)
# start servers
main_logger.info("Starting main asynchronous loop")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment