Raise in EntityComponent.async_prepare_reload on configuration error

This commit is contained in:
Erik 2023-10-02 15:07:44 +02:00
parent 07ceafed62
commit fca50bfbf8
17 changed files with 49 additions and 43 deletions

View file

@ -333,8 +333,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Remove all automations and load new ones from config."""
await async_get_blueprints(hass).async_reset_cache()
if (conf := await component.async_prepare_reload(skip_reset=True)) is None:
return
conf = await component.async_prepare_reload(skip_reset=True)
if automation_id := service_call.data.get(CONF_ID):
await _async_process_single_config(hass, conf, component, automation_id)
else:

View file

@ -194,8 +194,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
- Remove group.group entities not created by service calls and set them up again
- Reload xxx.group platforms
"""
if (conf := await component.async_prepare_reload(skip_reset=True)) is None:
return
conf = await component.async_prepare_reload(skip_reset=True)
# Simplified + modified version of EntityPlatform.async_reset:
# - group.group never retries setup

View file

@ -121,8 +121,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Remove all input booleans and load new ones from config."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
return
await yaml_collection.async_load(
[
{CONF_ID: id_, **(conf or {})}

View file

@ -106,8 +106,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Remove all input buttons and load new ones from config."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
return
await yaml_collection.async_load(
[
{CONF_ID: id_, **(conf or {})}

View file

@ -159,8 +159,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **cfg} for id_, cfg in conf.get(DOMAIN, {}).items()]
)

View file

@ -137,8 +137,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **conf} for id_, conf in conf.get(DOMAIN, {}).items()]
)

View file

@ -167,8 +167,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **cfg} for id_, cfg in conf.get(DOMAIN, {}).items()]
)

View file

@ -137,8 +137,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **(cfg or {})} for id_, cfg in conf.get(DOMAIN, {}).items()]
)

View file

@ -403,8 +403,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_reload_yaml(call: ServiceCall) -> None:
"""Reload YAML."""
conf = await entity_component.async_prepare_reload(skip_reset=True)
if conf is None:
return
await yaml_collection.async_load(
await filter_yaml_data(hass, conf.get(DOMAIN, []))
)

View file

@ -187,8 +187,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **cfg} for id_, cfg in conf.get(DOMAIN, {}).items()]
)

View file

@ -229,8 +229,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service(service: ServiceCall) -> None:
"""Call a service to reload scripts."""
await async_get_blueprints(hass).async_reset_cache()
if (conf := await component.async_prepare_reload(skip_reset=True)) is None:
return
conf = await component.async_prepare_reload(skip_reset=True)
await _async_process_config(hass, conf, component)
async def turn_on_service(service: ServiceCall) -> None:

View file

@ -141,8 +141,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Reload yaml entities."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
conf = {DOMAIN: {}}
await yaml_collection.async_load(
[{CONF_ID: id_, **cfg} for id_, cfg in conf.get(DOMAIN, {}).items()]
)

View file

@ -265,8 +265,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def reload_service_handler(service_call: ServiceCall) -> None:
"""Remove all zones and load new ones from config."""
conf = await component.async_prepare_reload(skip_reset=True)
if conf is None:
return
await yaml_collection.async_load(conf[DOMAIN])
service.async_register_admin_service(

View file

@ -16,7 +16,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, Literal, overload
from urllib.parse import urlparse
from awesomeversion import AwesomeVersion
@ -1208,6 +1208,39 @@ def _get_log_message_and_stack_print_pref(
return (log_message, show_stack_trace, placeholders)
# The complicated overloads are due to a limitation in mypy, details in
# https://github.com/python/mypy/issues/7333
@overload
@callback
async def async_process_component_and_handle_errors(
hass: HomeAssistant,
config: ConfigType,
integration: Integration,
) -> ConfigType | None: ...
@overload
@callback
async def async_process_component_and_handle_errors(
hass: HomeAssistant,
config: ConfigType,
integration: Integration,
*,
raise_on_failure: Literal[True],
) -> ConfigType: ...
@overload
@callback
async def async_process_component_and_handle_errors(
hass: HomeAssistant,
config: ConfigType,
integration: Integration,
*,
raise_on_failure: bool,
) -> ConfigType | None: ...
async def async_process_component_and_handle_errors(
hass: HomeAssistant,
config: ConfigType,
@ -1226,7 +1259,7 @@ async def async_process_component_and_handle_errors(
hass, config, integration
)
async_handle_component_errors(
hass, integration_config_info, integration, raise_on_failure
hass, integration_config_info, integration, raise_on_failure=raise_on_failure
)
return async_drop_config_annotations(integration_config_info, integration)

View file

@ -348,28 +348,19 @@ class EntityComponent(Generic[_EntityT]):
if found:
await found.async_remove_entity(entity_id)
async def async_prepare_reload(
self, *, skip_reset: bool = False
) -> ConfigType | None:
async def async_prepare_reload(self, *, skip_reset: bool = False) -> ConfigType:
"""Prepare reloading this entity component.
This method must be run in the event loop.
"""
try:
conf = await conf_util.async_hass_config_yaml(self.hass)
except HomeAssistantError as err:
self.logger.error(err)
return None
integration = await async_get_integration(self.hass, self.domain)
processed_conf = await conf_util.async_process_component_and_handle_errors(
self.hass, conf, integration
self.hass, conf, integration, raise_on_failure=True
)
if processed_conf is None:
return None
if not skip_reset:
await self._async_reset()

View file

@ -136,6 +136,8 @@ async def _async_reconfig_platform(
await asyncio.gather(*tasks)
# The complicated overloads are due to a limitation in mypy, details in
# https://github.com/python/mypy/issues/7333
@overload
async def async_integration_yaml_config(
hass: HomeAssistant, integration_name: str

View file

@ -704,9 +704,12 @@ async def test_reload_config_handles_load_fails(
assert len(calls) == 1
assert calls[0].data.get("event") == "test_event"
with patch(
with (
patch(
"homeassistant.config.load_yaml_config_file",
side_effect=HomeAssistantError("bla"),
),
pytest.raises(HomeAssistantError),
):
await hass.services.async_call(automation.DOMAIN, SERVICE_RELOAD, blocking=True)