From 423e8fbde3e5130ff4efa132a16ed1d9d2b5be52 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 4 Sep 2023 14:10:43 +0200 Subject: [PATCH] Validate state in template helper preview (#99455) * Validate state in template helper preview * Deduplicate state validation --- .../components/template/template_entity.py | 13 ++++++++++--- homeassistant/core.py | 16 +++++++++++----- tests/test_core.py | 7 +++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/template/template_entity.py b/homeassistant/components/template/template_entity.py index ac06e2c8734..c33674fa86f 100644 --- a/homeassistant/components/template/template_entity.py +++ b/homeassistant/components/template/template_entity.py @@ -25,6 +25,7 @@ from homeassistant.core import ( HomeAssistant, State, callback, + validate_state, ) from homeassistant.exceptions import TemplateError import homeassistant.helpers.config_validation as cv @@ -413,8 +414,8 @@ class TemplateEntity(Entity): return for update in updates: - for attr in self._template_attrs[update.template]: - attr.handle_result( + for template_attr in self._template_attrs[update.template]: + template_attr.handle_result( event, update.template, update.last_result, update.result ) @@ -422,7 +423,13 @@ class TemplateEntity(Entity): self.async_write_ha_state() return - self._preview_callback(*self._async_generate_attributes(), None) + try: + state, attrs = self._async_generate_attributes() + validate_state(state) + except Exception as err: # pylint: disable=broad-exception-caught + self._preview_callback(None, None, str(err)) + else: + self._preview_callback(state, attrs, None) @callback def _async_template_startup(self, *_: Any) -> None: diff --git a/homeassistant/core.py b/homeassistant/core.py index 18c5c355ae9..f2921e244ab 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -174,6 +174,16 @@ def valid_entity_id(entity_id: str) -> bool: return VALID_ENTITY_ID.match(entity_id) is not None +def validate_state(state: str) -> str: + """Validate a state, raise if it not valid.""" + if len(state) > MAX_LENGTH_STATE_STATE: + raise InvalidStateError( + f"Invalid state with length {len(state)}. " + "State max length is 255 characters." + ) + return state + + def callback(func: _CallableT) -> _CallableT: """Annotation to mark method as safe to call from within the event loop.""" setattr(func, "_hass_callback", True) @@ -1251,11 +1261,7 @@ class State: "Format should be ." ) - if len(state) > MAX_LENGTH_STATE_STATE: - raise InvalidStateError( - f"Invalid state encountered for entity ID: {entity_id}. " - "State max length is 255 characters." - ) + validate_state(state) self.entity_id = entity_id.lower() self.state = state diff --git a/tests/test_core.py b/tests/test_core.py index 4f7916e757b..8ec4dad2ebd 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2464,3 +2464,10 @@ async def test_cancellable_hassjob(hass: HomeAssistant) -> None: # Cleanup timer2.cancel() + + +async def test_validate_state(hass: HomeAssistant) -> None: + """Test validate_state.""" + assert ha.validate_state("test") == "test" + with pytest.raises(InvalidStateError): + ha.validate_state("t" * 256)