diff --git a/README.md b/README.md index eeab6ca781c2719315d1da4a6d486262417cd754..3c80a843e98a72ba2543f8fcf9a8feeae08127fc 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [](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: 10.0.5 +Current stable version: 10.0.6 ## Installation 1. Install the WZL-UDI package via pip @@ -22,28 +22,28 @@ Examples of fictional devices using the library can be found [here](https://git- Scientific background and publications related to the _(Python) Unified Device Interface_ are: -[Bodenbenner, M.](mailto:m.bodenbenner@wzl-mq.rwth-aachen.de); Sanders, M. P.; Montavon, B.; Schmitt, R. H. (2021): +[Bodenbenner, M.](mailto:matthias.bodenbenner@wzl-iqs.rwth-aachen.de); Sanders, M. P.; Montavon, B.; Schmitt, R. H. (2021): Domain-Specific Language for Sensors in the Internet of Production. In: Bernd-Arno Behrens, Alexander Brosius, Wolfgang Hintze, Steffen Ihlenfeldt und Jens Peter Wulfsberg (Hg.): Production at the leading edge of technology. Proceedings of the 10th Congress of the German Academic Association for Production Technology (WGP), Dresden, 23-24 September 2020. Berlin, Heidelberg, 2021. 1st ed. 2021. Berlin, Heidelberg: Springer (Lecture Notes in Production Engineering), S. 448–456, http://dx.doi.org/10.1007/978-3-662-62138-7_45 -[Bodenbenner, M.](mailto:m.bodenbenner@wzl-mq.rwth-aachen.de); Montavon, B.; Schmitt, R.H. (2021): +[Bodenbenner, M.](mailto:matthias.bodenbenner@wzl-iqs.rwth-aachen.de); Montavon, B.; Schmitt, R.H. (2021): FAIR sensor services - Towards sustainable sensor data management. In: Measurement: Sensors 18, S. 100206, https://doi.org/10.1016/j.measen.2021.100206 -[Bodenbenner, M.](mailto:m.bodenbenner@wzl-mq.rwth-aachen.de); Montavon, B.; Schmitt, R.H. (2022): +[Bodenbenner, M.](mailto:matthias.bodenbenner@wzl-iqs.rwth-aachen.de); Montavon, B.; Schmitt, R.H. (2022): Model-driven development of interoperable communication interfaces for FAIR sensor services, In: Measurement: Sensors, Volume 24, S. 100442, https://doi.org/10.1016/j.measen.2022.100442 -[Montavon, B.](mailto:b.montavon@wzl-mq.rwth-aachen.de) (2021): +[Montavon, B.](mailto:benjamin.montavon@wzl-iqd.rwth-aachen.de) (2021): Virtual Reference Frame Based on Distributed Large-Scale Metrology Providing Coordinates as a Service. Aachen: Apprimus Verlag, https://doi.org/10.18154/RWTH-2021-10238 -[Montavon, B.](mailto:b.montavon@wzl-mq.rwth-aachen.de); Peterek, M.; Schmitt, R. H. (2019): +[Montavon, B.](mailto:benjamin.montavon@wzl-iqd.rwth-aachen.de); Peterek, M.; Schmitt, R. H. (2019): Model-based interfacing of large-scale metrology instruments. In: Ettore Stella (Hg.): Multimodal Sensing: Technologies and Applications. 26-27 June 2019, Munich, Germany. Multimodal Sensing and Artificial Intelligence: Technologies and Applications. Munich, Germany, 6/24/2019 - 6/27/2019. Bellingham, Washington: SPIE (Proceedings of SPIE. 5200-, volume 11059), S. 11, https://doi.org/10.1117/12.2527461 @@ -56,7 +56,7 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Project-ID 432233186 -- AIMS. -## License of used third-party libraries +## Licenses of third-party libraries used | Library | License | |--------------|---------------------------------------| @@ -69,10 +69,13 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) ## Recent changes +**10.0.6** - 2024-03-22 + - fixed validation of rfc3339 datetime strings + **10.0.5** - 2024-03-22 - bug fix in streaming - - **10.0.4** - 2024-03-22 +**10.0.4** - 2024-03-22 - increased logging verbosity of streaming class - fixed streaming of semantic measurements diff --git a/setup.py b/setup.py index 7470647efd68df9cd89388217fd7c749f66d8faf..445975fe1a1aca5e3f9100a77e5755cf88c2bfad 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setup(name='wzl-udi', - version='10.0.5', + version='10.0.6', url='https://git-ce.rwth-aachen.de/wzl-mq-public/soil/python', project_urls={ "Bug Tracker": "https://git-ce.rwth-aachen.de/wzl-mq-public/soil/python/-/issues", diff --git a/src/soil/variable.py b/src/soil/variable.py index 1458c4f9fd695de01001fe6cf23dd9880524f4cc..bbfa1629e7d4f3a7971b45fa7d2121b2bda4195d 100644 --- a/src/soil/variable.py +++ b/src/soil/variable.py @@ -24,6 +24,31 @@ from ..utils.error import DeviceException logger = root_logger.get(__name__) +def validate_time(time_rfc3339: Union[str, List]): + if isinstance(time_rfc3339, list): + for e in time_rfc3339: + if not validate_time(e): + return False + return True + else: + if time_rfc3339 is None or time_rfc3339 == "": + return False + + formats = ["%Y-%m-%dT%H:%M:%S.%f%z", "%Y-%m-%dT%H:%M:%S%z", "%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ"] + + for fmt in formats: + try: + if fmt.endswith('Z'): + datetime.datetime.strptime(time_rfc3339.rstrip('Z'), fmt.rstrip('Z')) + else: + datetime.datetime.strptime(time_rfc3339, fmt) + return True + + except ValueError: + continue + return False + + def parse_time(time_rfc3339: Union[str, List]): if isinstance(time_rfc3339, list): return [parse_time(e) for e in time_rfc3339] @@ -38,10 +63,10 @@ def parse_time(time_rfc3339: Union[str, List]): # Attempt to parse the timestamp with the current format if fmt.endswith('Z'): # Strip the 'Z' and replace it after parsing if format specifies 'Z' at the end - dt = datetime.strptime(time_rfc3339.rstrip('Z'), fmt.rstrip('Z')) + dt = datetime.datetime.strptime(time_rfc3339.rstrip('Z'), fmt.rstrip('Z')) dt = dt.replace(tzinfo=pytz.UTC) else: - dt = datetime.strptime(time_rfc3339, fmt) + dt = datetime.datetime.strptime(time_rfc3339, fmt) return dt except ValueError: @@ -217,7 +242,7 @@ class Variable(Element, ABC): "Time field {} must be string.".format( value)) elif datatype == Datatype.TIME and isinstance(value, str): - if value != "" and value is not None and not rfc3339.validate_rfc3339(value): + if value != "" and value is not None and not validate_time(value): raise TypeException("Value is not a valid RFC3339-formatted timestring: {}".format(value)) else: # recursion case: value is an array or matrix => check datatype of each "subvalue" recursively @@ -279,7 +304,7 @@ class Variable(Element, ABC): raise RangeException("Enum value {} is not within the set of allowed values!".format(value)) elif datatype == Datatype.TIME and value is not None and value != "": if range[0] is not None: - if not rfc3339.validate_rfc3339(range[0]): + if not validate_time(range[0]): raise TypeException( "Can not check range of time value. Lower bound {} is not a valid RFC3339 timestring.".format( range[0])) @@ -288,7 +313,7 @@ class Variable(Element, ABC): "Time value {} is smaller than lower bound {}!".format(parse_time(value), parse_time(range[0]))) elif range[1] is not None: - if not rfc3339.validate_rfc3339(range[1]): + if not validate_time(range[1]): raise TypeException( "Can not check range of time value. Upper bound {} is not a valid RFC3339 timestring.".format( range[0]))