diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 0676cec7fad..c764bfe8c21 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -115,11 +115,6 @@ async def async_from_config_dict(config: Dict[str, Any], conf_util.merge_packages_config( hass, config, core_config.get(conf_util.CONF_PACKAGES, {})) - # Ensure we have no None values after merge - for key, value in config.items(): - if not value: - config[key] = {} - hass.config_entries = config_entries.ConfigEntries(hass, config) await hass.config_entries.async_load() diff --git a/homeassistant/config.py b/homeassistant/config.py index 5f7107f95ae..4fc77bd81cd 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -332,7 +332,7 @@ async def async_hass_config_yaml(hass: HomeAssistant) -> Dict: """Load YAML from a Home Assistant configuration file. This function allow a component inside the asyncio loop to reload its - configuration by itself. + configuration by itself. Include package merge. This method is a coroutine. """ @@ -341,7 +341,10 @@ async def async_hass_config_yaml(hass: HomeAssistant) -> Dict: if path is None: raise HomeAssistantError( "Config file not found in: {}".format(hass.config.config_dir)) - return load_yaml_config_file(path) + config = load_yaml_config_file(path) + core_config = config.get(CONF_CORE, {}) + merge_packages_config(hass, config, core_config.get(CONF_PACKAGES, {})) + return config return await hass.async_add_executor_job(_load_hass_yaml_config) diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index 1e77454a8d5..ac341e8f58a 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -327,11 +327,6 @@ def check_ha_config_file(hass): hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error) core_config.pop(CONF_PACKAGES, None) - # Ensure we have no None values after merge - for key, value in config.items(): - if not value: - config[key] = {} - # Filter out repeating config sections components = set(key.split(' ')[0] for key in config.keys()) diff --git a/tests/test_config.py b/tests/test_config.py index 0d248e2b170..212fc247eb9 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -6,8 +6,10 @@ import unittest import unittest.mock as mock from collections import OrderedDict +import asynctest import pytest from voluptuous import MultipleInvalid, Invalid +import yaml from homeassistant.core import DOMAIN, HomeAssistantError, Config import homeassistant.config as config_util @@ -31,7 +33,8 @@ from homeassistant.components.config.customize import ( CONFIG_PATH as CUSTOMIZE_CONFIG_PATH) import homeassistant.scripts.check_config as check_config -from tests.common import get_test_config_dir, get_test_home_assistant +from tests.common import ( + get_test_config_dir, get_test_home_assistant, patch_yaml_files) CONFIG_DIR = get_test_config_dir() YAML_PATH = os.path.join(CONFIG_DIR, config_util.YAML_CONFIG_FILE) @@ -550,6 +553,30 @@ class TestConfig(unittest.TestCase): ).result() == 'bad' +@asynctest.mock.patch('homeassistant.config.os.path.isfile', + mock.Mock(return_value=True)) +async def test_async_hass_config_yaml_merge(merge_log_err, hass): + """Test merge during async config reload.""" + config = { + config_util.CONF_CORE: {config_util.CONF_PACKAGES: { + 'pack_dict': { + 'input_boolean': {'ib1': None}}}}, + 'input_boolean': {'ib2': None}, + 'light': {'platform': 'test'} + } + + files = {config_util.YAML_CONFIG_FILE: yaml.dump(config)} + with patch_yaml_files(files, True): + conf = await config_util.async_hass_config_yaml(hass) + + assert merge_log_err.call_count == 0 + assert conf[config_util.CONF_CORE].get(config_util.CONF_PACKAGES) \ + is not None + assert len(conf) == 3 + assert len(conf['input_boolean']) == 2 + assert len(conf['light']) == 1 + + # pylint: disable=redefined-outer-name @pytest.fixture def merge_log_err(hass):