def test_merge_id_schema(hass): """Test if we identify the config schemas correctly.""" types = { 'panel_custom': 'list', 'group': 'dict', 'script': 'dict', 'input_boolean': 'dict', 'shell_command': 'dict', 'qwikswitch': 'dict', } for name, expected_type in types.items(): module = config_util.get_component(hass, name) typ, _ = config_util._identify_config_schema(module) assert typ == expected_type, "{} expected {}, got {}".format( name, expected_type, typ)
def test_merge_id_schema(hass): """Test if we identify the config schemas correctly.""" types = { 'panel_custom': 'list', 'group': 'dict', 'script': 'dict', 'input_boolean': 'dict', 'shell_command': 'dict', 'qwikswitch': 'dict', } for name, expected_type in types.items(): module = config_util.get_component(name) typ, _ = config_util._identify_config_schema(module) assert typ == expected_type, "{} expected {}, got {}".format( name, expected_type, typ)
def check_ha_config_file(config_dir): """Check if Home Assistant configuration file is valid.""" result = HomeAssistantConfig() def _pack_error(package, component, config, message): """Handle errors from packages: _log_pkg_error.""" message = "Package {} setup failed. Component {} {}".format( package, component, message) domain = 'homeassistant.packages.{}.{}'.format(package, component) pack_config = core_config[CONF_PACKAGES].get(package, config) result.add_error(message, domain, pack_config) def _comp_error(ex, domain, config): """Handle errors from components: async_log_exception.""" result.add_error(_format_config_error(ex, domain, config), domain, config) # Load configuration.yaml try: config_path = find_config_file(config_dir) if not config_path: return result.add_error("File configuration.yaml not found.") config = load_yaml_config_file(config_path) except HomeAssistantError as err: return result.add_error("Error loading {}: {}".format( config_path, err)) finally: yaml.clear_secret_cache() # Extract and validate core [homeassistant] config try: core_config = config.pop(CONF_CORE, {}) core_config = CORE_CONFIG_SCHEMA(core_config) result[CONF_CORE] = core_config except vol.Invalid as err: result.add_error(err, CONF_CORE, core_config) core_config = {} # Merge packages merge_packages_config(config, core_config.get(CONF_PACKAGES, {}), _pack_error) del core_config[CONF_PACKAGES] # 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()) # Process and validate config for domain in components: component = get_component(domain) if not component: result.add_error("Component not found: {}".format(domain)) continue if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) result[domain] = config[domain] except vol.Invalid as ex: _comp_error(ex, domain, config) continue if not hasattr(component, 'PLATFORM_SCHEMA'): continue 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.Invalid as ex: _comp_error(ex, domain, config) continue # 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 = get_platform(domain, p_name) if platform is None: result.add_error("Platform not found: {}.{}".format( domain, p_name)) continue # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): # pylint: disable=no-member try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.Invalid as ex: _comp_error(ex, '{}.{}'.format(domain, p_name), p_validated) continue platforms.append(p_validated) # Remove config for current component and add validated config back in. for filter_comp in extract_domain_configs(config, domain): del config[filter_comp] result[domain] = platforms return result
def check_ha_config_file(config_dir): """Check if Home Assistant configuration file is valid.""" result = HomeAssistantConfig() def _pack_error(package, component, config, message): """Handle errors from packages: _log_pkg_error.""" message = "Package {} setup failed. Component {} {}".format( package, component, message) domain = 'homeassistant.packages.{}.{}'.format(package, component) pack_config = core_config[CONF_PACKAGES].get(package, config) result.add_error(message, domain, pack_config) def _comp_error(ex, domain, config): """Handle errors from components: async_log_exception.""" result.add_error( _format_config_error(ex, domain, config), domain, config) # Load configuration.yaml try: config_path = find_config_file(config_dir) if not config_path: return result.add_error("File configuration.yaml not found.") config = load_yaml_config_file(config_path) except HomeAssistantError as err: return result.add_error(err) finally: yaml.clear_secret_cache() # Extract and validate core [homeassistant] config try: core_config = config.pop(CONF_CORE, {}) core_config = CORE_CONFIG_SCHEMA(core_config) result[CONF_CORE] = core_config except vol.Invalid as err: result.add_error(err, CONF_CORE, core_config) core_config = {} # Merge packages merge_packages_config( config, core_config.get(CONF_PACKAGES, {}), _pack_error) del core_config[CONF_PACKAGES] # 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()) # Process and validate config for domain in components: component = get_component(domain) if not component: result.add_error("Component not found: {}".format(domain)) continue if hasattr(component, 'CONFIG_SCHEMA'): try: config = component.CONFIG_SCHEMA(config) result[domain] = config[domain] except vol.Invalid as ex: _comp_error(ex, domain, config) continue if not hasattr(component, 'PLATFORM_SCHEMA'): continue 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.Invalid as ex: _comp_error(ex, domain, config) continue # 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 = get_platform(domain, p_name) if platform is None: result.add_error( "Platform not found: {}.{}".format(domain, p_name)) continue # Validate platform specific schema if hasattr(platform, 'PLATFORM_SCHEMA'): # pylint: disable=no-member try: p_validated = platform.PLATFORM_SCHEMA(p_validated) except vol.Invalid as ex: _comp_error( ex, '{}.{}'.format(domain, p_name), p_validated) continue platforms.append(p_validated) # Remove config for current component and add validated config back in. for filter_comp in extract_domain_configs(config, domain): del config[filter_comp] result[domain] = platforms return result