async def async_process_component_config( hass: HomeAssistant, config: Dict, integration: Integration ) -> Optional[Dict]: """Check component configuration and return processed configuration. Returns None on error. This method must be run in the event loop. """ domain = integration.domain try: component = integration.get_component() except ImportError as ex: _LOGGER.error("Unable to import %s: %s", domain, ex) return None # Check if the integration has a custom config validator config_validator = None try: config_validator = integration.get_platform("config") except ImportError: pass if config_validator is not None and hasattr( config_validator, "async_validate_config" ): try: return await config_validator.async_validate_config( # type: ignore hass, config ) except (vol.Invalid, HomeAssistantError) as ex: async_log_exception(ex, domain, config, hass) return None # No custom config validator, proceed with schema validation if hasattr(component, "CONFIG_SCHEMA"): try: return component.CONFIG_SCHEMA(config) # type: ignore except vol.Invalid as ex: async_log_exception(ex, domain, config, hass) return None component_platform_schema = getattr( component, "PLATFORM_SCHEMA_BASE", getattr(component, "PLATFORM_SCHEMA", None) ) if component_platform_schema is None: return config 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: async_log_exception(ex, domain, p_config, hass) 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 try: p_integration = await async_get_integration_with_requirements(hass, p_name) except (RequirementsNotFound, IntegrationNotFound) as ex: _LOGGER.error("Platform error: %s - %s", domain, ex) continue try: platform = p_integration.get_platform(domain) except ImportError: _LOGGER.exception("Platform error: %s", domain) continue # Validate platform specific schema if hasattr(platform, "PLATFORM_SCHEMA"): # pylint: disable=no-member try: p_validated = platform.PLATFORM_SCHEMA( # type: ignore p_config ) except vol.Invalid as ex: async_log_exception(ex, f"{domain}.{p_name}", p_config, hass) continue platforms.append(p_validated) # Create a copy of the configuration with all config for current # component removed and add validated config back in. config = config_without_domain(config, domain) config[domain] = platforms return config
async def async_process_component_config( # noqa: C901 hass: HomeAssistant, config: ConfigType, integration: Integration) -> ConfigType | None: """Check component configuration and return processed configuration. Returns None on error. This method must be run in the event loop. """ domain = integration.domain try: component = integration.get_component() except LOAD_EXCEPTIONS as ex: _LOGGER.error("Unable to import %s: %s", domain, ex) return None # Check if the integration has a custom config validator config_validator = None try: config_validator = integration.get_platform("config") except ImportError as err: # Filter out import error of the config platform. # If the config platform contains bad imports, make sure # that still fails. if err.name != f"{integration.pkg_path}.config": _LOGGER.error("Error importing config platform %s: %s", domain, err) return None if config_validator is not None and hasattr(config_validator, "async_validate_config"): try: return await config_validator.async_validate_config( # type: ignore hass, config) except (vol.Invalid, HomeAssistantError) as ex: async_log_exception(ex, domain, config, hass, integration.documentation) return None except Exception: # pylint: disable=broad-except _LOGGER.exception("Unknown error calling %s config validator", domain) return None # No custom config validator, proceed with schema validation if hasattr(component, "CONFIG_SCHEMA"): try: return component.CONFIG_SCHEMA(config) # type: ignore except vol.Invalid as ex: async_log_exception(ex, domain, config, hass, integration.documentation) return None except Exception: # pylint: disable=broad-except _LOGGER.exception("Unknown error calling %s CONFIG_SCHEMA", domain) return None component_platform_schema = getattr( component, "PLATFORM_SCHEMA_BASE", getattr(component, "PLATFORM_SCHEMA", None)) if component_platform_schema is None: return config 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: async_log_exception(ex, domain, p_config, hass, integration.documentation) continue except Exception: # pylint: disable=broad-except _LOGGER.exception( "Unknown error validating %s platform config with %s component platform schema", p_name, domain, ) 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 try: p_integration = await async_get_integration_with_requirements( hass, p_name) except (RequirementsNotFound, IntegrationNotFound) as ex: _LOGGER.error("Platform error: %s - %s", domain, ex) continue try: platform = p_integration.get_platform(domain) except LOAD_EXCEPTIONS: _LOGGER.exception("Platform error: %s", domain) continue # Validate platform specific schema if hasattr(platform, "PLATFORM_SCHEMA"): try: p_validated = platform.PLATFORM_SCHEMA( p_config) # type: ignore except vol.Invalid as ex: async_log_exception( ex, f"{domain}.{p_name}", p_config, hass, p_integration.documentation, ) continue except Exception: # pylint: disable=broad-except _LOGGER.exception( "Unknown error validating config for %s platform for %s component with PLATFORM_SCHEMA", p_name, domain, ) continue platforms.append(p_validated) # Create a copy of the configuration with all config for current # component removed and add validated config back in. config = config_without_domain(config, domain) config[domain] = platforms return config