99#
1010# SPDX-License-Identifier: MPL-2.0
1111
12+ from os .path import exists , join
1213from pathlib import Path
1314from 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
0 commit comments