Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add persistent notifications to bootstrap #3738

Merged
merged 2 commits into from Oct 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 22 additions & 5 deletions homeassistant/bootstrap.py
Expand Up @@ -32,6 +32,8 @@
ATTR_COMPONENT = 'component'

ERROR_LOG_FILENAME = 'home-assistant.log'
_PERSISTENT_PLATFORMS = set()
_PERSISTENT_VALIDATION = set()


def setup_component(hass: core.HomeAssistant, domain: str,
Expand Down Expand Up @@ -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'):
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By passing in an id you will overwrite the previous message with that id.

return None

# Already loaded
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -305,6 +314,7 @@ def component_setup():
hass.loop.run_until_complete(
hass.loop.run_in_executor(None, component_setup)
)

return hass


Expand Down Expand Up @@ -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')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By passing in an id you will overwrite the previous message with that id.

Copy link
Member Author

@kellerza kellerza Oct 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding many cards with one error each, the messages lists them. There will be 2 type of messages:


Invalid platforms

Unable to find the following platforms: sensor.forecast, sensor.loch_ness_monster (please check your configuration)


Invalid config

The following platforms_components_ contain invalid configuration: sensor, light (please check your configuration)



if 'extra keys not allowed' in ex.error_message:
message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/scripts/check_config.py
Expand Up @@ -199,9 +199,10 @@ def mock_secrets(ldr, node): # pylint: disable=unused-variable
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
Expand Down
16 changes: 9 additions & 7 deletions tests/scripts/test_check_config.py
Expand Up @@ -74,13 +74,15 @@ def test_config_component_platform_fail_validation(self, mock_get_loop):
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'
Expand Down
3 changes: 2 additions & 1 deletion tests/test_bootstrap.py
Expand Up @@ -269,11 +269,12 @@ def exception_setup(hass, config):
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."""
Expand Down