def _recursive_merge(conf: dict[str, Any], package: dict[str, Any]) -> bool | str: """Merge package into conf, recursively.""" error: bool | str = False for key, pack_conf in package.items(): if isinstance(pack_conf, dict): if not pack_conf: continue conf[key] = conf.get(key, OrderedDict()) error = _recursive_merge(conf=conf[key], package=pack_conf) elif isinstance(pack_conf, list): conf[key] = cv.remove_falsy( cv.ensure_list(conf.get(key)) + cv.ensure_list(pack_conf)) else: if conf.get(key) is not None: return key conf[key] = pack_conf return error
async def merge_packages_config( opp: OpenPeerPower, config: dict, packages: dict[str, Any], _log_pkg_error: Callable = _log_pkg_error, ) -> dict: """Merge packages into the top-level configuration. Mutate config.""" PACKAGES_CONFIG_SCHEMA(packages) for pack_name, pack_conf in packages.items(): for comp_name, comp_conf in pack_conf.items(): if comp_name == CONF_CORE: continue # If component name is given with a trailing description, remove it # when looking for component domain = comp_name.split(" ")[0] try: integration = await async_get_integration_with_requirements( opp, domain) component = integration.get_component() except INTEGRATION_LOAD_EXCEPTIONS as ex: _log_pkg_error(pack_name, comp_name, config, str(ex)) continue merge_list = hasattr(component, "PLATFORM_SCHEMA") if not merge_list and hasattr(component, "CONFIG_SCHEMA"): merge_list = _identify_config_schema(component) == "list" if merge_list: config[comp_name] = cv.remove_falsy( cv.ensure_list(config.get(comp_name)) + cv.ensure_list(comp_conf)) continue if comp_conf is None: comp_conf = OrderedDict() if not isinstance(comp_conf, dict): _log_pkg_error(pack_name, comp_name, config, "cannot be merged. Expected a dict.") continue if comp_name not in config or config[comp_name] is None: config[comp_name] = OrderedDict() if not isinstance(config[comp_name], dict): _log_pkg_error( pack_name, comp_name, config, "cannot be merged. Dict expected in main config.", ) continue error = _recursive_merge(conf=config[comp_name], package=comp_conf) if error: _log_pkg_error(pack_name, comp_name, config, f"has duplicate key '{error}'") return config
def test_remove_falsy(): """Test remove falsy.""" assert cv.remove_falsy([0, None, 1, "1", {}, [], ""]) == [1, "1"]