diff --git a/homeassistant/core.py b/homeassistant/core.py index 48c69f35956..2fed56644e4 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -161,9 +161,19 @@ def split_entity_id(entity_id: str) -> tuple[str, str]: return domain, object_id -VALID_ENTITY_ID = re.compile(r"^(?!.+__)(?!_)[\da-z_]+(? bool: + """Test if a domain a valid format.""" + return VALID_DOMAIN.match(domain) is not None + + +@functools.lru_cache(64) def valid_entity_id(entity_id: str) -> bool: """Test if an entity ID is a valid format. diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 5cc2c6aa807..267e2e6c565 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -63,6 +63,7 @@ from homeassistant.core import ( State, callback, split_entity_id, + valid_domain, valid_entity_id, ) from homeassistant.exceptions import TemplateError @@ -796,7 +797,7 @@ class AllStates: if name in _RESERVED_NAMES: return None - if not valid_entity_id(f"{name}.entity"): + if not valid_domain(name): raise TemplateError(f"Invalid domain name '{name}'") return _domain_states(self._hass, name) diff --git a/tests/test_core.py b/tests/test_core.py index 4d7a93c2887..11715952126 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1384,6 +1384,32 @@ def test_valid_entity_id() -> None: assert ha.valid_entity_id(valid), valid +def test_valid_domain() -> None: + """Test valid domain.""" + for invalid in [ + "_light", + ".kitchen", + ".light.kitchen", + "light_.kitchen", + "._kitchen", + "light.", + "light.kitchen__ceiling", + "light.kitchen_yo_", + "light.kitchen.", + "Light", + ]: + assert not ha.valid_domain(invalid), invalid + + for valid in [ + "1", + "1light", + "a", + "input_boolean", + "light", + ]: + assert ha.valid_domain(valid), valid + + async def test_additional_data_in_core_config( hass: HomeAssistant, hass_storage: dict[str, Any] ) -> None: