1515
1616logger = logging .getLogger (__name__ )
1717
18- #TODO
19- #Implement cycle detection in case of wrong yaml/json link that creates a cycle
18+ accepted_suffixes = [".yaml" , ".yml" , ".json" ]
2019
21- def load (filename :str ) -> Union [dict ,list ]:
20+ def load (filename :str , paths_stack : list = None ) -> Union [dict ,list ]:
2221 """Load recursively a configuration setup"""
2322 if filename .endswith (".yaml" ) or filename .endswith (".yml" ):
24- l = YAMLLoader (filename )
23+ l = YAMLLoader (filename , paths_stack )
2524 elif filename .endswith (".json" ):
26- l = JSONLoader (filename )
25+ l = JSONLoader (filename , paths_stack )
2726 else :
2827 raise PyAMLException (f"{ filename } File format not supported (only .yaml .yml or .json)" )
29- return l .load (filename )
28+ return l .load ()
29+
30+ # Expand condition
31+ def hasToExpand (value ):
32+ return isinstance (value ,str ) and any (value .endswith (suffix ) for suffix in accepted_suffixes )
33+
3034
3135# Loader base class (nested files expansion)
3236class Loader :
3337
34- def __init__ (self , filename :str ):
35- self .suffixes = []
38+ def __init__ (self , filename :str , parent_path_stack :list ):
3639 self .path :Path = get_root_folder () / filename
40+ self .files_stack = []
41+ if parent_path_stack :
42+ if any (self .path .samefile (parent_path ) for parent_path in parent_path_stack ):
43+ raise PyAMLException (f"A cycle has been detected: { parent_path_stack } " )
44+ self .files_stack .extend (parent_path_stack )
45+ self .files_stack .append (self .path )
3746
38- # Expand condition
39- def hasToExpand (self ,value ):
40- return isinstance (value ,str ) and any (value .endswith (suffix ) for suffix in self .suffixes )
4147
4248 # Recursively expand a dict
4349 def expand_dict (self ,d :dict ):
4450 for key , value in d .items ():
45- if self . hasToExpand (value ):
46- d [key ] = load (value )
51+ if hasToExpand (value ):
52+ d [key ] = load (value , self . files_stack )
4753 else :
4854 self .expand (value )
4955
5056 # Recursively expand a list
5157 def expand_list (self ,l :list ):
5258 for idx ,value in enumerate (l ):
53- if self . hasToExpand (value ):
54- l [idx ] = load (value )
59+ if hasToExpand (value ):
60+ l [idx ] = load (value , self . files_stack )
5561 else :
5662 self .expand (value )
5763
@@ -65,7 +71,7 @@ def expand(self,obj: Union[dict,list]):
6571
6672 # Load a file
6773 def load (self ) -> Union [dict ,list ]:
68- raise Exception (str (self .path ) + ": load() method not implemented" )
74+ raise PyAMLException (str (self .path ) + ": load() method not implemented" )
6975
7076class SafeLineLoader (SafeLoader ):
7177
@@ -93,22 +99,24 @@ def construct_mapping(self, node, deep=False):
9399
94100# YAML loader
95101class YAMLLoader (Loader ):
96-
97- def load (self ,fileName :str ) -> Union [dict ,list ]:
98- self .path :Path = get_root_folder () / fileName
99- self .suffixes = [".yaml" ,".yml" ]
102+ def __init__ (self , filename : str , parent_paths_stack :list ):
103+ super ().__init__ (filename , parent_paths_stack )
104+
105+ def load (self ) -> Union [dict ,list ]:
106+ logger .log (logging .DEBUG , f"Loading YAML file '{ self .path } '" )
100107 with open (self .path ) as file :
101108 try :
102109 return self .expand (yaml .load (file ,Loader = SafeLineLoader ))
103110 except yaml .YAMLError as e :
104- raise Exception ( self .path + ": " + str (e ))
111+ raise PyAMLException ( str ( self .path ) + ": " + str (e )) from e
105112
106113# JSON loader
107114class JSONLoader (Loader ):
115+ def __init__ (self , filename : str , parent_paths_stack :list ):
116+ super ().__init__ (filename , parent_paths_stack )
108117
109- def load (self , fileName : str ) -> Union [dict ,list ]:
118+ def load (self ) -> Union [dict ,list ]:
110119 logger .log (logging .DEBUG , f"Loading JSON file '{ self .path } '" )
111- self .suffixes = [".json" ]
112120 with open (self .path ) as file :
113121 try :
114122 return self .expand (json .load (file ))
0 commit comments