1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Make template lock code error consistent between state based and trigger based template entities (#162923)

This commit is contained in:
Petro31
2026-02-13 08:13:58 -05:00
committed by GitHub
parent fd3258a6d3
commit d3d916566a
4 changed files with 63 additions and 18 deletions

View File

@@ -104,7 +104,7 @@ class AbstractTemplateEntity(Entity):
validator: Callable[[Any], Any] | None = None,
on_update: Callable[[Any], None] | None = None,
render_complex: bool = False,
**kwargs,
none_on_template_error: bool = True,
) -> None:
"""Set up a template that manages any property or attribute of the entity.
@@ -124,6 +124,9 @@ class AbstractTemplateEntity(Entity):
This signals trigger based template entities to render the template
as a complex result. State based template entities always render
complex results.
none_on_template_error (default=True)
If set to false, template errors will be supplied in the result to
on_update.
"""
def add_template(

View File

@@ -305,7 +305,9 @@ class TemplateEntity(AbstractTemplateEntity):
else:
setattr(self, attribute, state)
self.add_template(option, attribute, on_update=_update_state)
self.add_template(
option, attribute, on_update=_update_state, none_on_template_error=False
)
def setup_template(
self,
@@ -314,7 +316,7 @@ class TemplateEntity(AbstractTemplateEntity):
validator: Callable[[Any], Any] | None = None,
on_update: Callable[[Any], None] | None = None,
render_complex: bool = False,
**kwargs,
none_on_template_error: bool = True,
):
"""Set up a template that manages any property or attribute of the entity.
@@ -334,8 +336,10 @@ class TemplateEntity(AbstractTemplateEntity):
This signals trigger based template entities to render the template
as a complex result. State based template entities always render
complex results.
none_on_template_error (default=True)
If set to false, template errors will be supplied in the result to
on_update.
"""
none_on_template_error = kwargs.get("none_on_template_error", True)
self.add_template(
option, attribute, validator, on_update, none_on_template_error
)

View File

@@ -7,9 +7,16 @@ from typing import Any
from homeassistant.const import CONF_STATE, CONF_VARIABLES
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import TemplateError
from homeassistant.helpers.script_variables import ScriptVariables
from homeassistant.helpers.template import _SENTINEL
from homeassistant.helpers.trigger_template_entity import TriggerBaseEntity
from homeassistant.helpers.template import (
_SENTINEL,
render_complex as template_render_complex,
)
from homeassistant.helpers.trigger_template_entity import (
TriggerBaseEntity,
log_triggered_template_error,
)
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from . import TriggerUpdateCoordinator
@@ -59,7 +66,9 @@ class TriggerEntity( # pylint: disable=hass-enforce-class-module
on_update: Callable[[Any], None] | None = None,
) -> None:
"""Set up a template that manages the main state of the entity."""
if self.add_template(option, attribute, validator, on_update):
if self.add_template(
option, attribute, validator, on_update, none_on_template_error=False
):
self._to_render_simple.append(option)
self._parse_result.add(option)
@@ -70,7 +79,7 @@ class TriggerEntity( # pylint: disable=hass-enforce-class-module
validator: Callable[[Any], Any] | None = None,
on_update: Callable[[Any], None] | None = None,
render_complex: bool = False,
**kwargs,
none_on_template_error: bool = True,
) -> None:
"""Set up a template that manages any property or attribute of the entity.
@@ -90,8 +99,13 @@ class TriggerEntity( # pylint: disable=hass-enforce-class-module
This signals trigger based template entities to render the template
as a complex result. State based template entities always render
complex results.
none_on_template_error (default=True)
If set to false, template errors will be supplied in the result to
on_update.
"""
if self.add_template(option, attribute, validator, on_update):
if self.add_template(
option, attribute, validator, on_update, none_on_template_error
):
if render_complex:
self._to_render_complex.append(option)
else:
@@ -116,6 +130,33 @@ class TriggerEntity( # pylint: disable=hass-enforce-class-module
"""Render configured variables."""
return self._rendered_entity_variables or {}
def _render_single_template(
self,
key: str,
variables: dict[str, Any],
strict: bool = False,
) -> Any:
"""Render a single template."""
try:
if key in self._to_render_complex:
return template_render_complex(self._config[key], variables)
return self._config[key].async_render(
variables, parse_result=key in self._parse_result, strict=strict
)
except TemplateError as err:
log_triggered_template_error(self.entity_id, err, key=key)
# Filter out state templates because they have unique behavior
# with none_on_template_error.
if (
key != CONF_STATE
and key in self._templates
and not self._templates[key].none_on_template_error
):
return err
return _SENTINEL
def _render_templates(self, variables: dict[str, Any]) -> None:
"""Render templates."""
self._state_render_error = False

View File

@@ -757,16 +757,16 @@ async def test_lock_actions_fail_with_invalid_code(
],
)
@pytest.mark.parametrize(
("style", "attribute", "expected"),
("style", "attribute"),
[
(ConfigurationStyle.LEGACY, "code_format_template", 0),
(ConfigurationStyle.MODERN, "code_format", 0),
(ConfigurationStyle.TRIGGER, "code_format", 2),
(ConfigurationStyle.LEGACY, "code_format_template"),
(ConfigurationStyle.MODERN, "code_format"),
(ConfigurationStyle.TRIGGER, "code_format"),
],
)
@pytest.mark.usefixtures("setup_state_lock_with_attribute")
async def test_lock_actions_dont_execute_with_code_template_rendering_error(
hass: HomeAssistant, calls: list[ServiceCall], expected: int
hass: HomeAssistant, calls: list[ServiceCall]
) -> None:
"""Test lock code format rendering fails block lock/unlock actions."""
@@ -786,10 +786,7 @@ async def test_lock_actions_dont_execute_with_code_template_rendering_error(
)
await hass.async_block_till_done()
# Trigger expects calls here because trigger based entities don't
# allow template exception resolutions into code_format property so
# the actions will fire using the previous code_format.
assert len(calls) == expected
assert len(calls) == 0
@pytest.mark.parametrize(