Skip to content

Commit 5c053aa

Browse files
authored
Merge pull request #45 from thec0dewriter/#43-state-initiator-implementation
#43 state initiator implementation
2 parents 5e97f21 + a85adaf commit 5c053aa

File tree

3 files changed

+143
-1
lines changed

3 files changed

+143
-1
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH
2+
#
3+
# See the AUTHORS file(s) distributed with this work for additional
4+
# information regarding authorship.
5+
#
6+
# This Source Code Form is subject to the terms of the Mozilla Public
7+
# License, v. 2.0. If a copy of the MPL was not distributed with this
8+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
9+
#
10+
# SPDX-License-Identifier: MPL-2.0
11+
12+
from typing import Any, Dict, Optional
13+
14+
import rdflib # type: ignore
15+
16+
from rdflib.term import Node
17+
18+
from esmf_aspect_meta_model_python.base.characteristics.state import State
19+
from esmf_aspect_meta_model_python.impl.characteristics.default_state import DefaultState
20+
from esmf_aspect_meta_model_python.loader.instantiator.constants import DATA_TYPE_ERROR_MSG
21+
from esmf_aspect_meta_model_python.loader.instantiator.enumeration_instantiator import EnumerationInstantiator
22+
from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper
23+
from esmf_aspect_meta_model_python.vocabulary.SAMM import SAMM
24+
from esmf_aspect_meta_model_python.vocabulary.SAMMC import SAMMC
25+
26+
27+
class StateInstantiator(EnumerationInstantiator):
28+
def _create_instance(self, element_node: Node) -> State:
29+
data_type = self._get_data_type(element_node)
30+
if data_type is None:
31+
raise TypeError(DATA_TYPE_ERROR_MSG)
32+
33+
meta_model_base_attributes = self._get_base_attributes(element_node)
34+
value_collection_node = self._aspect_graph.value(
35+
subject=element_node,
36+
predicate=self._sammc.get_urn(SAMMC.values),
37+
)
38+
value_nodes = RdfHelper.get_rdf_list_values(value_collection_node, self._aspect_graph)
39+
values = [self.__to_state_node_value(value_node) for value_node in value_nodes]
40+
41+
defaultValue = self._aspect_graph.value(
42+
subject=element_node,
43+
predicate=self._sammc.get_urn(SAMMC.default_value),
44+
)
45+
default = self.__to_state_node_value(defaultValue)
46+
47+
return DefaultState(meta_model_base_attributes, data_type, values, default)
48+
49+
def __to_state_node_value(self, value_node: Optional[Node]) -> Dict:
50+
"""
51+
This method instantiates one possible value of a state.
52+
:param value_node: Node of the Graph that represents one state value.
53+
The Argument can either be a Literal or a URIRef.
54+
- If value_node is a Literal it will represent e.g. a string or an integer value
55+
- If value_node is a URIRef it will represent a value of a ComplexType
56+
:return: the one generated value of the state
57+
"""
58+
if isinstance(value_node, rdflib.Literal):
59+
# value represents a simple data type
60+
return value_node.toPython()
61+
62+
elif isinstance(value_node, rdflib.URIRef):
63+
# value represents a complex data type
64+
value = {}
65+
value_node_properties = self._aspect_graph.predicate_objects(value_node)
66+
for property_urn, property_value in value_node_properties:
67+
if property_urn != rdflib.RDF.type and isinstance(property_urn, str):
68+
property_name = property_urn.split("#")[1]
69+
actual_value: Optional[Any]
70+
if self.__is_collection_value(property_urn):
71+
actual_value = self.__instantiate_enum_collection(property_value)
72+
else:
73+
actual_value = self.__to_state_node_value(property_value)
74+
value[property_name] = actual_value
75+
76+
value_node_name = value_node.split("#")[1]
77+
value_key = self._samm.get_urn(SAMM.name).toPython()
78+
value[value_key] = value_node_name # type: ignore
79+
return value
80+
81+
else:
82+
# illegal node type for state value (e.g., Blank Node)
83+
raise TypeError(
84+
f"Every value of an state must either be a Literal (string, int, etc.) or "
85+
f"a URI reference to a ComplexType. Values of type {type(value_node).__name__} are not allowed"
86+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright (c) 2023 Robert Bosch Manufacturing Solutions GmbH
2+
#
3+
# See the AUTHORS file(s) distributed with this work for
4+
# additional information regarding authorship.
5+
#
6+
# This Source Code Form is subject to the terms of the Mozilla Public
7+
# License, v. 2.0. If a copy of the MPL was not distributed with this
8+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
9+
#
10+
# SPDX-License-Identifier: MPL-2.0
11+
12+
@prefix : <urn:samm:org.eclipse.esmf.test.characteristics:2.0.0#> .
13+
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.0.0#> .
14+
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.0.0#> .
15+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
16+
@prefix unit: <urn:samm:org.eclipse.esmf.samm:unit:2.0.0#> .
17+
18+
:TestAspect a samm:Aspect ;
19+
samm:preferredName "Test Aspect"@en ;
20+
samm:preferredName "Test Aspekt"@de ;
21+
samm:description "This is a test description"@en ;
22+
samm:see <https://eclipse-esmf.github.io> ;
23+
samm:properties ( :testPropertyOne ) ;
24+
samm:operations ( ) .
25+
26+
:testPropertyOne a samm:Property ;
27+
samm:characteristic [
28+
a samm-c:State ;
29+
samm:preferredName "Test State"@en ;
30+
samm:description "This is a test state."@en ;
31+
samm:dataType xsd:string ;
32+
samm-c:values ( "default" "good" "bad" ) ;
33+
samm-c:defaultValue "default"
34+
] .

core/esmf-aspect-meta-model-python/tests/integration/test_characteristics.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
Enumeration,
2222
Measurement,
2323
Quantifiable,
24-
StructuredValue,
24+
State,
25+
StructuredValue
2526
)
2627

2728
RESOURCE_PATH = getcwd() / Path("tests/integration/resources/org.eclipse.esmf.test.characteristics/2.0.0")
@@ -116,6 +117,27 @@ def test_loading_aspect_with_simple_enum():
116117
assert "baz" in values
117118

118119

120+
def test_loading_aspect_with_simple_state():
121+
print(RESOURCE_PATH)
122+
file_path = RESOURCE_PATH / "AspectWithState.ttl"
123+
aspect_loader = AspectLoader()
124+
model_elements = aspect_loader.load_aspect_model(file_path)
125+
aspect = model_elements[0]
126+
127+
first_property = aspect.properties[0]
128+
state_characteristic = first_property.characteristic
129+
assert isinstance(state_characteristic, State)
130+
assert state_characteristic.name == "testPropertyOne_characteristic"
131+
132+
values = state_characteristic.values
133+
assert len(values) == 3
134+
assert "default" in values
135+
assert "good" in values
136+
assert "bad" in values
137+
default = state_characteristic.default_value
138+
assert default == "default"
139+
140+
119141
def test_loading_aspect_with_quantifiable():
120142
file_path = RESOURCE_PATH / "AspectWithQuantifiableAndUnit.ttl"
121143
aspect_loader = AspectLoader()

0 commit comments

Comments
 (0)