diff --git a/README.md b/README.md index 7b2f58c691ee9a2c42e9330f92031cb9ddb37ea6..d0ada772b4b1bc1b02a7fed91e5a7d1319914d02 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: 9.0.0 +Current stable version: 9.0.1 ## Installation 1. Install the WZL-UDI package via pip @@ -53,10 +53,14 @@ https://doi.org/10.1117/12.2527461 The authors acknowledge funding from the LaVA project (Large Volume Applications, contract 17IND03 of the European Metrology Programme for Innovation and Research EMPIR). The EMPIR initiative is co-funded by the European Union’s Horizon 2020 research and innovation programme and the EMPIR Participating States. Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Germany's Excellence Strategy – EXC-2023 Internet of Production – 390621612. + Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Project-ID 432233186 -- AIMS. ## Recent changes +**9.0.1** - 2024-01-11 + - bug fix of semantic name resolution + **9.0.0** - 2024-01-10 - added semantic features - the device can return profiles, metadata and data defined and structured according to semantic web standards using RDF and SHACL diff --git a/requirements.txt b/requirements.txt index 042289c3677d361567cbd9fec5c4b022b474ba22..9d3aff5b04e6c396aa63f9f4d69cedbf7f7ad70c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ rdflib==7.0.0 sphinx==3.5.2 sphinx-rtd-theme==1.0.0 strict-rfc3339==0.7 -wzl-mqtt~=2.6.0 \ No newline at end of file +wzl-mqtt~=2.6.1 \ No newline at end of file diff --git a/setup.py b/setup.py index c019b33b380c662a58cf79946294701534df8286..d8f626c49704e3c30932d62cf35744972db93afa 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='9.0.0', + version='9.0.1', 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", @@ -25,7 +25,7 @@ setup(name='wzl-udi', 'Deprecated~=1.2.13', 'nest-asyncio~=1.5.6', 'strict-rfc3339==0.7', - 'wzl-mqtt~=2.5.3', + 'wzl-mqtt~=2.6.1', 'rdflib~=7.0.0' ], zip_safe=False) diff --git a/src/http/server.py b/src/http/server.py index a947643233b4f72a1e43458588e3fb6e9977007c..2cac618899f441802c051e4e94f633bdde0bb5bb 100644 --- a/src/http/server.py +++ b/src/http/server.py @@ -180,7 +180,7 @@ class HTTPServer(object): semantic = request.query['semantic'] if len(splitted_request) > 0 and splitted_request[0] == Semantics.prefix: - item, semantic = self.root.resolve_semantic_path(splitted_request[1:]) + item, semantic = self.root.resolve_semantic_path(splitted_request[1]) else: try: item = self.root[splitted_request] diff --git a/src/soil/component.py b/src/soil/component.py index b80b9519ba53b1f173ed731d4aaa03ba8e131de0..daca80dfe5916dc8c46d7f3082456b57678efdc3 100644 --- a/src/soil/component.py +++ b/src/soil/component.py @@ -395,20 +395,13 @@ class Component(Element): raise DeviceException('The provided kind of semantic information cannot be returned.') return result - def resolve_semantic_path(self, path: List[str]): + def resolve_semantic_path(self, suffix: str) -> (Element, str): try: - super().resolve_semantic_path(path) + return super().resolve_semantic_path(suffix) except ChildNotFoundException: - triples = list(self._metadata.triples((None, Namespaces.rdf.type, None))) - triples = list(filter(lambda x: x[2] == Namespaces.ssn.System, triples)) - assert len(triples) > 0 - - if path[0] == triples[0][0].split('/')[-1] and len(path) == 1: - return self, 'metadata' - for child in self.children: try: - return child.resolve_semantic_path(path) + return child.resolve_semantic_path(suffix) except ChildNotFoundException: continue @@ -419,4 +412,4 @@ class Component(Element): if self._metadata is None: return "" subject = next(self._metadata.subjects(predicate=Namespaces.rdf.type, object=Namespaces.ssn.System)) - return subject.toPython() \ No newline at end of file + return subject.toPython() diff --git a/src/soil/element.py b/src/soil/element.py index c7e332d409b2a48db4cddf891ce8dd939fede3f6..cf0c30ac6fe1e429c38151fea50381d8f961a75a 100644 --- a/src/soil/element.py +++ b/src/soil/element.py @@ -112,12 +112,11 @@ class Element(ABC): def serialize_semantics(self, kind: str) -> rdflib.Graph: ... - def resolve_semantic_path(self, path: List[str]) -> ('Element', str): - if len(path) == 0: - raise ChildNotFoundException('Could not resolve the semantic path.') - - if path[0] == f'{self._profilename}Shape' and len(path) == 1: + def resolve_semantic_path(self, suffix: str) -> ('Element', str): + if suffix == f'{self._profilename}Shape': return self, 'profile' + elif suffix == self.semantic_name.split('/')[-1]: + return self, 'metadata' raise ChildNotFoundException('Could not resolve the semantic path.') diff --git a/src/soil/function.py b/src/soil/function.py index b531f8c88e86d0d7c8a6bb5379be01b24750ec47..53c2a45cce2a81ae1dd33ffe1283a1e2e6ac5678 100644 --- a/src/soil/function.py +++ b/src/soil/function.py @@ -195,10 +195,10 @@ class Function(Element): # This method does nothing intentionally, as we do not have any semantic definition for function return None - def resolve_semantic_path(self, path: List[str]) -> ('Element', str): + def resolve_semantic_path(self, suffix: str) -> (Element, str): # This method does nothing intentionally, as we do not have any semantic definition for function raise ChildNotFoundException('Could not resolve the semantic path.') @property def semantic_name(self) -> str: - return "" \ No newline at end of file + return "" diff --git a/src/soil/measurement.py b/src/soil/measurement.py index 063431cf5dbe4797006a21e9d4cf7e46e645e028..217f46fac3b67d4ad4db2e315a9d080d3dee7a25 100644 --- a/src/soil/measurement.py +++ b/src/soil/measurement.py @@ -6,8 +6,6 @@ import rdflib from deprecated import deprecated from .datatype import Datatype -from .element import Element -from .error import ChildNotFoundException from .figure import Figure from .semantics import Semantics, Namespaces from ..utils import root_logger @@ -223,22 +221,10 @@ class Measurement(Figure): raise DeviceException('The provided kind of semantic information cannot be returned.') return result - def resolve_semantic_path(self, path: List[str]) -> (Element, str): - try: - super().resolve_semantic_path(path) - except ChildNotFoundException: - triples = list(self._metadata.triples((None, Namespaces.rdf.type, None))) - triples = list(filter(lambda x: x[2] == Namespaces.sosa.ObservableProperty, triples)) - assert len(triples) > 0 - - if path[0] == triples[0][0].split('/')[-1] and len(path) == 1: - return self, 'metadata' - - raise ChildNotFoundException('Could not resolve the semantic path.') - @property def semantic_name(self) -> str: if self._metadata is None: return "" - subject = next(self._metadata.subjects(predicate=Namespaces.rdf.type, object=Namespaces.sosa.ObservableProperty)) + subject = next( + self._metadata.subjects(predicate=Namespaces.rdf.type, object=Namespaces.sosa.ObservableProperty)) return subject.toPython() diff --git a/src/soil/parameter.py b/src/soil/parameter.py index 5c794b3a64c278cbe11258a759842ad8f9304e15..62b094b44b02c54a31767bcf6f79f11c3b81db03 100644 --- a/src/soil/parameter.py +++ b/src/soil/parameter.py @@ -6,7 +6,7 @@ from typing import Dict, Callable, Any, List import rdflib from .datatype import Datatype -from .error import ReadOnlyException, ChildNotFoundException +from .error import ReadOnlyException from .figure import Figure from .semantics import Semantics, Namespaces from ..utils import root_logger @@ -154,19 +154,6 @@ class Parameter(Figure): raise DeviceException('The provided kind of semantic information cannot be returned.') return result - def resolve_semantic_path(self, path: List[str]) -> ('Element', str): - try: - super().resolve_semantic_path(path) - except ChildNotFoundException: - triples = list(self._metadata.triples((None, Namespaces.rdf.type, None))) - triples = list(filter(lambda x: x[2] == Namespaces.ssn.Property, triples)) - assert len(triples) > 0 - - if path[0] == triples[0][0].split('/')[-1] and len(path) == 1: - return self, 'metadata' - - raise ChildNotFoundException('Could not resolve the semantic path.') - @property def semantic_name(self) -> str: if self._metadata is None: