From cb322f72db746827fd87f1b9a49f7c6627e8fff2 Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Thu, 13 Oct 2016 18:09:07 +0200 Subject: [PATCH] Add persistent notifications to bootstrap (#3738) * Add persistent notifications to bootstrap * Rebase, Fix test --- homeassistant/bootstrap.py | 27 ++++++++++++++++++++++----- homeassistant/scripts/check_config.py | 5 +++-- tests/scripts/test_check_config.py | 16 +++++++++------- tests/test_bootstrap.py | 3 ++- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 57adcd74fa4..4d4887a1a52 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -32,6 +32,8 @@ _CURRENT_SETUP = [] ATTR_COMPONENT = 'component' ERROR_LOG_FILENAME = 'home-assistant.log' +_PERSISTENT_PLATFORMS = set() +_PERSISTENT_VALIDATION = set() def setup_component(hass: core.HomeAssistant, domain: str, @@ -149,7 +151,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict, try: config = component.CONFIG_SCHEMA(config) except vol.Invalid as ex: - log_exception(ex, domain, config) + log_exception(ex, domain, config, hass) return None elif hasattr(component, 'PLATFORM_SCHEMA'): @@ -159,7 +161,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict, try: p_validated = component.PLATFORM_SCHEMA(p_config) except vol.Invalid as ex: - log_exception(ex, domain, config) + log_exception(ex, domain, config, hass) continue # Not all platform components follow same pattern for platforms @@ -181,7 +183,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict, p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.Invalid as ex: log_exception(ex, '{}.{}'.format(domain, p_name), - p_validated) + p_validated, hass) continue platforms.append(p_validated) @@ -211,6 +213,13 @@ def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, # Not found if platform is None: _LOGGER.error('Unable to find platform %s', platform_path) + + _PERSISTENT_PLATFORMS.add(platform_path) + message = ('Unable to find the following platforms: ' + + ', '.join(list(_PERSISTENT_PLATFORMS)) + + '(please check your configuration)') + persistent_notification.create( + hass, message, 'Invalid platforms', 'platform_errors') return None # Already loaded @@ -257,7 +266,7 @@ def from_config_dict(config: Dict[str, Any], try: conf_util.process_ha_core_config(hass, core_config) except vol.Invalid as ex: - log_exception(ex, 'homeassistant', core_config) + log_exception(ex, 'homeassistant', core_config, hass) return None conf_util.process_ha_config_upgrade(hass) @@ -305,6 +314,7 @@ def from_config_dict(config: Dict[str, Any], hass.loop.run_until_complete( hass.loop.run_in_executor(None, component_setup) ) + return hass @@ -397,9 +407,16 @@ def _ensure_loader_prepared(hass: core.HomeAssistant) -> None: loader.prepare(hass) -def log_exception(ex, domain, config): +def log_exception(ex, domain, config, hass=None): """Generate log exception for config validation.""" message = 'Invalid config for [{}]: '.format(domain) + if hass is not None: + _PERSISTENT_VALIDATION.add(domain) + message = ('The following platforms contain invalid configuration: ' + + ', '.join(list(_PERSISTENT_VALIDATION)) + + ' (please check your configuration)') + persistent_notification.create( + hass, message, 'Invalid config', 'invalid_config') if 'extra keys not allowed' in ex.error_message: message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\ diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index b3df02e8b34..f8b6fc6e69b 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -199,9 +199,10 @@ def check(config_path): res['secrets'][node.value] = val return val - def mock_except(ex, domain, config): # pylint: disable=unused-variable + def mock_except(ex, domain, config, # pylint: disable=unused-variable + hass=None): """Mock bootstrap.log_exception.""" - MOCKS['except'][1](ex, domain, config) + MOCKS['except'][1](ex, domain, config, hass) res['except'][domain] = config.get(domain, config) # Patches to skip functions diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 056bb074afa..efe99f86ebd 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -74,13 +74,15 @@ class TestCheckConfig(unittest.TestCase): with patch_yaml_files(files): res = check_config.check(get_test_config_dir('component.yaml')) change_yaml_files(res) - self.assertDictEqual({ - 'components': {}, - 'except': {'http': {'password': 'err123'}}, - 'secret_cache': {}, - 'secrets': {}, - 'yaml_files': ['.../component.yaml'] - }, res) + + self.assertDictEqual({}, res['components']) + self.assertDictEqual( + {'http': {'password': 'err123'}}, + res['except'] + ) + self.assertDictEqual({}, res['secret_cache']) + self.assertDictEqual({}, res['secrets']) + self.assertListEqual(['.../component.yaml'], res['yaml_files']) files = { 'platform.yaml': (BASE_CONFIG + 'mqtt:\n\n' diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index 0f675d7f012..d3f3caf795c 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -269,11 +269,12 @@ class TestBootstrap: def test_home_assistant_core_config_validation(self): """Test if we pass in wrong information for HA conf.""" # Extensive HA conf validation testing is done in test_config.py + hass = get_test_home_assistant() assert None is bootstrap.from_config_dict({ 'homeassistant': { 'latitude': 'some string' } - }) + }, hass=hass) def test_component_setup_with_validation_and_dependency(self): """Test all config is passed to dependencies."""