Skip to content

Commit

Permalink
Extract component config validation from setup
Browse files Browse the repository at this point in the history
  • Loading branch information
balloob committed Sep 4, 2016
1 parent 5411c80 commit 60cfedb
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 62 deletions.
128 changes: 70 additions & 58 deletions homeassistant/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,67 +90,12 @@ def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
domain, domain)
return False

component = loader.get_component(domain)
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
if dep not in hass.config.components]
config = prepare_setup_component(hass, config, domain)

if missing_deps:
_LOGGER.error(
'Not initializing %s because not all dependencies loaded: %s',
domain, ", ".join(missing_deps))
return False

if hasattr(component, 'CONFIG_SCHEMA'):
try:
config = component.CONFIG_SCHEMA(config)
except vol.MultipleInvalid as ex:
log_exception(ex, domain, config)
return False

elif hasattr(component, 'PLATFORM_SCHEMA'):
platforms = []
for p_name, p_config in config_per_platform(config, domain):
# Validate component specific platform schema
try:
p_validated = component.PLATFORM_SCHEMA(p_config)
except vol.MultipleInvalid as ex:
log_exception(ex, domain, p_config)
return False

# Not all platform components follow same pattern for platforms
# So if p_name is None we are not going to validate platform
# (the automation component is one of them)
if p_name is None:
platforms.append(p_validated)
continue

platform = prepare_setup_platform(hass, config, domain,
p_name)

if platform is None:
return False

# Validate platform specific schema
if hasattr(platform, 'PLATFORM_SCHEMA'):
try:
p_validated = platform.PLATFORM_SCHEMA(p_validated)
except vol.MultipleInvalid as ex:
log_exception(ex, '{}.{}'.format(domain, p_name),
p_validated)
return False

platforms.append(p_validated)

# Create a copy of the configuration with all config for current
# component removed and add validated config back in.
filter_keys = extract_domain_configs(config, domain)
config = {key: value for key, value in config.items()
if key not in filter_keys}
config[domain] = platforms

if not _handle_requirements(hass, component, domain):
if config is None:
return False

component = loader.get_component(domain)
_CURRENT_SETUP.append(domain)

try:
Expand Down Expand Up @@ -182,6 +127,73 @@ def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
return True


def prepare_setup_component(hass: core.HomeAssistant, config: dict,
domain: str):
"""Prepare setup of a component and return processed config."""
component = loader.get_component(domain)
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
if dep not in hass.config.components]

if missing_deps:
_LOGGER.error(
'Not initializing %s because not all dependencies loaded: %s',
domain, ", ".join(missing_deps))
return None

if hasattr(component, 'CONFIG_SCHEMA'):
try:
config = component.CONFIG_SCHEMA(config)
except vol.MultipleInvalid as ex:
log_exception(ex, domain, config)
return None

elif hasattr(component, 'PLATFORM_SCHEMA'):
platforms = []
for p_name, p_config in config_per_platform(config, domain):
# Validate component specific platform schema
try:
p_validated = component.PLATFORM_SCHEMA(p_config)
except vol.MultipleInvalid as ex:
log_exception(ex, domain, p_config)
return None

# Not all platform components follow same pattern for platforms
# So if p_name is None we are not going to validate platform
# (the automation component is one of them)
if p_name is None:
platforms.append(p_validated)
continue

platform = prepare_setup_platform(hass, config, domain,
p_name)

if platform is None:
return None

# Validate platform specific schema
if hasattr(platform, 'PLATFORM_SCHEMA'):
try:
p_validated = platform.PLATFORM_SCHEMA(p_validated)
except vol.MultipleInvalid as ex:
log_exception(ex, '{}.{}'.format(domain, p_name),
p_validated)
return None

platforms.append(p_validated)

# Create a copy of the configuration with all config for current
# component removed and add validated config back in.
filter_keys = extract_domain_configs(config, domain)
config = {key: value for key, value in config.items()
if key not in filter_keys}
config[domain] = platforms

if not _handle_requirements(hass, component, domain):
return None

return config


def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
platform_name: str) -> Optional[ModuleType]:
"""Load a platform and makes sure dependencies are setup."""
Expand Down
8 changes: 4 additions & 4 deletions tests/test_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,19 @@ def test_component_not_setup_missing_dependencies(self):
deps = ['non_existing']
loader.set_component('comp', MockModule('comp', dependencies=deps))

assert not bootstrap._setup_component(self.hass, 'comp', None)
assert not bootstrap._setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components

self.hass.config.components.append('non_existing')

assert bootstrap._setup_component(self.hass, 'comp', None)
assert bootstrap._setup_component(self.hass, 'comp', {})

def test_component_failing_setup(self):
"""Test component that fails setup."""
loader.set_component(
'comp', MockModule('comp', setup=lambda hass, config: False))

assert not bootstrap._setup_component(self.hass, 'comp', None)
assert not bootstrap._setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components

def test_component_exception_setup(self):
Expand All @@ -234,7 +234,7 @@ def exception_setup(hass, config):

loader.set_component('comp', MockModule('comp', setup=exception_setup))

assert not bootstrap._setup_component(self.hass, 'comp', None)
assert not bootstrap._setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components

def test_home_assistant_core_config_validation(self):
Expand Down

0 comments on commit 60cfedb

Please sign in to comment.