diff --git a/pyaml/accelerator.py b/pyaml/accelerator.py index 68bf2e9c..fd625f4a 100644 --- a/pyaml/accelerator.py +++ b/pyaml/accelerator.py @@ -88,5 +88,16 @@ def design(self) -> Simulator: return self.__design @staticmethod - def load(filename:str) -> "Accelerator": - return load_accelerator(filename) + def load(filename:str, use_fast_loader:bool = False) -> "Accelerator": + """ + Load an accelerator from a config file. + + Parameters + ---------- + filename : str + Configuration file name, yaml or json. + use_fast_loader : bool + Use fast yaml loader. When specified, no line number are reported in case of error, + only the element name that triggered the error will be reported in the exception) + """ + return load_accelerator(filename,use_fast_loader) diff --git a/pyaml/configuration/factory.py b/pyaml/configuration/factory.py index ea517d8f..5c9ae23d 100644 --- a/pyaml/configuration/factory.py +++ b/pyaml/configuration/factory.py @@ -53,7 +53,7 @@ def handle_validation_error(self, e, type_str:str, location_str:str, field_locat else: field = err['loc'][0] message = f"'{field}': {msg}" - if field in field_locations: + if field_locations and field in field_locations: file, line, col = field_locations[field] loc = f"{file} at line {line}, colum {col}" message += f" {loc}" diff --git a/pyaml/configuration/fileloader.py b/pyaml/configuration/fileloader.py index 5a022e6a..5b0d92b7 100644 --- a/pyaml/configuration/fileloader.py +++ b/pyaml/configuration/fileloader.py @@ -8,6 +8,7 @@ import yaml from yaml.loader import SafeLoader +from yaml import CLoader from yaml.constructor import ConstructorError import collections.abc @@ -47,26 +48,26 @@ def __init__(self, error_filename:str, path_stack:list[Path]): super().__init__(f"Circular file inclusion of {error_filename}. File list before reaching it: {parent_file_stack}") pass -def load_accelerator(filename:str, paths_stack:list=None) -> "Accelerator": - """ Load an instrument from file.""" +def load_accelerator(filename:str, use_fast_loader:bool = False) -> "Accelerator": + """ Load an accelerator from file.""" # Asume that all files are referenced from folder where main AML file is stored if not os.path.exists(filename): raise PyAMLException(f"{filename} file not found") rootfolder = os.path.abspath(os.path.dirname(filename)) set_root_folder(rootfolder) - config_dict = load(os.path.basename(filename)) + config_dict = load(os.path.basename(filename),None,use_fast_loader) aml = Factory.depth_first_build(config_dict) Factory.clear() return aml -def load(filename:str, paths_stack:list=None) -> Union[dict,list]: +def load(filename:str, paths_stack:list=None, use_fast_loader:bool = False) -> Union[dict,list]: """Load recursively a configuration setup""" if filename.endswith(".yaml") or filename.endswith(".yml"): - l = YAMLLoader(filename, paths_stack) + l = YAMLLoader(filename, paths_stack, use_fast_loader) elif filename.endswith(".json"): - l = JSONLoader(filename, paths_stack) + l = JSONLoader(filename, paths_stack, use_fast_loader) else: raise PyAMLException(f"{filename} File format not supported (only .yaml .yml or .json)") return l.load() @@ -94,7 +95,7 @@ def expand_dict(self,d:dict): for key, value in d.items(): try: if hasToExpand(value): - d[key] = load(value, self.files_stack) + d[key] = load(value, self.files_stack, self.use_fast_loader) else: self.expand(value) except PyAMLConfigCyclingException as pyaml_ex: @@ -155,21 +156,24 @@ def construct_mapping(self, node, deep=False): # YAML loader class YAMLLoader(Loader): - def __init__(self, filename: str, parent_paths_stack:list): + def __init__(self, filename: str, parent_paths_stack:list,use_fast_loader:bool): super().__init__(filename, parent_paths_stack) + self._loader = SafeLineLoader if not use_fast_loader else CLoader + self.use_fast_loader = use_fast_loader def load(self) -> Union[dict,list]: logger.log(logging.DEBUG, f"Loading YAML file '{self.path}'") with open(self.path) as file: try: - return self.expand(yaml.load(file,Loader=SafeLineLoader)) + return self.expand(yaml.load(file,Loader=self._loader)) except yaml.YAMLError as e: raise PyAMLException(str(self.path) + ": " + str(e)) from e # JSON loader class JSONLoader(Loader): - def __init__(self, filename: str, parent_paths_stack:list): + def __init__(self, filename: str, parent_paths_stack:list,use_fast_loader:bool): super().__init__(filename, parent_paths_stack) + self.use_fast_loader = False def load(self) -> Union[dict,list]: logger.log(logging.DEBUG, f"Loading JSON file '{self.path}'") diff --git a/tests/test_arrays.py b/tests/test_arrays.py index 5b16681f..79ed6e56 100644 --- a/tests/test_arrays.py +++ b/tests/test_arrays.py @@ -174,7 +174,7 @@ def test_arrays(install_test_package): # Test dynamic arrays - sr:Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml") + sr:Accelerator = Accelerator.load("tests/config/EBSOrbit.yaml",use_fast_loader=True) ae = ElementArray("All",sr.design.get_all_elements()) acfm = ElementArray("AllCFM",sr.design.get_all_cfm_magnets(),use_aggregator=False)