def parse_config(config: Dict, macros: Dict = None) -> Dict: """Fill macro parameters and references in config from macros. Example ------- >>> from deepr.config import parse_config >>> config = {"x": "$params:x", "y": 2} >>> macros = {"params": {"x": 1}} >>> parse_config(config, macros) {'x': 1, 'y': 2} Parameters ---------- config : Dict Config dictionary macros : Dict, optional Dictionary of macro parameters. Returns ------- Dict Parsed Config, without macro parameters and references. Raises ------ ValueError If some macro parameter in config not found in macros. If some references not found. """ # Evaluate macros in order to account for inter macro params if macros is not None: macros_eval = dict() # type: ignore for macro in macros_eval_order(macros): macro_eval = fill_macros(macros[macro], macros_eval) assert_no_macros(macro_eval) macros_eval[macro] = from_config(macro_eval) else: macros_eval = None # type: ignore # Fill macros and references in config, evaluate and return config_no_macro = fill_macros(config, macros_eval) assert_no_macros(config_no_macro) references = default_references(config=config, macros=macros, macros_eval=macros_eval) parsed = fill_references(config_no_macro, references) # Look for macro params that were not used if macros_eval is not None: for macro, params in macros_eval.items(): used = find_macro_params({ "config": config, "macros": macros }, macro) for param in set(params) - set(used): LOGGER.warning( f"- MACRO PARAM NOT USED: macro = '{macro}', param = '{param}'" ) return parsed
def add_macro_params(config: Dict, macro: str, params: List[str]) -> Dict: """Add new macro parameters in config automatically. Parameters ---------- config : Dict Config to modify macro : str Name of the new macro params : List[str] List of new parameter names Returns ------- Dict A new config with new macro parameters Raises ------ ValueError If one param has no reference in config after adding new params. """ # Add new macro params to config old_counts = Counter(find_macro_params(config, macro)) values = {key: f"{MACRO}{macro}:{key}" for key in params} config = replace_values(config, values) # Check that the macro params in config are consistent new_counts = Counter(find_macro_params(config, macro)) for param in params: old_count = old_counts[param] new_count = new_counts[param] if new_count == 0: raise ValueError(f"Parameter '{param}': no reference in config.") if new_count - old_count == 0: LOGGER.warning(f"Parameter '{param}': NO NEW REFERENCE IN CONFIG.") if new_count - old_count == 1: LOGGER.info(f"Parameter '{param}': 1 new reference in config.") if new_count - old_count > 1: LOGGER.warning( f"Parameter '{param}': {new_count - old_count} NEW REFERENCES IN CONFIG." ) return config