def build_config(config_dicts, ignore_names): """ Builds the model from the configuration Arguments: config_dicts: The parsed configuration file ignore_names: A set of names that should be ignored during the loading. """ if "main" not in config_dicts: raise Exception("Configuration does not contain the main block.") existing_objects = dict() main_config = config_dicts['main'] configuration = dict() # TODO ensure tf_manager goes last in a better way for key, value in sorted(main_config.items(), key=lambda t: t[0] if t[0] != 'tf_manager' else 'zzz'): if key not in ignore_names: try: configuration[key] = build_object(value, config_dicts, existing_objects, 0) except Exception as exc: raise ConfigBuildException(key, exc) from None return configuration
def instantiate_class(name: str, all_dicts: Dict[str, Any], existing_objects: Dict[str, Any], depth: int) -> Any: """Instantiate a class from the configuration. Arguments: see help(build_object) """ if name not in all_dicts: debug(str(all_dicts), "configBuild") raise ConfigInvalidValueException(name, "Undefined object") this_dict = all_dicts[name] if "class" not in this_dict: raise ConfigInvalidValueException(name, "Undefined object type") clazz = this_dict["class"].create() if not isclass(clazz) and not isfunction(clazz): raise ConfigInvalidValueException( name, "Cannot instantiate object with '{}'".format(clazz)) # prepare the arguments for the constructor arguments = dict() for key, value in this_dict.items(): if key == "class": continue arguments[key] = build_object(value, all_dicts, existing_objects, depth + 1) # get a signature of the constructing function construct_sig = signature(clazz) try: # try to bound the arguments to the signature bounded_params = construct_sig.bind(**arguments) except TypeError as exc: raise ConfigBuildException(clazz, exc) debug("Instantiating class {} with arguments {}".format(clazz, arguments), "configBuild") # call the function with the arguments # NOTE: any exception thrown from the body of the constructor is # not worth catching here obj = clazz(*bounded_params.args, **bounded_params.kwargs) debug("Class {} initialized into object {}".format(clazz, obj), "configBuild") return obj
def build_config( config_dicts: Dict[str, Any], ignore_names: Set[str], warn_unused: bool = False) -> Tuple[Dict[str, Any], Dict[str, Any]]: """Build the model from the configuration. Arguments: config_dicts: The parsed configuration file ignore_names: A set of names that should be ignored during the loading. warn_unused: Emit a warning if there are unused sections. Returns: A tuple containing a dictionary corresponding to the main section and a dictionary mapping section names to objects. """ if "main" not in config_dicts: raise Exception("Configuration does not contain the main block.") existing_objects = collections.OrderedDict() # type: Dict[str, Any] main_config = config_dicts["main"] existing_objects["main"] = Namespace(**main_config) configuration = collections.OrderedDict() # type: Dict[str, Any] # TODO ensure tf_manager goes last in a better way for key, value in sorted(main_config.items(), key=lambda t: t[0] if t[0] != "tf_manager" else "zzz"): if key not in ignore_names: try: configuration[key] = build_object(value, config_dicts, existing_objects, 0) except Exception as exc: raise ConfigBuildException(key, exc) from None if warn_unused: existing_names = set(existing_objects.keys()) | {"main"} unused = config_dicts.keys() - existing_names if unused: warn("Configuration contains unused sections: " + str(unused) + ".") return configuration, existing_objects
def build_config(config_dicts: Dict[str, Any], ignore_names: Set[str], warn_unused: bool = False) -> Dict[str, Any]: """ Builds the model from the configuration Arguments: config_dicts: The parsed configuration file ignore_names: A set of names that should be ignored during the loading. warn_unused: Emit a warning if there are unused sections. """ if "main" not in config_dicts: raise Exception("Configuration does not contain the main block.") existing_objects = collections.OrderedDict() # type: Dict[str, Any] main_config = config_dicts['main'] configuration = collections.OrderedDict() # type: Dict[str, Any] # TODO ensure tf_manager goes last in a better way for key, value in sorted(main_config.items(), key=lambda t: t[0] if t[0] != 'tf_manager' else 'zzz'): if key not in ignore_names: try: configuration[key] = build_object(value, config_dicts, existing_objects, 0) except Exception as exc: raise ConfigBuildException(key, exc) from None if warn_unused: existing_names = {x[7:] for x in existing_objects.keys()} | {'main'} unused = config_dicts.keys() - existing_names if unused: warn("Configuration contains unused sections: " + str(unused) + ".") return configuration
def instantiate_class(name: str, all_dicts: Dict[str, Any], existing_objects: Dict[str, Any], depth: int) -> Any: """Instantiate a class from the configuration. Arguments: see help(build_object) """ if name not in all_dicts: debug(str(all_dicts), "configBuild") raise ConfigInvalidValueException(name, "Undefined object") this_dict = all_dicts[name] if "class" not in this_dict: raise ConfigInvalidValueException(name, "Undefined object type") clazz = this_dict["class"].create() if not isclass(clazz) and not isfunction(clazz): raise ConfigInvalidValueException( name, "Cannot instantiate object with '{}'".format(clazz)) # prepare the arguments for the constructor arguments = dict() for key, value in this_dict.items(): if key == "class": continue arguments[key] = build_object(value, all_dicts, existing_objects, depth + 1) # get a signature of the constructing function construct_sig = signature(clazz) # if a signature contains a "name" attribute which is not in arguments, # replace it with the name of the section if "name" in construct_sig.parameters and "name" not in arguments: annotation = construct_sig.parameters["name"].annotation if annotation == Parameter.empty: debug( "No type annotation for the 'name' parameter in " "class/function {}. Default value will not be used.".format( this_dict["class"].clazz), "configBuild") elif annotation != str: debug( "Type annotation for the 'name' parameter in class/function " "{} is not 'str'. Default value will not be used.".format( this_dict["class"].clazz), "configBuild") debug("Annotation is {}".format(str(annotation))) else: debug( "Using default 'name' for object {}".format( this_dict["class"].clazz), "configBuild") arguments["name"] = name try: # try to bound the arguments to the signature bounded_params = construct_sig.bind(**arguments) except TypeError as exc: raise ConfigBuildException(clazz, exc) debug("Instantiating class {} with arguments {}".format(clazz, arguments), "configBuild") # call the function with the arguments # NOTE: any exception thrown from the body of the constructor is # not worth catching here obj = clazz(*bounded_params.args, **bounded_params.kwargs) debug("Class {} initialized into object {}".format(clazz, obj), "configBuild") return obj