diff --git a/homeassistant/config.py b/homeassistant/config.py index 44bf542f7cd..2906f07a307 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -548,15 +548,15 @@ def _identify_config_schema(module): return '', schema -def _recursive_merge(pack_name, comp_name, config, conf, package): +def _recursive_merge(conf, package): """Merge package into conf, recursively.""" + error = False for key, pack_conf in package.items(): if isinstance(pack_conf, dict): if not pack_conf: continue conf[key] = conf.get(key, OrderedDict()) - _recursive_merge(pack_name, comp_name, config, - conf=conf[key], package=pack_conf) + error = _recursive_merge(conf=conf[key], package=pack_conf) elif isinstance(pack_conf, list): if not pack_conf: @@ -566,11 +566,10 @@ def _recursive_merge(pack_name, comp_name, config, conf, package): else: if conf.get(key) is not None: - _log_pkg_error( - pack_name, comp_name, config, - 'has keys that are defined multiple times') + return key else: conf[key] = pack_conf + return error def merge_packages_config(hass, config, packages, @@ -605,39 +604,34 @@ def merge_packages_config(hass, config, packages, config[comp_name].extend(cv.ensure_list(comp_conf)) continue - if merge_type == 'dict': - if comp_conf is None: - comp_conf = OrderedDict() + 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: - 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 - - for key, val in comp_conf.items(): - if key in config[comp_name]: - _log_pkg_error(pack_name, comp_name, config, - "duplicate key '{}'".format(key)) - continue - config[comp_name][key] = val - continue - - # The last merge type are sections that require recursive merging - if comp_name in config: - _recursive_merge(pack_name, comp_name, config, - conf=config[comp_name], package=comp_conf) + if not isinstance(comp_conf, dict): + _log_pkg_error( + pack_name, comp_name, config, + "cannot be merged. Expected a dict.") continue - config[comp_name] = comp_conf + + 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 + if not isinstance(comp_conf, dict): + _log_pkg_error( + pack_name, comp_name, config, + "cannot be merged. Dict expected in package.") + continue + + error = _recursive_merge(conf=config[comp_name], + package=comp_conf) + if error: + _log_pkg_error(pack_name, comp_name, config, + "has duplicate key '{}'".format(error)) return config diff --git a/tests/test_config.py b/tests/test_config.py index d22d6b2acfd..717a3f62ec9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -589,7 +589,7 @@ def test_merge(merge_log_err, hass): assert len(config['input_boolean']) == 2 assert len(config['input_select']) == 1 assert len(config['light']) == 3 - assert config['wake_on_lan'] is None + assert isinstance(config['wake_on_lan'], OrderedDict) def test_merge_try_falsy(merge_log_err, hass): @@ -656,6 +656,14 @@ def test_merge_type_mismatch(merge_log_err, hass): def test_merge_once_only_keys(merge_log_err, hass): """Test if we have a merge for a comp that may occur only once. Keys.""" + packages = {'pack_2': {'api': None}} + config = { + config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, + 'api': None, + } + config_util.merge_packages_config(hass, config, packages) + assert config['api'] == OrderedDict() + packages = {'pack_2': {'api': { 'key_3': 3, }}} @@ -755,7 +763,7 @@ def test_merge_duplicate_keys(merge_log_err, hass): } config = { config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, - 'input_select': {'ib1': None}, + 'input_select': {'ib1': 1}, } config_util.merge_packages_config(hass, config, packages)