Generate ConfigValidationError message from English translations (#113844)
* Fetch ConfigValidationError message from translation cache * Sync error logmessages with translation cache * More sync * Cleanup * Remove unrelated change * Follow up comments * Rebase and improve contructor * Improve name * Rename to MULTIPLE_INTEGRATION_CONFIG_ERRORS
This commit is contained in:
parent
a58049554d
commit
19fa39d556
5 changed files with 200 additions and 178 deletions
|
@ -163,31 +163,31 @@
|
||||||
"message": "Error importing config platform {domain}: {error}"
|
"message": "Error importing config platform {domain}: {error}"
|
||||||
},
|
},
|
||||||
"config_validation_err": {
|
"config_validation_err": {
|
||||||
"message": "Invalid config for integration {domain} at {config_file}, line {line}: {error}. Check the logs for more information."
|
"message": "Invalid config for integration {domain} at {config_file}, line {line}: {error}."
|
||||||
},
|
},
|
||||||
"config_validator_unknown_err": {
|
"config_validator_unknown_err": {
|
||||||
"message": "Unknown error calling {domain} config validator. Check the logs for more information."
|
"message": "Unknown error calling {domain} config validator - {error}."
|
||||||
},
|
},
|
||||||
"config_schema_unknown_err": {
|
"config_schema_unknown_err": {
|
||||||
"message": "Unknown error calling {domain} CONFIG_SCHEMA. Check the logs for more information."
|
"message": "Unknown error calling {domain} CONFIG_SCHEMA - {error}."
|
||||||
},
|
},
|
||||||
"integration_config_error": {
|
"multiple_integration_config_errors": {
|
||||||
"message": "Failed to process config for integration {domain} due to multiple ({errors}) errors. Check the logs for more information."
|
"message": "Failed to process config for integration {domain} due to multiple ({errors}) errors. Check the logs for more information."
|
||||||
},
|
},
|
||||||
"max_length_exceeded": {
|
"max_length_exceeded": {
|
||||||
"message": "Value {value} for property {property_name} has a maximum length of {max_length} characters."
|
"message": "Value {value} for property {property_name} has a maximum length of {max_length} characters."
|
||||||
},
|
},
|
||||||
"platform_component_load_err": {
|
"platform_component_load_err": {
|
||||||
"message": "Platform error: {domain} - {error}. Check the logs for more information."
|
"message": "Platform error: {domain} - {error}."
|
||||||
},
|
},
|
||||||
"platform_component_load_exc": {
|
"platform_component_load_exc": {
|
||||||
"message": "Platform error: {domain} - {error}. Check the logs for more information."
|
"message": "[%key:component::homeassistant::exceptions::platform_component_load_err::message%]"
|
||||||
},
|
},
|
||||||
"platform_config_validation_err": {
|
"platform_config_validation_err": {
|
||||||
"message": "Invalid config for {domain} from integration {p_name} at file {config_file}, line {line}: {error}. Check the logs for more information."
|
"message": "Invalid config for {domain} from integration {p_name} at file {config_file}, line {line}: {error}. Check the logs for more information."
|
||||||
},
|
},
|
||||||
"platform_schema_validator_err": {
|
"platform_schema_validator_err": {
|
||||||
"message": "Unknown error when validating config for {domain} from integration {p_name}"
|
"message": "Unknown error when validating config for {domain} from integration {p_name} - {error}."
|
||||||
},
|
},
|
||||||
"service_not_found": {
|
"service_not_found": {
|
||||||
"message": "Service {domain}.{service} not found."
|
"message": "Service {domain}.{service} not found."
|
||||||
|
|
|
@ -63,6 +63,7 @@ from .exceptions import ConfigValidationError, HomeAssistantError
|
||||||
from .generated.currencies import HISTORIC_CURRENCIES
|
from .generated.currencies import HISTORIC_CURRENCIES
|
||||||
from .helpers import config_validation as cv, issue_registry as ir
|
from .helpers import config_validation as cv, issue_registry as ir
|
||||||
from .helpers.entity_values import EntityValues
|
from .helpers.entity_values import EntityValues
|
||||||
|
from .helpers.translation import async_get_exception_message
|
||||||
from .helpers.typing import ConfigType
|
from .helpers.typing import ConfigType
|
||||||
from .loader import ComponentProtocol, Integration, IntegrationNotFound
|
from .loader import ComponentProtocol, Integration, IntegrationNotFound
|
||||||
from .requirements import RequirementsNotFound, async_get_integration_with_requirements
|
from .requirements import RequirementsNotFound, async_get_integration_with_requirements
|
||||||
|
@ -130,13 +131,23 @@ class ConfigErrorTranslationKey(StrEnum):
|
||||||
CONFIG_PLATFORM_IMPORT_ERR = "config_platform_import_err"
|
CONFIG_PLATFORM_IMPORT_ERR = "config_platform_import_err"
|
||||||
CONFIG_VALIDATOR_UNKNOWN_ERR = "config_validator_unknown_err"
|
CONFIG_VALIDATOR_UNKNOWN_ERR = "config_validator_unknown_err"
|
||||||
CONFIG_SCHEMA_UNKNOWN_ERR = "config_schema_unknown_err"
|
CONFIG_SCHEMA_UNKNOWN_ERR = "config_schema_unknown_err"
|
||||||
PLATFORM_VALIDATOR_UNKNOWN_ERR = "platform_validator_unknown_err"
|
|
||||||
PLATFORM_COMPONENT_LOAD_ERR = "platform_component_load_err"
|
PLATFORM_COMPONENT_LOAD_ERR = "platform_component_load_err"
|
||||||
PLATFORM_COMPONENT_LOAD_EXC = "platform_component_load_exc"
|
PLATFORM_COMPONENT_LOAD_EXC = "platform_component_load_exc"
|
||||||
PLATFORM_SCHEMA_VALIDATOR_ERR = "platform_schema_validator_err"
|
PLATFORM_SCHEMA_VALIDATOR_ERR = "platform_schema_validator_err"
|
||||||
|
|
||||||
# translation key in case multiple errors occurred
|
# translation key in case multiple errors occurred
|
||||||
INTEGRATION_CONFIG_ERROR = "integration_config_error"
|
MULTIPLE_INTEGRATION_CONFIG_ERRORS = "multiple_integration_config_errors"
|
||||||
|
|
||||||
|
|
||||||
|
_CONFIG_LOG_SHOW_STACK_TRACE: dict[ConfigErrorTranslationKey, bool] = {
|
||||||
|
ConfigErrorTranslationKey.COMPONENT_IMPORT_ERR: False,
|
||||||
|
ConfigErrorTranslationKey.CONFIG_PLATFORM_IMPORT_ERR: False,
|
||||||
|
ConfigErrorTranslationKey.CONFIG_VALIDATOR_UNKNOWN_ERR: True,
|
||||||
|
ConfigErrorTranslationKey.CONFIG_SCHEMA_UNKNOWN_ERR: True,
|
||||||
|
ConfigErrorTranslationKey.PLATFORM_COMPONENT_LOAD_ERR: False,
|
||||||
|
ConfigErrorTranslationKey.PLATFORM_COMPONENT_LOAD_EXC: True,
|
||||||
|
ConfigErrorTranslationKey.PLATFORM_SCHEMA_VALIDATOR_ERR: True,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -1183,48 +1194,16 @@ def _get_log_message_and_stack_print_pref(
|
||||||
platform_config = platform_exception.config
|
platform_config = platform_exception.config
|
||||||
link = platform_exception.integration_link
|
link = platform_exception.integration_link
|
||||||
|
|
||||||
placeholders: dict[str, str] = {"domain": domain, "error": str(exception)}
|
placeholders: dict[str, str] = {
|
||||||
|
"domain": domain,
|
||||||
log_message_mapping: dict[ConfigErrorTranslationKey, tuple[str, bool]] = {
|
"error": str(exception),
|
||||||
ConfigErrorTranslationKey.COMPONENT_IMPORT_ERR: (
|
"p_name": platform_path,
|
||||||
f"Unable to import {domain}: {exception}",
|
|
||||||
False,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.CONFIG_PLATFORM_IMPORT_ERR: (
|
|
||||||
f"Error importing config platform {domain}: {exception}",
|
|
||||||
False,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.CONFIG_VALIDATOR_UNKNOWN_ERR: (
|
|
||||||
f"Unknown error calling {domain} config validator",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.CONFIG_SCHEMA_UNKNOWN_ERR: (
|
|
||||||
f"Unknown error calling {domain} CONFIG_SCHEMA",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.PLATFORM_VALIDATOR_UNKNOWN_ERR: (
|
|
||||||
f"Unknown error validating {platform_path} platform config with {domain} "
|
|
||||||
"component platform schema",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.PLATFORM_COMPONENT_LOAD_ERR: (
|
|
||||||
f"Platform error: {domain} - {exception}",
|
|
||||||
False,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.PLATFORM_COMPONENT_LOAD_EXC: (
|
|
||||||
f"Platform error: {domain} - {exception}",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
ConfigErrorTranslationKey.PLATFORM_SCHEMA_VALIDATOR_ERR: (
|
|
||||||
f"Unknown error validating config for {platform_path} platform "
|
|
||||||
f"for {domain} component with PLATFORM_SCHEMA",
|
|
||||||
True,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
log_message_show_stack_trace = log_message_mapping.get(
|
|
||||||
|
show_stack_trace: bool | None = _CONFIG_LOG_SHOW_STACK_TRACE.get(
|
||||||
platform_exception.translation_key
|
platform_exception.translation_key
|
||||||
)
|
)
|
||||||
if log_message_show_stack_trace is None:
|
if show_stack_trace is None:
|
||||||
# If no pre defined log_message is set, we generate an enriched error
|
# If no pre defined log_message is set, we generate an enriched error
|
||||||
# message, so we can notify about it during setup
|
# message, so we can notify about it during setup
|
||||||
show_stack_trace = False
|
show_stack_trace = False
|
||||||
|
@ -1247,9 +1226,14 @@ def _get_log_message_and_stack_print_pref(
|
||||||
show_stack_trace = True
|
show_stack_trace = True
|
||||||
return (log_message, show_stack_trace, placeholders)
|
return (log_message, show_stack_trace, placeholders)
|
||||||
|
|
||||||
assert isinstance(log_message_show_stack_trace, tuple)
|
# Generate the log message from the English translations
|
||||||
|
log_message = async_get_exception_message(
|
||||||
|
HA_DOMAIN,
|
||||||
|
platform_exception.translation_key,
|
||||||
|
translation_placeholders=placeholders,
|
||||||
|
)
|
||||||
|
|
||||||
return (*log_message_show_stack_trace, placeholders)
|
return (log_message, show_stack_trace, placeholders)
|
||||||
|
|
||||||
|
|
||||||
async def async_process_component_and_handle_errors(
|
async def async_process_component_and_handle_errors(
|
||||||
|
@ -1348,21 +1332,16 @@ def async_handle_component_errors(
|
||||||
if len(config_exception_info) == 1:
|
if len(config_exception_info) == 1:
|
||||||
translation_key = platform_exception.translation_key
|
translation_key = platform_exception.translation_key
|
||||||
else:
|
else:
|
||||||
translation_key = ConfigErrorTranslationKey.INTEGRATION_CONFIG_ERROR
|
translation_key = ConfigErrorTranslationKey.MULTIPLE_INTEGRATION_CONFIG_ERRORS
|
||||||
errors = str(len(config_exception_info))
|
errors = str(len(config_exception_info))
|
||||||
log_message = (
|
|
||||||
f"Failed to process component config for integration {domain} "
|
|
||||||
f"due to multiple errors ({errors}), check the logs for more information."
|
|
||||||
)
|
|
||||||
placeholders = {
|
placeholders = {
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
}
|
}
|
||||||
raise ConfigValidationError(
|
raise ConfigValidationError(
|
||||||
str(log_message),
|
translation_key,
|
||||||
[platform_exception.exception for platform_exception in config_exception_info],
|
[platform_exception.exception for platform_exception in config_exception_info],
|
||||||
translation_domain="homeassistant",
|
translation_domain=HA_DOMAIN,
|
||||||
translation_key=translation_key,
|
|
||||||
translation_placeholders=placeholders,
|
translation_placeholders=placeholders,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -87,20 +87,19 @@ class ConfigValidationError(HomeAssistantError, ExceptionGroup[Exception]):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
message: str,
|
message_translation_key: str,
|
||||||
exceptions: list[Exception],
|
exceptions: list[Exception],
|
||||||
translation_domain: str | None = None,
|
translation_domain: str | None = None,
|
||||||
translation_key: str | None = None,
|
|
||||||
translation_placeholders: dict[str, str] | None = None,
|
translation_placeholders: dict[str, str] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize exception."""
|
"""Initialize exception."""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
*(message, exceptions),
|
*(message_translation_key, exceptions),
|
||||||
translation_domain=translation_domain,
|
translation_domain=translation_domain,
|
||||||
translation_key=translation_key,
|
translation_key=message_translation_key,
|
||||||
translation_placeholders=translation_placeholders,
|
translation_placeholders=translation_placeholders,
|
||||||
)
|
)
|
||||||
self._message = message
|
self.generate_message = True
|
||||||
|
|
||||||
|
|
||||||
class ServiceValidationError(HomeAssistantError):
|
class ServiceValidationError(HomeAssistantError):
|
||||||
|
|
|
@ -1,4 +1,19 @@
|
||||||
# serializer version: 1
|
# serializer version: 1
|
||||||
|
# name: test_component_config_error_processing[exception_info_list0-bla-messages0-False-component_import_err]
|
||||||
|
'Unable to import test_domain: bla'
|
||||||
|
# ---
|
||||||
|
# name: test_component_config_error_processing[exception_info_list1-bla-messages1-True-config_validation_err]
|
||||||
|
'Invalid config for integration test_domain at configuration.yaml, line 140: bla'
|
||||||
|
# ---
|
||||||
|
# name: test_component_config_error_processing[exception_info_list2-bla @ data['path']-messages2-False-config_validation_err]
|
||||||
|
"Invalid config for integration test_domain at configuration.yaml, line 140: bla @ data['path']"
|
||||||
|
# ---
|
||||||
|
# name: test_component_config_error_processing[exception_info_list3-bla @ data['path']-messages3-False-platform_config_validation_err]
|
||||||
|
"Invalid config for test_domain from integration test_domain at file configuration.yaml, line 140: bla @ data['path']. Check the logs for more information"
|
||||||
|
# ---
|
||||||
|
# name: test_component_config_error_processing[exception_info_list4-bla-messages4-False-platform_component_load_err]
|
||||||
|
'Platform error: test_domain - bla'
|
||||||
|
# ---
|
||||||
# name: test_component_config_validation_error[basic]
|
# name: test_component_config_validation_error[basic]
|
||||||
list([
|
list([
|
||||||
dict({
|
dict({
|
||||||
|
@ -63,7 +78,7 @@
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'has_exc_info': True,
|
'has_exc_info': True,
|
||||||
'message': 'Unknown error calling custom_validator_bad_2 config validator',
|
'message': 'config_validator_unknown_err',
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
@ -131,7 +146,7 @@
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'has_exc_info': True,
|
'has_exc_info': True,
|
||||||
'message': 'Unknown error calling custom_validator_bad_2 config validator',
|
'message': 'config_validator_unknown_err',
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
@ -247,7 +262,7 @@
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'has_exc_info': True,
|
'has_exc_info': True,
|
||||||
'message': 'Unknown error calling custom_validator_bad_2 config validator',
|
'message': 'config_validator_unknown_err',
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
@ -291,7 +306,7 @@
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'has_exc_info': True,
|
'has_exc_info': True,
|
||||||
'message': 'Unknown error calling custom_validator_bad_2 config validator',
|
'message': 'config_validator_unknown_err',
|
||||||
}),
|
}),
|
||||||
dict({
|
dict({
|
||||||
'has_exc_info': False,
|
'has_exc_info': False,
|
||||||
|
@ -342,7 +357,27 @@
|
||||||
''',
|
''',
|
||||||
"Invalid config for 'custom_validator_ok_2' at configuration.yaml, line 52: required key 'host' not provided, please check the docs at https://www.home-assistant.io/integrations/custom_validator_ok_2",
|
"Invalid config for 'custom_validator_ok_2' at configuration.yaml, line 52: required key 'host' not provided, please check the docs at https://www.home-assistant.io/integrations/custom_validator_ok_2",
|
||||||
"Invalid config for 'custom_validator_bad_1' at configuration.yaml, line 55: broken, please check the docs at https://www.home-assistant.io/integrations/custom_validator_bad_1",
|
"Invalid config for 'custom_validator_bad_1' at configuration.yaml, line 55: broken, please check the docs at https://www.home-assistant.io/integrations/custom_validator_bad_1",
|
||||||
'Unknown error calling custom_validator_bad_2 config validator',
|
'config_validator_unknown_err',
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_individual_packages_schema_validation_errors[packages_dict]
|
||||||
|
list([
|
||||||
|
"Setup of package 'should_be_a_dict' at configuration.yaml, line 3 failed: Invalid package definition 'should_be_a_dict': expected a dictionary. Package will not be initialized",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_individual_packages_schema_validation_errors[packages_include_dir_named_dict]
|
||||||
|
list([
|
||||||
|
"Setup of package 'should_be_a_dict' at packages/expected_dict.yaml, line 1 failed: Invalid package definition 'should_be_a_dict': expected a dictionary. Package will not be initialized",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_individual_packages_schema_validation_errors[packages_include_dir_named_slug]
|
||||||
|
list([
|
||||||
|
"Setup of package 'this is not a slug but it should be one' at packages/expected_slug.yaml, line 1 failed: Invalid package definition 'this is not a slug but it should be one': invalid slug this is not a slug but it should be one (try this_is_not_a_slug_but_it_should_be_one). Package will not be initialized",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_individual_packages_schema_validation_errors[packages_slug]
|
||||||
|
list([
|
||||||
|
"Setup of package 'this is not a slug but it should be one' at configuration.yaml, line 3 failed: Invalid package definition 'this is not a slug but it should be one': invalid slug this is not a slug but it should be one (try this_is_not_a_slug_but_it_should_be_one). Package will not be initialized",
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_package_merge_error[packages]
|
# name: test_package_merge_error[packages]
|
||||||
|
@ -381,6 +416,21 @@
|
||||||
"Setup of package 'unknown_integration' at integrations/unknown_integration.yaml, line 1 failed: Integration test_domain caused error: ModuleNotFoundError: No module named 'not_installed_something'",
|
"Setup of package 'unknown_integration' at integrations/unknown_integration.yaml, line 1 failed: Integration test_domain caused error: ModuleNotFoundError: No module named 'not_installed_something'",
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_packages_schema_validation_error[packages_is_a_list]
|
||||||
|
list([
|
||||||
|
"Invalid package configuration 'packages' at configuration.yaml, line 2: expected a dictionary",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_packages_schema_validation_error[packages_is_a_value]
|
||||||
|
list([
|
||||||
|
"Invalid package configuration 'packages' at configuration.yaml, line 2: expected a dictionary",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
|
# name: test_packages_schema_validation_error[packages_is_null]
|
||||||
|
list([
|
||||||
|
"Invalid package configuration 'packages' at configuration.yaml, line 3: expected a dictionary",
|
||||||
|
])
|
||||||
|
# ---
|
||||||
# name: test_yaml_error[basic]
|
# name: test_yaml_error[basic]
|
||||||
'''
|
'''
|
||||||
mapping values are not allowed here
|
mapping values are not allowed here
|
||||||
|
@ -451,38 +501,3 @@
|
||||||
''',
|
''',
|
||||||
])
|
])
|
||||||
# ---
|
# ---
|
||||||
# name: test_individual_packages_schema_validation_errors[packages_dict]
|
|
||||||
list([
|
|
||||||
"Setup of package 'should_be_a_dict' at configuration.yaml, line 3 failed: Invalid package definition 'should_be_a_dict': expected a dictionary. Package will not be initialized",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_individual_packages_schema_validation_errors[packages_slug]
|
|
||||||
list([
|
|
||||||
"Setup of package 'this is not a slug but it should be one' at configuration.yaml, line 3 failed: Invalid package definition 'this is not a slug but it should be one': invalid slug this is not a slug but it should be one (try this_is_not_a_slug_but_it_should_be_one). Package will not be initialized",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_individual_packages_schema_validation_errors[packages_include_dir_named_dict]
|
|
||||||
list([
|
|
||||||
"Setup of package 'should_be_a_dict' at packages/expected_dict.yaml, line 1 failed: Invalid package definition 'should_be_a_dict': expected a dictionary. Package will not be initialized",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_individual_packages_schema_validation_errors[packages_include_dir_named_slug]
|
|
||||||
list([
|
|
||||||
"Setup of package 'this is not a slug but it should be one' at packages/expected_slug.yaml, line 1 failed: Invalid package definition 'this is not a slug but it should be one': invalid slug this is not a slug but it should be one (try this_is_not_a_slug_but_it_should_be_one). Package will not be initialized",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_packages_schema_validation_error[packages_is_a_list]
|
|
||||||
list([
|
|
||||||
"Invalid package configuration 'packages' at configuration.yaml, line 2: expected a dictionary",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_packages_schema_validation_error[packages_is_a_value]
|
|
||||||
list([
|
|
||||||
"Invalid package configuration 'packages' at configuration.yaml, line 2: expected a dictionary",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
# name: test_packages_schema_validation_error[packages_is_null]
|
|
||||||
list([
|
|
||||||
"Invalid package configuration 'packages' at configuration.yaml, line 3: expected a dictionary",
|
|
||||||
])
|
|
||||||
# ---
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ import homeassistant.helpers.check_config as check_config
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
from homeassistant.loader import Integration, async_get_integration
|
from homeassistant.loader import Integration, async_get_integration
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.util.unit_system import (
|
from homeassistant.util.unit_system import (
|
||||||
_CONF_UNIT_SYSTEM_US_CUSTOMARY,
|
_CONF_UNIT_SYSTEM_US_CUSTOMARY,
|
||||||
METRIC_SYSTEM,
|
METRIC_SYSTEM,
|
||||||
|
@ -51,6 +52,7 @@ from homeassistant.util.unit_system import (
|
||||||
UnitSystem,
|
UnitSystem,
|
||||||
)
|
)
|
||||||
from homeassistant.util.yaml import SECRET_YAML
|
from homeassistant.util.yaml import SECRET_YAML
|
||||||
|
from homeassistant.util.yaml.objects import NodeDictClass
|
||||||
|
|
||||||
from .common import (
|
from .common import (
|
||||||
MockModule,
|
MockModule,
|
||||||
|
@ -373,6 +375,14 @@ async def mock_custom_validator_integrations_with_docs(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigTestClass(NodeDictClass):
|
||||||
|
"""Test class for config with wrapper."""
|
||||||
|
|
||||||
|
__dict__ = {"__config_file__": "configuration.yaml", "__line__": 140}
|
||||||
|
__line__ = 140
|
||||||
|
__config_file__ = "configuration.yaml"
|
||||||
|
|
||||||
|
|
||||||
async def test_create_default_config(hass: HomeAssistant) -> None:
|
async def test_create_default_config(hass: HomeAssistant) -> None:
|
||||||
"""Test creation of default config."""
|
"""Test creation of default config."""
|
||||||
assert not os.path.isfile(YAML_PATH)
|
assert not os.path.isfile(YAML_PATH)
|
||||||
|
@ -1435,7 +1445,24 @@ async def test_component_config_exceptions(
|
||||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test unexpected exceptions validating component config."""
|
"""Test unexpected exceptions validating component config."""
|
||||||
# Config validator
|
|
||||||
|
# Create test config with embedded info
|
||||||
|
test_config = ConfigTestClass({"test_domain": {}})
|
||||||
|
test_platform_config = ConfigTestClass(
|
||||||
|
{"test_domain": {"platform": "test_platform"}}
|
||||||
|
)
|
||||||
|
test_multi_platform_config = ConfigTestClass(
|
||||||
|
{
|
||||||
|
"test_domain": [
|
||||||
|
{"platform": "test_platform1"},
|
||||||
|
{"platform": "test_platform2"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Make sure the exception translation cache is loaded
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
test_integration = Mock(
|
test_integration = Mock(
|
||||||
domain="test_domain",
|
domain="test_domain",
|
||||||
async_get_component=AsyncMock(),
|
async_get_component=AsyncMock(),
|
||||||
|
@ -1447,7 +1474,7 @@ async def test_component_config_exceptions(
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass, {}, integration=test_integration
|
hass, test_config, integration=test_integration
|
||||||
)
|
)
|
||||||
is None
|
is None
|
||||||
)
|
)
|
||||||
|
@ -1456,12 +1483,13 @@ async def test_component_config_exceptions(
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass, {}, integration=test_integration, raise_on_failure=True
|
hass, test_config, integration=test_integration, raise_on_failure=True
|
||||||
)
|
)
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert "Unknown error calling test_domain config validator" in caplog.text
|
assert "Unknown error calling test_domain config validator" in caplog.text
|
||||||
assert str(ex.value) == "Unknown error calling test_domain config validator"
|
assert (
|
||||||
|
str(ex.value) == "Unknown error calling test_domain config validator - broken"
|
||||||
|
)
|
||||||
test_integration = Mock(
|
test_integration = Mock(
|
||||||
domain="test_domain",
|
domain="test_domain",
|
||||||
async_get_platform=AsyncMock(
|
async_get_platform=AsyncMock(
|
||||||
|
@ -1476,17 +1504,23 @@ async def test_component_config_exceptions(
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
assert (
|
assert (
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass, {}, integration=test_integration, raise_on_failure=False
|
hass, test_config, integration=test_integration, raise_on_failure=False
|
||||||
)
|
)
|
||||||
is None
|
is None
|
||||||
)
|
)
|
||||||
assert "Invalid config for 'test_domain': broken" in caplog.text
|
assert (
|
||||||
|
"Invalid config for 'test_domain' at ../../configuration.yaml, "
|
||||||
|
"line 140: broken, please check the docs at" in caplog.text
|
||||||
|
)
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass, {}, integration=test_integration, raise_on_failure=True
|
hass, test_config, integration=test_integration, raise_on_failure=True
|
||||||
)
|
)
|
||||||
assert "Invalid config for 'test_domain': broken" in str(ex.value)
|
assert (
|
||||||
|
str(ex.value)
|
||||||
|
== "Invalid config for integration test_domain at configuration.yaml, "
|
||||||
|
"line 140: broken"
|
||||||
|
)
|
||||||
# component.CONFIG_SCHEMA
|
# component.CONFIG_SCHEMA
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
test_integration = Mock(
|
test_integration = Mock(
|
||||||
|
@ -1499,23 +1533,23 @@ async def test_component_config_exceptions(
|
||||||
assert (
|
assert (
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
)
|
)
|
||||||
is None
|
is None
|
||||||
)
|
)
|
||||||
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
|
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
|
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
|
||||||
assert str(ex.value) == "Unknown error calling test_domain CONFIG_SCHEMA"
|
assert str(ex.value) == "Unknown error calling test_domain CONFIG_SCHEMA - broken"
|
||||||
|
|
||||||
# component.PLATFORM_SCHEMA
|
# component.PLATFORM_SCHEMA
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
test_integration = Mock(
|
test_integration = Mock(
|
||||||
|
@ -1530,30 +1564,30 @@ async def test_component_config_exceptions(
|
||||||
)
|
)
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
) == {"test_domain": []}
|
) == {"test_domain": []}
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
assert str(ex.value) == (
|
assert str(ex.value) == (
|
||||||
"Unknown error validating config for test_platform platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken"
|
||||||
)
|
)
|
||||||
|
|
||||||
# platform.PLATFORM_SCHEMA
|
# platform.PLATFORM_SCHEMA
|
||||||
|
@ -1575,78 +1609,65 @@ async def test_component_config_exceptions(
|
||||||
):
|
):
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
) == {"test_domain": []}
|
) == {"test_domain": []}
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform platform for test_domain"
|
"Unknown error when validating config for test_domain "
|
||||||
" component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform platform for test_domain"
|
"Unknown error when validating config for test_domain "
|
||||||
" component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken" in str(ex.value)
|
||||||
) in str(ex.value)
|
)
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform platform for test_domain"
|
"Unknown error when validating config for test_domain "
|
||||||
" component with PLATFORM_SCHEMA" in caplog.text
|
"from integration test_platform - broken" in caplog.text
|
||||||
)
|
)
|
||||||
# Test multiple platform failures
|
# Test multiple platform failures
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{
|
test_multi_platform_config,
|
||||||
"test_domain": [
|
|
||||||
{"platform": "test_platform1"},
|
|
||||||
{"platform": "test_platform2"},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
) == {"test_domain": []}
|
) == {"test_domain": []}
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform1 platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform - broken"
|
||||||
) in caplog.text
|
|
||||||
assert (
|
|
||||||
"Unknown error validating config for test_platform2 platform "
|
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{
|
test_multi_platform_config,
|
||||||
"test_domain": [
|
|
||||||
{"platform": "test_platform1"},
|
|
||||||
{"platform": "test_platform2"},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
"Failed to process component config for integration test_domain"
|
"Failed to process config for integration test_domain "
|
||||||
" due to multiple errors (2), check the logs for more information."
|
"due to multiple (2) errors. Check the logs for more information"
|
||||||
) in str(ex.value)
|
in str(ex.value)
|
||||||
|
)
|
||||||
assert "ValueError: broken" in caplog.text
|
assert "ValueError: broken" in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform1 platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform1 - broken"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
assert (
|
assert (
|
||||||
"Unknown error validating config for test_platform2 platform "
|
"Unknown error when validating config for test_domain "
|
||||||
"for test_domain component with PLATFORM_SCHEMA"
|
"from integration test_platform2 - broken"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
# async_get_platform("domain") raising on ImportError
|
# async_get_platform("domain") raising on ImportError
|
||||||
|
@ -1668,7 +1689,7 @@ async def test_component_config_exceptions(
|
||||||
):
|
):
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
) == {"test_domain": []}
|
) == {"test_domain": []}
|
||||||
|
@ -1680,7 +1701,7 @@ async def test_component_config_exceptions(
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
assert await config_util.async_process_component_and_handle_errors(
|
assert await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {"platform": "test_platform"}},
|
test_platform_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
|
@ -1713,7 +1734,7 @@ async def test_component_config_exceptions(
|
||||||
assert (
|
assert (
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {}},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
)
|
)
|
||||||
|
@ -1726,7 +1747,7 @@ async def test_component_config_exceptions(
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {}},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
|
@ -1751,7 +1772,7 @@ async def test_component_config_exceptions(
|
||||||
assert (
|
assert (
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {}},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=False,
|
raise_on_failure=False,
|
||||||
)
|
)
|
||||||
|
@ -1761,7 +1782,7 @@ async def test_component_config_exceptions(
|
||||||
with pytest.raises(HomeAssistantError) as ex:
|
with pytest.raises(HomeAssistantError) as ex:
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass,
|
hass,
|
||||||
{"test_domain": {}},
|
test_config,
|
||||||
integration=test_integration,
|
integration=test_integration,
|
||||||
raise_on_failure=True,
|
raise_on_failure=True,
|
||||||
)
|
)
|
||||||
|
@ -1778,7 +1799,7 @@ async def test_component_config_exceptions(
|
||||||
ImportError("bla"),
|
ImportError("bla"),
|
||||||
"component_import_err",
|
"component_import_err",
|
||||||
"test_domain",
|
"test_domain",
|
||||||
{"test_domain": []},
|
ConfigTestClass({"test_domain": []}),
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -1793,13 +1814,14 @@ async def test_component_config_exceptions(
|
||||||
HomeAssistantError("bla"),
|
HomeAssistantError("bla"),
|
||||||
"config_validation_err",
|
"config_validation_err",
|
||||||
"test_domain",
|
"test_domain",
|
||||||
{"test_domain": []},
|
ConfigTestClass({"test_domain": []}),
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
"bla",
|
"bla",
|
||||||
[
|
[
|
||||||
"Invalid config for 'test_domain': bla, "
|
"Invalid config for 'test_domain' at "
|
||||||
|
"../../configuration.yaml, line 140: bla, "
|
||||||
"please check the docs at https://example.com",
|
"please check the docs at https://example.com",
|
||||||
"bla",
|
"bla",
|
||||||
],
|
],
|
||||||
|
@ -1812,14 +1834,15 @@ async def test_component_config_exceptions(
|
||||||
vol.Invalid("bla", ["path"]),
|
vol.Invalid("bla", ["path"]),
|
||||||
"config_validation_err",
|
"config_validation_err",
|
||||||
"test_domain",
|
"test_domain",
|
||||||
{"test_domain": []},
|
ConfigTestClass({"test_domain": []}),
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
"bla @ data['path']",
|
"bla @ data['path']",
|
||||||
[
|
[
|
||||||
"Invalid config for 'test_domain': bla 'path', got None, "
|
"Invalid config for 'test_domain' at "
|
||||||
"please check the docs at https://example.com",
|
"../../configuration.yaml, line 140: bla 'path', "
|
||||||
|
"got None, please check the docs at https://example.com",
|
||||||
"bla",
|
"bla",
|
||||||
],
|
],
|
||||||
False,
|
False,
|
||||||
|
@ -1831,14 +1854,15 @@ async def test_component_config_exceptions(
|
||||||
vol.Invalid("bla", ["path"]),
|
vol.Invalid("bla", ["path"]),
|
||||||
"platform_config_validation_err",
|
"platform_config_validation_err",
|
||||||
"test_domain",
|
"test_domain",
|
||||||
{"test_domain": []},
|
ConfigTestClass({"test_domain": []}),
|
||||||
"https://alt.example.com",
|
"https://alt.example.com",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
"bla @ data['path']",
|
"bla @ data['path']",
|
||||||
[
|
[
|
||||||
"Invalid config for 'test_domain': bla 'path', got None, "
|
"Invalid config for 'test_domain' at "
|
||||||
"please check the docs at https://alt.example.com",
|
"../../configuration.yaml, line 140: bla 'path', "
|
||||||
|
"got None, please check the docs at https://alt.example.com",
|
||||||
"bla",
|
"bla",
|
||||||
],
|
],
|
||||||
False,
|
False,
|
||||||
|
@ -1850,7 +1874,7 @@ async def test_component_config_exceptions(
|
||||||
ImportError("bla"),
|
ImportError("bla"),
|
||||||
"platform_component_load_err",
|
"platform_component_load_err",
|
||||||
"test_domain",
|
"test_domain",
|
||||||
{"test_domain": []},
|
ConfigTestClass({"test_domain": []}),
|
||||||
"https://example.com",
|
"https://example.com",
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -1864,13 +1888,18 @@ async def test_component_config_exceptions(
|
||||||
async def test_component_config_error_processing(
|
async def test_component_config_error_processing(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
error: str,
|
|
||||||
exception_info_list: list[config_util.ConfigExceptionInfo],
|
exception_info_list: list[config_util.ConfigExceptionInfo],
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
error: str,
|
||||||
messages: list[str],
|
messages: list[str],
|
||||||
show_stack_trace: bool,
|
show_stack_trace: bool,
|
||||||
translation_key: str,
|
translation_key: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test component config error processing."""
|
"""Test component config error processing."""
|
||||||
|
|
||||||
|
# Make sure the exception translation cache is loaded
|
||||||
|
await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
test_integration = Mock(
|
test_integration = Mock(
|
||||||
domain="test_domain",
|
domain="test_domain",
|
||||||
documentation="https://example.com",
|
documentation="https://example.com",
|
||||||
|
@ -1890,7 +1919,7 @@ async def test_component_config_error_processing(
|
||||||
records = [record for record in caplog.records if record.msg == messages[0]]
|
records = [record for record in caplog.records if record.msg == messages[0]]
|
||||||
assert len(records) == 1
|
assert len(records) == 1
|
||||||
assert (records[0].exc_info is not None) == show_stack_trace
|
assert (records[0].exc_info is not None) == show_stack_trace
|
||||||
assert str(ex.value) == messages[0]
|
assert str(ex.value) == snapshot
|
||||||
assert ex.value.translation_key == translation_key
|
assert ex.value.translation_key == translation_key
|
||||||
assert ex.value.translation_domain == "homeassistant"
|
assert ex.value.translation_domain == "homeassistant"
|
||||||
assert ex.value.translation_placeholders["domain"] == "test_domain"
|
assert ex.value.translation_placeholders["domain"] == "test_domain"
|
||||||
|
@ -1902,7 +1931,7 @@ async def test_component_config_error_processing(
|
||||||
return_value=config_util.IntegrationConfigInfo(None, exception_info_list),
|
return_value=config_util.IntegrationConfigInfo(None, exception_info_list),
|
||||||
):
|
):
|
||||||
await config_util.async_process_component_and_handle_errors(
|
await config_util.async_process_component_and_handle_errors(
|
||||||
hass, {}, test_integration
|
hass, ConfigTestClass({}), test_integration
|
||||||
)
|
)
|
||||||
assert all(message in caplog.text for message in messages)
|
assert all(message in caplog.text for message in messages)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue