Skip to content

Commit b3c9b50

Browse files
committed
Merge branch 'main' into 2.1.x
2 parents 7a3463c + b448fdf commit b3c9b50

File tree

76 files changed

+495
-186
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+495
-186
lines changed

core/esmf-aspect-meta-model-python/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ An Aspect of the Meta Model can be created as follows using the provided `Aspect
1313

1414
```
1515
aspect_loader = AspectLoader()
16-
aspect = aspect_loader.load_aspect_model("path/to/turtle.ttl");
16+
aspect = aspect_loader.load_aspect_model("absolute/path/to/turtle.ttl");
1717
```
1818

1919
or
2020

2121
```
2222
aspect_loader = AspectLoader()
23-
aspect = aspect_loader.load_aspect_model_from_multiple_files(["list/of/paths/to/turtles.ttl"], "aspect_urn");
23+
aspect = aspect_loader.load_aspect_model_from_multiple_files(["list/of/absolute/paths/to/turtles.ttl"], "aspect_urn");
2424
```
2525

2626
## Automatic Deployment

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/base/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ HasUrn
2727
│ ├── SingleEntity
2828
│ ├── StructuredValue
2929
│ ├── Quantifiable
30-
│ │ ├── Duration
31-
│ │ └── Measurement
32-
│ └── Trait
30+
│ │ ├── Duration
31+
│ │ └── Measurement
32+
│ └── Trait
3333
├── Constraint
3434
│ ├── EncodingConstraint
3535
│ ├── FixedPointConstraint
@@ -38,7 +38,7 @@ HasUrn
3838
│ ├── LocaleConstraint
3939
│ ├── RangeConstraint
4040
│ └── RegularExpressionConstraint
41-
├── Event
41+
├── Event
4242
├── Operation
4343
├── Property
4444
├── QuantityKind

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/impl/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from .constraints.default_regular_expression_constraint import DefaultRegularExpressionConstraint
3636
from .data_types.default_abstract_entity import DefaultAbstractEntity
3737
from .data_types.default_complex_type import DefaultComplexType
38+
from .data_types.default_data_type import DefaultDataType
3839
from .data_types.default_entity import DefaultEntity
3940
from .data_types.default_scalar import DefaultScalar
4041
from .default_aspect import DefaultAspect
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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 esmf_aspect_meta_model_python.base.data_types.data_type import DataType
13+
14+
15+
class DefaultDataType(DataType):
16+
"""Default DataType class."""
17+
18+
def __init__(self, urn: str, meta_model_version: str):
19+
self._urn = urn
20+
self._meta_model_version = meta_model_version
21+
22+
@property
23+
def urn(self) -> str:
24+
"""URN."""
25+
return self._urn
26+
27+
@property
28+
def meta_model_version(self) -> str:
29+
"""Meta model version."""
30+
return self._meta_model_version

core/esmf-aspect-meta-model-python/esmf_aspect_meta_model_python/loader/aspect_loader.py

Lines changed: 150 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#
1010
# SPDX-License-Identifier: MPL-2.0
1111

12+
from os.path import exists, join
1213
from pathlib import Path
1314
from typing import Optional, Union
1415

@@ -36,38 +37,142 @@ def __init__(self) -> None:
3637
self._cache = DefaultElementCache()
3738

3839
def load_aspect_model(self, file_path: Union[str, Path]) -> Aspect:
39-
"""
40-
creates an aspect object with all the including properties and operations with the
41-
turtle file
40+
"""Load aspect model to RDF GRAPH.
41+
42+
Create an aspect object with all the including properties and operations with the turtle file
43+
4244
:param file_path: path to the turtle file. Can be either a string or a Path object
4345
:return: instance of the aspect
4446
"""
4547
return self.load_aspect_model_from_multiple_files([file_path])
4648

49+
@staticmethod
50+
def _get_additional_files_from_dir(file_path: str) -> list[str]:
51+
"""Get additional files from specific directory.
52+
53+
:param file_path: path list to the turtle files
54+
:return: list of the additional turtle files
55+
"""
56+
additional_files = []
57+
58+
if not exists(file_path):
59+
raise NotADirectoryError(f"Directory not found: {file_path}")
60+
61+
for additional_file_path in Path(file_path).glob("*.ttl"):
62+
additional_files.append(str(additional_file_path))
63+
64+
return additional_files
65+
66+
@staticmethod
67+
def _parse_namespace(prefix_namespace: str) -> tuple[Optional[str], Optional[str]]:
68+
"""Parse the prefix namespace string.
69+
70+
:param prefix_namespace: namespace string of the specific prefix
71+
:return namespace_specific_str: dir of the namespace
72+
:return version: version of the model
73+
"""
74+
namespace_specific_str = None
75+
version = None
76+
77+
namespace_info = prefix_namespace.split(":")
78+
if len(namespace_info) == 4:
79+
urn, namespace_id, namespace_specific_str, version = namespace_info
80+
81+
if urn == "urn" and namespace_id == "samm":
82+
version = version.replace("#", "")
83+
84+
return namespace_specific_str, version
85+
86+
def _get_dirs_for_advanced_loading(self, aspect_graph: rdflib.Graph, file_path: str) -> list[str]:
87+
"""Get directories from graph namespaces for advanced loading.
88+
89+
:param aspect_graph:rdflib.Graph
90+
:param file_path: str path to the main file
91+
:return: list of str path for further advanced files loading
92+
"""
93+
paths_for_advanced_loading = []
94+
base_path = Path(file_path).parents[2]
95+
96+
for prefix, namespace in aspect_graph.namespace_manager.namespaces():
97+
namespace_specific_str, version = self._parse_namespace(namespace)
98+
if namespace_specific_str and version:
99+
paths_for_advanced_loading.append(join(base_path, namespace_specific_str, version))
100+
101+
return paths_for_advanced_loading
102+
103+
def _get_list_of_additional_files(self, aspect_graph: rdflib.Graph, file_path: str) -> list[str]:
104+
"""Get a list of additional files for parsing in graph.
105+
106+
:param aspect_graph: rdflib.Graph
107+
:param base_path: base path of the main graph file
108+
:return: list of full path to the additional files
109+
"""
110+
additional_files = []
111+
112+
for file_path in self._get_dirs_for_advanced_loading(aspect_graph, file_path):
113+
additional_files += self._get_additional_files_from_dir(file_path)
114+
115+
return list(set(additional_files))
116+
117+
def _extend_graph_with_prefix_files(self, aspect_graph: rdflib.Graph, file_path: str) -> None:
118+
"""Extend graph with models from prefix namespaces.
119+
120+
:param aspect_graph: rdflib.Graph
121+
:param file_path: str path of the base graph file
122+
"""
123+
additional_files = self._get_list_of_additional_files(aspect_graph, file_path)
124+
125+
if file_path in additional_files:
126+
additional_files.remove(file_path)
127+
128+
for file_path in additional_files:
129+
aspect_graph.parse(file_path, format="turtle")
130+
131+
@staticmethod
132+
def _prepare_file_paths(file_paths: list[Union[str, Path]]):
133+
"""Check and prepare file paths."""
134+
prepared_file_paths = []
135+
136+
for file_path in file_paths:
137+
if not exists(Path(file_path)):
138+
raise FileNotFoundError(f"Could not find a file {file_path}")
139+
140+
prepared_file_paths.append(str(file_path))
141+
142+
return prepared_file_paths
143+
144+
def _get_graph(self, file_paths: list[Union[str, Path]]) -> rdflib.Graph:
145+
"""Get RDF graph object.
146+
147+
:param file_paths: list of absolute paths to the turtle files.
148+
:return: parsed rdflib Graph.
149+
"""
150+
151+
aspect_graph = rdflib.Graph()
152+
153+
for file_path in self._prepare_file_paths(file_paths):
154+
aspect_graph.parse(file_path, format="turtle")
155+
self._extend_graph_with_prefix_files(aspect_graph, file_path)
156+
157+
return aspect_graph
158+
47159
def load_aspect_model_from_multiple_files(
48160
self,
49161
file_paths: list[Union[str, Path]],
50162
aspect_urn: rdflib.URIRef | str = "",
51163
) -> Aspect:
52-
"""creates the aspect specified in urn with all the including properties and operations
53-
with the turtle files after merge them. an initialize a cached memory to store all
54-
instance to make querying them more efficient
164+
"""Load aspect model from multiple files.
55165
56-
Args:
57-
file_paths (list[Union[str, Path]]): path/string list to the turtle files.
166+
Create aspect specified in urn with all the including properties and operations with the turtle files
167+
after merge them. Initialize a cached memory to store all
168+
instance to make querying them more efficient
58169
59-
Returns:
60-
Aspect: instance of the aspect
170+
:param file_paths: path/string list to the turtle files
171+
:param aspect_urn: urn of the Aspect property
172+
:return: instance of the aspect graph
61173
"""
62-
63174
self._cache.reset()
64-
aspect_graph = rdflib.Graph()
65-
66-
for file_path in file_paths:
67-
if isinstance(file_path, Path):
68-
file_path = str(file_path)
69-
aspect_graph.parse(file_path, format="turtle")
70-
175+
aspect_graph = self._get_graph(file_paths)
71176
meta_model_version = self.__extract_samm_version(aspect_graph)
72177

73178
if aspect_urn == "":
@@ -82,48 +187,46 @@ def load_aspect_model_from_multiple_files(
82187

83188
return model_element_factory.create_element(aspect_urn) # type: ignore
84189

85-
def __extract_samm_version(self, aspect_graph: rdflib.Graph) -> str:
86-
"""searches the aspect graph for the currently used version of the SAMM and returns it."""
190+
@staticmethod
191+
def __extract_samm_version(aspect_graph: rdflib.Graph) -> str:
192+
"""Get samm version.
193+
194+
searches the aspect graph for the currently used version of the SAMM and returns it
195+
196+
:param aspect_graph: RDF graph
197+
"""
87198
version = ""
199+
88200
for prefix, namespace in aspect_graph.namespace_manager.namespaces():
89201
if prefix == "samm":
90202
urn_parts = namespace.split(":")
91-
version_part = urn_parts[len(urn_parts) - 1]
92-
version = version_part.replace("#", "")
93-
return version
203+
version = urn_parts[-1].replace("#", "")
204+
94205
return version
95206

96207
def find_by_name(self, element_name: str) -> list[Base]:
97208
"""Find a specific model element by name, and returns the found elements
98209
99-
Args:
100-
name (str): name or pyload of element
101-
102-
Returns:
103-
list[Base]: list of found elements
210+
:param element_name: name or pyload of element
211+
:return: list of found elements
104212
"""
105213
return self._cache.get_by_name(element_name)
106214

107215
def find_by_urn(self, urn: str) -> Optional[Base]:
108216
"""Find a specific model element, and returns it or undefined.
109217
110-
Args:
111-
urn (str): urn of the model element
112-
113-
Returns:
114-
Optional[Base]: return found element or None
218+
:param urn: urn of the model element
219+
:return: found element or None
115220
"""
116221
return self._cache.get_by_urn(urn)
117222

118223
def determine_access_path(self, base_element_name: str) -> list[list[str]]:
119-
"""search for the element in cache first then call "determine_element_access_path"
120-
for every found element
224+
"""Determine the access path.
121225
122-
Args:
123-
base_element_name (str): name of element
226+
Search for the element in cache first then call "determine_element_access_path" for every found element
124227
125-
Returns:
126-
list[list[str]]: list of paths found to access the respective value.
228+
:param base_element_name: name of element
229+
:return: list of paths found to access the respective value.
127230
"""
128231
paths: list[list[str]] = []
129232
base_element_list = self.find_by_name(base_element_name)
@@ -135,11 +238,8 @@ def determine_access_path(self, base_element_name: str) -> list[list[str]]:
135238
def determine_element_access_path(self, base_element: Base) -> list[list[str]]:
136239
"""Determine the path to access the respective value in the Aspect JSON object.
137240
138-
Args:
139-
base_element (Base): Element for determine the path
140-
141-
Returns:
142-
list[list[str]]: list of paths found to access the respective value.
241+
:param base_element: element for determine the path
242+
:return: list of paths found to access the respective value.
143243
"""
144244
path: list[list[str]] = []
145245
if isinstance(base_element, Property):
@@ -151,6 +251,11 @@ def determine_element_access_path(self, base_element: Base) -> list[list[str]]:
151251
return self.__determine_access_path(base_element, path)
152252

153253
def __determine_access_path(self, base_element: Base, path: list[list[str]]) -> list[list[str]]:
254+
"""Determine access path.
255+
256+
:param base_element: element for determine the path
257+
:return: list of paths found to access the respective value.
258+
"""
154259
if base_element is None or base_element.parent_elements is None or len(base_element.parent_elements) == 0:
155260
return path
156261

@@ -170,4 +275,5 @@ def __determine_access_path(self, base_element: Base, path: list[list[str]]) ->
170275
path[index].insert(0, path_segment)
171276

172277
self.__determine_access_path(parent, path) # type: ignore
278+
173279
return path
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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 rdflib.term import Node
13+
14+
from esmf_aspect_meta_model_python.base.data_types.data_type import DataType
15+
from esmf_aspect_meta_model_python.impl.data_types.default_data_type import DefaultDataType
16+
from esmf_aspect_meta_model_python.loader.instantiator_base import InstantiatorBase
17+
from esmf_aspect_meta_model_python.loader.rdf_helper import RdfHelper
18+
19+
20+
class DatatypeInstantiator(InstantiatorBase[DataType]):
21+
def _create_instance(self, element_node: Node) -> DataType:
22+
if element_node is None:
23+
raise ValueError("Data Type is not specified")
24+
25+
return DefaultDataType(RdfHelper.to_python(element_node), self._meta_model_version)

core/esmf-aspect-meta-model-python/tests/integration/resources/characteristics/AspectWithBlankNode.ttl renamed to core/esmf-aspect-meta-model-python/tests/integration/resources/org.eclipse.esmf.test.characteristics/2.0.0/AspectWithBlankNode.ttl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#
1010
# SPDX-License-Identifier: MPL-2.0
1111

12-
@prefix : <urn:samm:org.eclipse.esmf.test:1.0.0#> .
12+
@prefix : <urn:samm:org.eclipse.esmf.test.characteristics:2.0.0#> .
1313
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
1414
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
1515
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

core/esmf-aspect-meta-model-python/tests/integration/resources/characteristics/AspectWithCode.ttl renamed to core/esmf-aspect-meta-model-python/tests/integration/resources/org.eclipse.esmf.test.characteristics/2.0.0/AspectWithCode.ttl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#
1010
# SPDX-License-Identifier: MPL-2.0
1111

12-
@prefix : <urn:samm:org.eclipse.esmf.test:1.0.0#> .
12+
@prefix : <urn:samm:org.eclipse.esmf.test.characteristics:2.0.0#> .
1313
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
1414
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
1515
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

core/esmf-aspect-meta-model-python/tests/integration/resources/characteristics/AspectWithCollection.ttl renamed to core/esmf-aspect-meta-model-python/tests/integration/resources/org.eclipse.esmf.test.characteristics/2.0.0/AspectWithCollection.ttl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#
1010
# SPDX-License-Identifier: MPL-2.0
1111

12-
@prefix : <urn:samm:org.eclipse.esmf.test:1.0.0#> .
12+
@prefix : <urn:samm:org.eclipse.esmf.test.characteristics:2.0.0#> .
1313
@prefix samm: <urn:samm:org.eclipse.esmf.samm:meta-model:2.1.0#> .
1414
@prefix samm-c: <urn:samm:org.eclipse.esmf.samm:characteristic:2.1.0#> .
1515
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

0 commit comments

Comments
 (0)