diff --git a/src/soil/component.py b/src/soil/component.py index 4c507d6c40a95235c788832a99186f6dfc7e969f..869f3896f90eac723e34e38c4fc56f178ca20069 100644 --- a/src/soil/component.py +++ b/src/soil/component.py @@ -19,6 +19,7 @@ from .error import ChildNotFoundException from .function import Function from .measurement import Measurement from .parameter import Parameter +from .semantics import Namespaces from ..utils import root_logger from ..utils.constants import HTTP_GET from ..utils.error import SerialisationException, DeviceException, UserException @@ -395,23 +396,23 @@ class Component(Element): return result def resolve_semantic_path(self, path: List[str]): - if len(path) == 0: - raise ChildNotFoundException('Could not resolve the semantic path.') + 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.System, triples)) + assert len(triples) > 0 + + if path[0] == triples[0][0].split('/')[-1] and len(path) == 1: + return self, 'metadata' - # first try to resolve whether it is a path to a profile - if path[0] == f'{self._profilename}Shape': - if len(path) == 1: - return self, 'profile' - else: for child in self.children: try: return child.resolve_semantic_path(path) except ChildNotFoundException: continue - # TODO resolve data or metadata terms - - raise ChildNotFoundException('Could not resolve the semantic path.') + raise ChildNotFoundException('Could not resolve the semantic path.') diff --git a/src/soil/element.py b/src/soil/element.py index c248859527f5b54a39d1f458bf0f27d725fab607..3fb465723d1f8edcf29df793c0cbe6eb80870d84 100644 --- a/src/soil/element.py +++ b/src/soil/element.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List import rdflib from .error import ChildNotFoundException +from .semantics import Namespaces from ..utils.constants import BASE_UUID_PATTERN, HTTP_GET from ..utils.error import SerialisationException @@ -118,7 +119,6 @@ class Element(ABC): if path[0] == f'{self._profilename}Shape' and len(path) == 1: return self, 'profile' - else: - raise ChildNotFoundException('Could not resolve the semantic path.') - # TODO resolve data or metadata terms + raise ChildNotFoundException('Could not resolve the semantic path.') + diff --git a/src/soil/function.py b/src/soil/function.py index 04131ff79633093e1d05d7f1e177e0f1b610e581..c9aad47d8710442369b6b3191473cc6f786a58f6 100644 --- a/src/soil/function.py +++ b/src/soil/function.py @@ -1,16 +1,15 @@ -import functools import inspect from typing import Any, Dict, List, Union, Callable import rdflib from .element import Element -from .error import InvokationException, NotImplementedException -from ..utils import root_logger -from ..utils.error import SerialisationException, DeviceException +from .error import InvokationException, NotImplementedException, ChildNotFoundException from .figure import Figure from .parameter import Parameter +from ..utils import root_logger from ..utils.constants import HTTP_GET, HTTP_OPTIONS +from ..utils.error import SerialisationException, DeviceException logger = root_logger.get(__name__) @@ -54,7 +53,8 @@ class Function(Element): for o in everything: if o.uuid == item[0]: return o[item[1:]] - raise Exception("{}: Given uuid {} is not the id of a child of the current component!".format(self.uuid, item)) + raise Exception( + "{}: Given uuid {} is not the id of a child of the current component!".format(self.uuid, item)) return super().__getitem__(item, method) def __setitem__(self, key: str, value: Any): @@ -121,7 +121,8 @@ class Function(Element): var = [x for x in self._returns if x['uuid'] == uuid] if len(var) != 1: raise InvokationException(self._uuid, self._name, - "Internal Server Error. UUID {} of returned parameter does not match!".format(uuid)) + "Internal Server Error. UUID {} of returned parameter does not match!".format( + uuid)) else: var = var[0] Figure.check_all(var.datatype, var.dimension, var.range, value) @@ -135,11 +136,14 @@ class Function(Element): 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'], legacy_mode, 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'], legacy_mode, HTTP_OPTIONS), self._returns)) + map(lambda x: x.serialize(['name', 'uuid', 'description', 'datatype', 'dimension', 'ontology'], + legacy_mode, HTTP_OPTIONS), self._returns)) return dictionary @staticmethod @@ -149,15 +153,19 @@ class Function(Element): uuid = dictionary['uuid'] if uuid[:3] != 'FUN': raise SerialisationException( - 'The Function can not be deserialized. The UUID must start with FUN, but actually starts with {}!'.format(uuid[:3])) + 'The Function can not be deserialized. The UUID must start with FUN, but actually starts with {}!'.format( + uuid[:3])) if 'name' not in dictionary: raise SerialisationException('{}: The function can not be deserialized. Name is missing!'.format(uuid)) if 'description' not in dictionary: - raise SerialisationException('{}: The function can not be deserialized. Description is missing!'.format(uuid)) + raise SerialisationException( + '{}: The function can not be deserialized. Description is missing!'.format(uuid)) if 'arguments' not in dictionary: - raise SerialisationException('{}: The function can not be deserialized. List of arguments is missing!'.format(uuid)) + raise SerialisationException( + '{}: The function can not be deserialized. List of arguments is missing!'.format(uuid)) if 'returns' not in dictionary: - raise SerialisationException('{}: The function can not be deserialized. List of returns is missing!'.format(uuid)) + raise SerialisationException( + '{}: The function can not be deserialized. List of returns is missing!'.format(uuid)) try: arguments = [] @@ -174,7 +182,8 @@ class Function(Element): try: ontology = dictionary['ontology'] if 'ontology' in dictionary else None profile = dictionary['profile'] if 'profile' in dictionary else None - return Function(dictionary['uuid'], dictionary['name'], dictionary['description'], arguments, returns, implementation, ontology, profile) + return Function(dictionary['uuid'], dictionary['name'], dictionary['description'], arguments, returns, + implementation, ontology, profile) except Exception as e: raise SerialisationException('{}: The function can not be deserialized. {}'.format(uuid, e)) @@ -185,3 +194,7 @@ class Function(Element): def serialize_semantics(self, kind: str) -> rdflib.Graph: # 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): + # This method does nothing intentionally, as we do not have any semantic definition for function + raise ChildNotFoundException('Could not resolve the semantic path.') diff --git a/src/soil/measurement.py b/src/soil/measurement.py index 3dee1c151c1e805d002eb57366e8dd96037e1372..a6aabb757c8d656e99a3a43c545210aeb9f9ea9d 100644 --- a/src/soil/measurement.py +++ b/src/soil/measurement.py @@ -1,17 +1,17 @@ import datetime import warnings -from typing import Dict, Callable, List, Any +from typing import Dict, Callable, List import rdflib from deprecated import deprecated -from rdflib import BNode from .datatype import Datatype +from .error import ChildNotFoundException from .figure import Figure +from .semantics import Semantics, Namespaces from ..utils import root_logger from ..utils.constants import HTTP_GET from ..utils.error import SerialisationException, DeviceException -from .semantics import Semantics, Namespaces logger = root_logger.get(__name__) @@ -193,8 +193,10 @@ class Measurement(Figure): # create observation node data_graph.add((observation_subject, Namespaces.rdf.type, rdflib.URIRef(Namespaces.sosa.Observation))) data_graph.add((observation_subject, Namespaces.schema.name, rdflib.Literal(f'{self._name} Observation'))) - data_graph.add((observation_subject, Namespaces.sosa.observedProperty, Semantics.namespace[self._semantic_name])) - data_graph.add((observation_subject, Namespaces.sosa.hasResult, Semantics.namespace[f'{self._semantic_name}Measurement'])) + data_graph.add( + (observation_subject, Namespaces.sosa.observedProperty, Semantics.namespace[self._semantic_name])) + data_graph.add((observation_subject, Namespaces.sosa.hasResult, + Semantics.namespace[f'{self._semantic_name}Measurement'])) data_graph.add((observation_subject, Namespaces.sosa.madeBySensor, sensor_triples[0][2])) # create result node @@ -210,7 +212,8 @@ class Measurement(Figure): rdf_value = Figure.serialize_value(data_graph, self.__getitem__('value', 0)) data_graph.add((measurement_subject, Namespaces.qudt.value, rdf_value)) - data_graph.add((measurement_subject, Namespaces.schema.dateCreated, rdflib.Literal(datetime.datetime.now().astimezone()))) + data_graph.add((measurement_subject, Namespaces.schema.dateCreated, + rdflib.Literal(datetime.datetime.now().astimezone()))) # TODO add uncertainty @@ -218,3 +221,16 @@ class Measurement(Figure): else: 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.') diff --git a/src/soil/parameter.py b/src/soil/parameter.py index d4f86fef7f9f9659a3e9e75b52c1555a63178d63..a10e7ab079249d1c2b6c09ea83810680766952c0 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 +from .error import ReadOnlyException, ChildNotFoundException from .figure import Figure from .semantics import Semantics, Namespaces from ..utils import root_logger @@ -153,3 +153,16 @@ class Parameter(Figure): else: 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.') \ No newline at end of file