From ae4562b7cdd2c95705a51858f011f46f4d49924b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 23 Feb 2020 23:54:56 -0800 Subject: [PATCH 1/6] Speed up validate_entity_id --- homeassistant/core.py | 8 +++++-- homeassistant/scripts/benchmark/__init__.py | 9 ++++++++ tests/test_core.py | 24 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index c17c1f698ce8c6..b3f25b80b16d44 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -12,6 +12,7 @@ import logging import os import pathlib +import re import threading from time import monotonic from types import MappingProxyType @@ -63,7 +64,7 @@ ServiceNotFound, Unauthorized, ) -from homeassistant.util import location, slugify +from homeassistant.util import location from homeassistant.util.async_ import fire_coroutine_threadsafe, run_callback_threadsafe import homeassistant.util.dt as dt_util from homeassistant.util.unit_system import IMPERIAL_SYSTEM, METRIC_SYSTEM, UnitSystem @@ -103,12 +104,15 @@ def split_entity_id(entity_id: str) -> List[str]: return entity_id.split(".", 1) +VALID_ENTITY_ID = re.compile(r"[0-9a-z][a-z_]+[0-9a-z]\.[0-9a-z][0-9a-z_]+[0-9a-z]") + + def valid_entity_id(entity_id: str) -> bool: """Test if an entity ID is a valid format. Format: . where both are slugs. """ - return "." in entity_id and slugify(entity_id) == entity_id.replace(".", "_", 1) + return VALID_ENTITY_ID.match(entity_id) is not None def valid_state(state: str) -> bool: diff --git a/homeassistant/scripts/benchmark/__init__.py b/homeassistant/scripts/benchmark/__init__.py index 58125bc4829a68..4d7df6d72481cc 100644 --- a/homeassistant/scripts/benchmark/__init__.py +++ b/homeassistant/scripts/benchmark/__init__.py @@ -185,3 +185,12 @@ def yield_events(event): list(logbook.humanify(None, yield_events(event))) return timer() - start + + +@benchmark +async def valid_entity_id(hass): + """Run valid entity ID a million times.""" + start = timer() + for _ in range(10 ** 6): + core.valid_entity_id("light.kitchen") + return timer() - start diff --git a/tests/test_core.py b/tests/test_core.py index 0c7acfbba0e6f7..0054266cb05414 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1206,3 +1206,27 @@ async def service_handler(call): await hass.services.async_call("test_domain", "test_service", blocking=True) assert len(runs) == 3 + + +def test_valid_entity_id(): + """Test valid entity ID.""" + for invalid in [ + "light_.kitchen", + "Light.kitchen", + "_light.kitchen", + "light._kitchen", + "light.kitchen_yo_", + "light.Kitchen", + "lightkitchen", + ".kitchen", + "light.", + ]: + assert not ha.valid_entity_id(invalid), invalid + + for valid in [ + "light.kitchen", + "input_boolean.hello_world_0123", + "light.something_yoo", + "a.a", + ]: + assert ha.valid_entity_id(valid), valid From c211aec88dec2348cf05ccf434f5d88dd07874f1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Feb 2020 00:03:19 -0800 Subject: [PATCH 2/6] Add some more invalid entity IDs --- tests/test_core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_core.py b/tests/test_core.py index 0054266cb05414..1f5aa5294fe689 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1220,6 +1220,8 @@ def test_valid_entity_id(): "lightkitchen", ".kitchen", "light.", + ".light.kitchen", + "light.kitchen.", ]: assert not ha.valid_entity_id(invalid), invalid From ba8c8b92bed3b9231295149cb3a8a4612a70864c Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 24 Feb 2020 09:46:18 +0100 Subject: [PATCH 3/6] Adjust regular expression --- homeassistant/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index b3f25b80b16d44..27eaabba0c065a 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -104,7 +104,7 @@ def split_entity_id(entity_id: str) -> List[str]: return entity_id.split(".", 1) -VALID_ENTITY_ID = re.compile(r"[0-9a-z][a-z_]+[0-9a-z]\.[0-9a-z][0-9a-z_]+[0-9a-z]") +VALID_ENTITY_ID = re.compile(r"^(?![_\d])[\da-z_]+(? bool: From ec54263828d7869d55a80d6cff5347686f8a90b0 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 24 Feb 2020 09:48:25 +0100 Subject: [PATCH 4/6] Extend and sort test cases --- tests/test_core.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index 1f5aa5294fe689..c45c94e05fca49 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1211,24 +1211,27 @@ async def service_handler(call): def test_valid_entity_id(): """Test valid entity ID.""" for invalid in [ - "light_.kitchen", - "Light.kitchen", "_light.kitchen", + ".kitchen", + ".light.kitchen", + "1.a", + "1light.kitchen", + "light_.kitchen", "light._kitchen", + "light.", + "light.1kitchen", "light.kitchen_yo_", + "light.kitchen.", + "Light.kitchen", "light.Kitchen", "lightkitchen", - ".kitchen", - "light.", - ".light.kitchen", - "light.kitchen.", ]: assert not ha.valid_entity_id(invalid), invalid for valid in [ - "light.kitchen", + "a.a", "input_boolean.hello_world_0123", + "light.kitchen", "light.something_yoo", - "a.a", ]: assert ha.valid_entity_id(valid), valid From 6e12104bafcdcff5f1432a8697af7ff41aa9192d Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 24 Feb 2020 11:13:36 +0100 Subject: [PATCH 5/6] Update regular expression, more cases, faster --- homeassistant/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/core.py b/homeassistant/core.py index 27eaabba0c065a..a1d9a83d1ad423 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -104,7 +104,7 @@ def split_entity_id(entity_id: str) -> List[str]: return entity_id.split(".", 1) -VALID_ENTITY_ID = re.compile(r"^(?![_\d])[\da-z_]+(? bool: From 695be47857c05bb7d08d2e53ec101875d6c5a6b9 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 24 Feb 2020 11:14:08 +0100 Subject: [PATCH 6/6] Adjust tests, allow start with number, disallow double underscore --- tests/test_core.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index c45c94e05fca49..f5a6f4718cd711 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -1214,12 +1214,10 @@ def test_valid_entity_id(): "_light.kitchen", ".kitchen", ".light.kitchen", - "1.a", - "1light.kitchen", "light_.kitchen", "light._kitchen", "light.", - "light.1kitchen", + "light.kitchen__ceiling", "light.kitchen_yo_", "light.kitchen.", "Light.kitchen", @@ -1229,8 +1227,12 @@ def test_valid_entity_id(): assert not ha.valid_entity_id(invalid), invalid for valid in [ + "1.a", + "1light.kitchen", + "a.1", "a.a", "input_boolean.hello_world_0123", + "light.1kitchen", "light.kitchen", "light.something_yoo", ]: