Source code for tickit.utils.configuration.loading

from importlib import import_module
from typing import Any, Dict, List, Optional, Type

import yaml
from apischema import deserialize
from apischema.conversions import AnyConversion, Conversion
from apischema.conversions.conversions import Conversion
from apischema.conversions.converters import default_deserialization

from tickit.core.components.component import ComponentConfig
from tickit.utils.configuration.configurable import is_tagged_union


[docs]def importing_conversion(typ: Type) -> Optional[AnyConversion]: """Create a conversion that imports the module of a ComponentConfig. When a ComponentConfig is requested from a dict, take its fully qualified name from the tagged union dict and import it before deserializing it """ if is_tagged_union[typ]: def conversion(d: Dict[str, Any]): # We can't use the deserialization union above as the classes # haven't been imported so won't appear in __subclasses__, so use a # single element dict instead assert len(d) == 1, d fullname, args = list(d.items())[0] pkg, clsname = fullname.rsplit(".", maxsplit=1) cls = getattr(import_module(pkg), clsname) return deserialize(cls, args, default_conversion=importing_conversion) return Conversion(conversion, source=dict, target=typ) return default_deserialization(typ)
[docs]def read_configs(config_path) -> List[ComponentConfig]: """A utility function which reads and deserializes configs. A utility function which reads config files, performs yaml deserialization, loads the required internal and external modules then subsequently performs apischema deserialization to produce a list of component configuration objects. Args: config_path ([type]): The path to the config file. Returns: List[Component]: A list of component configuration objects. """ with open(config_path, "r") as config_file: yaml_struct = yaml.load(config_file, Loader=yaml.Loader) configs = deserialize( List[ComponentConfig], yaml_struct, default_conversion=importing_conversion, ) return configs