From 0d14920758a15b32db3289339beb16baf813114c Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Thu, 3 Nov 2016 04:31:09 +0200 Subject: [PATCH] Component setup error messages with markdown (#3919) * Remove_dev_link_async * callback --- homeassistant/bootstrap.py | 48 ++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 294645f693b..fdcdb5d4fe2 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -31,8 +31,8 @@ _LOGGER = logging.getLogger(__name__) ATTR_COMPONENT = 'component' ERROR_LOG_FILENAME = 'home-assistant.log' -_PERSISTENT_PLATFORMS = set() -_PERSISTENT_VALIDATION = set() +_PERSISTENT_ERRORS = {} +HA_COMPONENT_URL = '[{}](https://home-assistant.io/components/{}/)' def setup_component(hass: core.HomeAssistant, domain: str, @@ -63,12 +63,14 @@ def async_setup_component(hass: core.HomeAssistant, domain: str, # OrderedSet is empty if component or dependencies could not be resolved if not components: + _async_persistent_notification(hass, domain, True) return False for component in components: res = yield from _async_setup_component(hass, component, config) if not res: _LOGGER.error('Component %s failed to setup', component) + _async_persistent_notification(hass, component, True) return False return True @@ -87,6 +89,7 @@ def _handle_requirements(hass: core.HomeAssistant, component, if not pkg_util.install_package(req, target=hass.config.path('deps')): _LOGGER.error('Not initializing %s because could not install ' 'dependency %s', name, req) + _async_persistent_notification(hass, name) return False return True @@ -114,6 +117,7 @@ def _async_setup_component(hass: core.HomeAssistant, if domain in setup_progress: _LOGGER.error('Attempt made to setup %s during setup of %s', domain, domain) + _async_persistent_notification(hass, domain, True) return False try: @@ -131,6 +135,10 @@ def _async_setup_component(hass: core.HomeAssistant, return False component = loader.get_component(domain) + if component is None: + _async_persistent_notification(hass, domain) + return False + async_comp = hasattr(component, 'async_setup') try: @@ -141,14 +149,17 @@ def _async_setup_component(hass: core.HomeAssistant, None, component.setup, hass, config) except Exception: # pylint: disable=broad-except _LOGGER.exception('Error during setup of component %s', domain) + _async_persistent_notification(hass, domain, True) return False if result is False: _LOGGER.error('component %s failed to initialize', domain) + _async_persistent_notification(hass, domain, True) return False elif result is not True: _LOGGER.error('component %s did not return boolean if setup ' 'was successful. Disabling component.', domain) + _async_persistent_notification(hass, domain, True) loader.set_component(domain, None) return False @@ -284,13 +295,7 @@ def async_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.async_create( - hass, message, 'Invalid platforms', 'platform_errors') + _async_persistent_notification(hass, platform_path) return None # Already loaded @@ -305,6 +310,7 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, 'Unable to prepare setup for platform %s because ' 'dependency %s could not be initialized', platform_path, component) + _async_persistent_notification(hass, platform_path, True) return None res = yield from hass.loop.run_in_executor( @@ -552,6 +558,22 @@ def log_exception(ex, domain, config, hass): hass.loop, async_log_exception, ex, domain, config, hass).result() +@core.callback +def _async_persistent_notification(hass: core.HomeAssistant, component: str, + link: Optional[bool]=False): + """Print a persistent notification. + + This method must be run in the event loop. + """ + _PERSISTENT_ERRORS[component] = _PERSISTENT_ERRORS.get(component) or link + _lst = [HA_COMPONENT_URL.format(name.replace('_', '-'), name) + if link else name for name, link in _PERSISTENT_ERRORS.items()] + message = ('The following components and platforms could not be set up:\n' + '* ' + '\n* '.join(list(_lst)) + '\nPlease check your config') + persistent_notification.async_create( + hass, message, 'Invalid config', 'invalid_config') + + @core.callback def async_log_exception(ex, domain, config, hass): """Generate log exception for config validation. @@ -559,12 +581,8 @@ def async_log_exception(ex, domain, config, hass): This method must be run in the event loop. """ message = 'Invalid config for [{}]: '.format(domain) - _PERSISTENT_VALIDATION.add(domain) - message = ('The following platforms contain invalid configuration: ' + - ', '.join(list(_PERSISTENT_VALIDATION)) + - ' (please check your configuration). ') - persistent_notification.async_create( - hass, message, 'Invalid config', 'invalid_config') + if hass is not None: + _async_persistent_notification(hass, domain, True) if 'extra keys not allowed' in ex.error_message: message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\