Remove file/line annotations after config has been validated (#107139)

This commit is contained in:
Erik Montnemery 2024-01-14 11:07:39 +01:00 committed by GitHub
parent 7fc3f8e473
commit 5e79cd8715
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 9 deletions

View file

@ -14,7 +14,7 @@ from pathlib import Path
import re
import shutil
from types import ModuleType
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, TypeVar
from urllib.parse import urlparse
from awesomeversion import AwesomeVersion
@ -67,6 +67,7 @@ from .requirements import RequirementsNotFound, async_get_integration_with_requi
from .util.package import is_docker_env
from .util.unit_system import get_unit_system, validate_unit_system
from .util.yaml import SECRET_YAML, Secrets, YamlTypeError, load_yaml_dict
from .util.yaml.objects import NodeStrClass
_LOGGER = logging.getLogger(__name__)
@ -146,6 +147,9 @@ class ConfigExceptionInfo:
integration_link: str | None
_T = TypeVar("_T")
@dataclass
class IntegrationConfigInfo:
"""Configuration for an integration and exception information."""
@ -1221,9 +1225,45 @@ async def async_process_component_and_handle_errors(
integration_config_info = await async_process_component_config(
hass, config, integration
)
return async_handle_component_errors(
async_handle_component_errors(
hass, integration_config_info, integration, raise_on_failure
)
return async_drop_config_annotations(integration_config_info, integration)
@callback
def async_drop_config_annotations(
integration_config_info: IntegrationConfigInfo,
integration: Integration,
) -> ConfigType | None:
"""Remove file and line annotations from str items in component configuration."""
if (config := integration_config_info.config) is None:
return None
def drop_config_annotations_rec(node: Any) -> Any:
if isinstance(node, dict):
# Some integrations store metadata in custom dict classes, preserve those
tmp = dict(node)
node.clear()
node.update(
(drop_config_annotations_rec(k), drop_config_annotations_rec(v))
for k, v in tmp.items()
)
return node
if isinstance(node, list):
return [drop_config_annotations_rec(v) for v in node]
if isinstance(node, NodeStrClass):
return str(node)
return node
# Don't drop annotations from the homeassistant integration because it may
# have configuration for other integrations as packages.
if integration.domain in config and integration.domain != CONF_CORE:
drop_config_annotations_rec(config[integration.domain])
return config
@callback
@ -1232,18 +1272,16 @@ def async_handle_component_errors(
integration_config_info: IntegrationConfigInfo,
integration: Integration,
raise_on_failure: bool = False,
) -> ConfigType | None:
) -> None:
"""Handle component configuration errors from async_process_component_config.
In case of errors:
- Print the error messages to the log.
- Raise a ConfigValidationError if raise_on_failure is set.
Returns the integration config or `None`.
"""
if not (config_exception_info := integration_config_info.exception_info_list):
return integration_config_info.config
return
platform_exception: ConfigExceptionInfo
domain = integration.domain
@ -1261,7 +1299,7 @@ def async_handle_component_errors(
)
if not raise_on_failure:
return integration_config_info.config
return
if len(config_exception_info) == 1:
translation_key = platform_exception.translation_key

View file

@ -256,8 +256,9 @@ async def _async_setup_component(
integration_config_info = await conf_util.async_process_component_config(
hass, config, integration
)
processed_config = conf_util.async_handle_component_errors(
hass, integration_config_info, integration
conf_util.async_handle_component_errors(hass, integration_config_info, integration)
processed_config = conf_util.async_drop_config_annotations(
integration_config_info, integration
)
for platform_exception in integration_config_info.exception_info_list:
if platform_exception.translation_key not in NOTIFY_FOR_TRANSLATION_KEYS: