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:
Jan Bouwhuis 2024-03-25 10:39:30 +01:00 committed by GitHub
parent a58049554d
commit 19fa39d556
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 200 additions and 178 deletions

View File

@ -163,31 +163,31 @@
"message": "Error importing config platform {domain}: {error}"
},
"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": {
"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": {
"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."
},
"max_length_exceeded": {
"message": "Value {value} for property {property_name} has a maximum length of {max_length} characters."
},
"platform_component_load_err": {
"message": "Platform error: {domain} - {error}. Check the logs for more information."
"message": "Platform error: {domain} - {error}."
},
"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": {
"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": {
"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": {
"message": "Service {domain}.{service} not found."

View File

@ -63,6 +63,7 @@ from .exceptions import ConfigValidationError, HomeAssistantError
from .generated.currencies import HISTORIC_CURRENCIES
from .helpers import config_validation as cv, issue_registry as ir
from .helpers.entity_values import EntityValues
from .helpers.translation import async_get_exception_message
from .helpers.typing import ConfigType
from .loader import ComponentProtocol, Integration, IntegrationNotFound
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_VALIDATOR_UNKNOWN_ERR = "config_validator_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_EXC = "platform_component_load_exc"
PLATFORM_SCHEMA_VALIDATOR_ERR = "platform_schema_validator_err"
# 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
@ -1183,48 +1194,16 @@ def _get_log_message_and_stack_print_pref(
platform_config = platform_exception.config
link = platform_exception.integration_link
placeholders: dict[str, str] = {"domain": domain, "error": str(exception)}
log_message_mapping: dict[ConfigErrorTranslationKey, tuple[str, bool]] = {
ConfigErrorTranslationKey.COMPONENT_IMPORT_ERR: (
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,
),
placeholders: dict[str, str] = {
"domain": domain,
"error": str(exception),
"p_name": platform_path,
}
log_message_show_stack_trace = log_message_mapping.get(
show_stack_trace: bool | None = _CONFIG_LOG_SHOW_STACK_TRACE.get(
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
# message, so we can notify about it during setup
show_stack_trace = False
@ -1247,9 +1226,14 @@ def _get_log_message_and_stack_print_pref(
show_stack_trace = True
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(
@ -1348,21 +1332,16 @@ def async_handle_component_errors(
if len(config_exception_info) == 1:
translation_key = platform_exception.translation_key
else:
translation_key = ConfigErrorTranslationKey.INTEGRATION_CONFIG_ERROR
translation_key = ConfigErrorTranslationKey.MULTIPLE_INTEGRATION_CONFIG_ERRORS
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 = {
"domain": domain,
"errors": errors,
}
raise ConfigValidationError(
str(log_message),
translation_key,
[platform_exception.exception for platform_exception in config_exception_info],
translation_domain="homeassistant",
translation_key=translation_key,
translation_domain=HA_DOMAIN,
translation_placeholders=placeholders,
)

View File

@ -87,20 +87,19 @@ class ConfigValidationError(HomeAssistantError, ExceptionGroup[Exception]):
def __init__(
self,
message: str,
message_translation_key: str,
exceptions: list[Exception],
translation_domain: str | None = None,
translation_key: str | None = None,
translation_placeholders: dict[str, str] | None = None,
) -> None:
"""Initialize exception."""
super().__init__(
*(message, exceptions),
*(message_translation_key, exceptions),
translation_domain=translation_domain,
translation_key=translation_key,
translation_key=message_translation_key,
translation_placeholders=translation_placeholders,
)
self._message = message
self.generate_message = True
class ServiceValidationError(HomeAssistantError):

View File

@ -1,4 +1,19 @@
# 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]
list([
dict({
@ -63,7 +78,7 @@
}),
dict({
'has_exc_info': True,
'message': 'Unknown error calling custom_validator_bad_2 config validator',
'message': 'config_validator_unknown_err',
}),
])
# ---
@ -131,7 +146,7 @@
}),
dict({
'has_exc_info': True,
'message': 'Unknown error calling custom_validator_bad_2 config validator',
'message': 'config_validator_unknown_err',
}),
])
# ---
@ -247,7 +262,7 @@
}),
dict({
'has_exc_info': True,
'message': 'Unknown error calling custom_validator_bad_2 config validator',
'message': 'config_validator_unknown_err',
}),
])
# ---
@ -291,7 +306,7 @@
}),
dict({
'has_exc_info': True,
'message': 'Unknown error calling custom_validator_bad_2 config validator',
'message': 'config_validator_unknown_err',
}),
dict({
'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_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]
@ -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'",
])
# ---
# 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]
'''
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",
])
# ---

View File

@ -44,6 +44,7 @@ import homeassistant.helpers.check_config as check_config
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType
from homeassistant.loader import Integration, async_get_integration
from homeassistant.setup import async_setup_component
from homeassistant.util.unit_system import (
_CONF_UNIT_SYSTEM_US_CUSTOMARY,
METRIC_SYSTEM,
@ -51,6 +52,7 @@ from homeassistant.util.unit_system import (
UnitSystem,
)
from homeassistant.util.yaml import SECRET_YAML
from homeassistant.util.yaml.objects import NodeDictClass
from .common import (
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:
"""Test creation of default config."""
assert not os.path.isfile(YAML_PATH)
@ -1435,7 +1445,24 @@ async def test_component_config_exceptions(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""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(
domain="test_domain",
async_get_component=AsyncMock(),
@ -1447,7 +1474,7 @@ async def test_component_config_exceptions(
)
assert (
await config_util.async_process_component_and_handle_errors(
hass, {}, integration=test_integration
hass, test_config, integration=test_integration
)
is None
)
@ -1456,12 +1483,13 @@ async def test_component_config_exceptions(
caplog.clear()
with pytest.raises(HomeAssistantError) as ex:
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 "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(
domain="test_domain",
async_get_platform=AsyncMock(
@ -1476,17 +1504,23 @@ async def test_component_config_exceptions(
caplog.clear()
assert (
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
)
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:
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
caplog.clear()
test_integration = Mock(
@ -1499,23 +1533,23 @@ async def test_component_config_exceptions(
assert (
await config_util.async_process_component_and_handle_errors(
hass,
{},
test_config,
integration=test_integration,
raise_on_failure=False,
)
is None
)
assert "Unknown error calling test_domain CONFIG_SCHEMA" in caplog.text
caplog.clear()
with pytest.raises(HomeAssistantError) as ex:
await config_util.async_process_component_and_handle_errors(
hass,
{},
test_config,
integration=test_integration,
raise_on_failure=True,
)
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
caplog.clear()
test_integration = Mock(
@ -1530,30 +1564,30 @@ async def test_component_config_exceptions(
)
assert await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=False,
) == {"test_domain": []}
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform - broken"
) in caplog.text
caplog.clear()
with pytest.raises(HomeAssistantError) as ex:
await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=True,
)
assert (
"Unknown error validating config for test_platform platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform - broken"
) in caplog.text
assert str(ex.value) == (
"Unknown error validating config for test_platform platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform - broken"
)
# platform.PLATFORM_SCHEMA
@ -1575,78 +1609,65 @@ async def test_component_config_exceptions(
):
assert await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=False,
) == {"test_domain": []}
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform platform for test_domain"
" component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform - broken"
) in caplog.text
caplog.clear()
with pytest.raises(HomeAssistantError) as ex:
assert await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=True,
)
assert (
"Unknown error validating config for test_platform platform for test_domain"
" component with PLATFORM_SCHEMA"
) in str(ex.value)
"Unknown error when validating config for test_domain "
"from integration test_platform - broken" in str(ex.value)
)
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform platform for test_domain"
" component with PLATFORM_SCHEMA" in caplog.text
"Unknown error when validating config for test_domain "
"from integration test_platform - broken" in caplog.text
)
# Test multiple platform failures
assert await config_util.async_process_component_and_handle_errors(
hass,
{
"test_domain": [
{"platform": "test_platform1"},
{"platform": "test_platform2"},
]
},
test_multi_platform_config,
integration=test_integration,
raise_on_failure=False,
) == {"test_domain": []}
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform1 platform "
"for test_domain component with PLATFORM_SCHEMA"
) in caplog.text
assert (
"Unknown error validating config for test_platform2 platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform - broken"
) in caplog.text
caplog.clear()
with pytest.raises(HomeAssistantError) as ex:
assert await config_util.async_process_component_and_handle_errors(
hass,
{
"test_domain": [
{"platform": "test_platform1"},
{"platform": "test_platform2"},
]
},
test_multi_platform_config,
integration=test_integration,
raise_on_failure=True,
)
assert (
"Failed to process component config for integration test_domain"
" due to multiple errors (2), check the logs for more information."
) in str(ex.value)
"Failed to process config for integration test_domain "
"due to multiple (2) errors. Check the logs for more information"
in str(ex.value)
)
assert "ValueError: broken" in caplog.text
assert (
"Unknown error validating config for test_platform1 platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform1 - broken"
) in caplog.text
assert (
"Unknown error validating config for test_platform2 platform "
"for test_domain component with PLATFORM_SCHEMA"
"Unknown error when validating config for test_domain "
"from integration test_platform2 - broken"
) in caplog.text
# 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(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=False,
) == {"test_domain": []}
@ -1680,7 +1701,7 @@ async def test_component_config_exceptions(
with pytest.raises(HomeAssistantError) as ex:
assert await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {"platform": "test_platform"}},
test_platform_config,
integration=test_integration,
raise_on_failure=True,
)
@ -1713,7 +1734,7 @@ async def test_component_config_exceptions(
assert (
await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {}},
test_config,
integration=test_integration,
raise_on_failure=False,
)
@ -1726,7 +1747,7 @@ async def test_component_config_exceptions(
with pytest.raises(HomeAssistantError) as ex:
await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {}},
test_config,
integration=test_integration,
raise_on_failure=True,
)
@ -1751,7 +1772,7 @@ async def test_component_config_exceptions(
assert (
await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {}},
test_config,
integration=test_integration,
raise_on_failure=False,
)
@ -1761,7 +1782,7 @@ async def test_component_config_exceptions(
with pytest.raises(HomeAssistantError) as ex:
await config_util.async_process_component_and_handle_errors(
hass,
{"test_domain": {}},
test_config,
integration=test_integration,
raise_on_failure=True,
)
@ -1778,7 +1799,7 @@ async def test_component_config_exceptions(
ImportError("bla"),
"component_import_err",
"test_domain",
{"test_domain": []},
ConfigTestClass({"test_domain": []}),
"https://example.com",
)
],
@ -1793,13 +1814,14 @@ async def test_component_config_exceptions(
HomeAssistantError("bla"),
"config_validation_err",
"test_domain",
{"test_domain": []},
ConfigTestClass({"test_domain": []}),
"https://example.com",
)
],
"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",
"bla",
],
@ -1812,14 +1834,15 @@ async def test_component_config_exceptions(
vol.Invalid("bla", ["path"]),
"config_validation_err",
"test_domain",
{"test_domain": []},
ConfigTestClass({"test_domain": []}),
"https://example.com",
)
],
"bla @ data['path']",
[
"Invalid config for 'test_domain': bla 'path', got None, "
"please check the docs at https://example.com",
"Invalid config for 'test_domain' at "
"../../configuration.yaml, line 140: bla 'path', "
"got None, please check the docs at https://example.com",
"bla",
],
False,
@ -1831,14 +1854,15 @@ async def test_component_config_exceptions(
vol.Invalid("bla", ["path"]),
"platform_config_validation_err",
"test_domain",
{"test_domain": []},
ConfigTestClass({"test_domain": []}),
"https://alt.example.com",
)
],
"bla @ data['path']",
[
"Invalid config for 'test_domain': bla 'path', got None, "
"please check the docs at https://alt.example.com",
"Invalid config for 'test_domain' at "
"../../configuration.yaml, line 140: bla 'path', "
"got None, please check the docs at https://alt.example.com",
"bla",
],
False,
@ -1850,7 +1874,7 @@ async def test_component_config_exceptions(
ImportError("bla"),
"platform_component_load_err",
"test_domain",
{"test_domain": []},
ConfigTestClass({"test_domain": []}),
"https://example.com",
)
],
@ -1864,13 +1888,18 @@ async def test_component_config_exceptions(
async def test_component_config_error_processing(
hass: HomeAssistant,
caplog: pytest.LogCaptureFixture,
error: str,
exception_info_list: list[config_util.ConfigExceptionInfo],
snapshot: SnapshotAssertion,
error: str,
messages: list[str],
show_stack_trace: bool,
translation_key: str,
) -> None:
"""Test component config error processing."""
# Make sure the exception translation cache is loaded
await async_setup_component(hass, "homeassistant", {})
test_integration = Mock(
domain="test_domain",
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]]
assert len(records) == 1
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_domain == "homeassistant"
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),
):
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)