From f96f4d31f76bd3a942cba0b658480592e58a4308 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 26 Jan 2024 18:02:42 -1000 Subject: [PATCH] Convert referenced registry functions to use cached_property (#108895) * Convert referenced registry functions to use cached_property These already implemented caching, but now that we can use cached_property because the lock problem is solved, we can make the code simplier and faster * missed one * make them the same --- .../components/automation/__init__.py | 36 +++++++-------- homeassistant/components/script/__init__.py | 26 ++++++----- homeassistant/helpers/script.py | 44 ++++++++----------- 3 files changed, 51 insertions(+), 55 deletions(-) diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index b5faeefdbe4..dbf76a1fe59 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -7,7 +7,7 @@ from collections.abc import Callable, Mapping from dataclasses import dataclass from functools import partial import logging -from typing import Any, Protocol, cast +from typing import TYPE_CHECKING, Any, Protocol, cast import voluptuous as vol @@ -111,6 +111,12 @@ from .const import ( from .helpers import async_get_blueprints from .trace import trace_automation +if TYPE_CHECKING: + from functools import cached_property +else: + from homeassistant.backports.functools import cached_property + + ENTITY_ID_FORMAT = DOMAIN + ".{}" @@ -334,7 +340,7 @@ class BaseAutomationEntity(ToggleEntity, ABC): return {CONF_ID: self.unique_id} return None - @property + @cached_property @abstractmethod def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" @@ -344,12 +350,12 @@ class BaseAutomationEntity(ToggleEntity, ABC): def referenced_blueprint(self) -> str | None: """Return referenced blueprint or None.""" - @property + @cached_property @abstractmethod def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" - @property + @cached_property @abstractmethod def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" @@ -389,7 +395,7 @@ class UnavailableAutomationEntity(BaseAutomationEntity): """Return the name of the entity.""" return self._name - @property + @cached_property def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" return set() @@ -399,12 +405,12 @@ class UnavailableAutomationEntity(BaseAutomationEntity): """Return referenced blueprint or None.""" return None - @property + @cached_property def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" return set() - @property + @cached_property def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" return set() @@ -446,8 +452,6 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): self.action_script.change_listener = self.async_write_ha_state self._initial_state = initial_state self._is_enabled = False - self._referenced_entities: set[str] | None = None - self._referenced_devices: set[str] | None = None self._logger = LOGGER self._variables = variables self._trigger_variables = trigger_variables @@ -478,7 +482,7 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): """Return True if entity is on.""" return self._async_detach_triggers is not None or self._is_enabled - @property + @cached_property def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" return self.action_script.referenced_areas @@ -490,12 +494,9 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): return None return cast(str, self._blueprint_inputs[CONF_USE_BLUEPRINT][CONF_PATH]) - @property + @cached_property def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" - if self._referenced_devices is not None: - return self._referenced_devices - referenced = self.action_script.referenced_devices if self._cond_func is not None: @@ -505,15 +506,11 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): for conf in self._trigger_config: referenced |= set(_trigger_extract_devices(conf)) - self._referenced_devices = referenced return referenced - @property + @cached_property def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" - if self._referenced_entities is not None: - return self._referenced_entities - referenced = self.action_script.referenced_entities if self._cond_func is not None: @@ -524,7 +521,6 @@ class AutomationEntity(BaseAutomationEntity, RestoreEntity): for entity_id in _trigger_extract_entities(conf): referenced.add(entity_id) - self._referenced_entities = referenced return referenced async def async_added_to_hass(self) -> None: diff --git a/homeassistant/components/script/__init__.py b/homeassistant/components/script/__init__.py index 716f0197c8b..f1a86687255 100644 --- a/homeassistant/components/script/__init__.py +++ b/homeassistant/components/script/__init__.py @@ -5,7 +5,7 @@ from abc import ABC, abstractmethod import asyncio from dataclasses import dataclass import logging -from typing import Any, cast +from typing import TYPE_CHECKING, Any, cast import voluptuous as vol @@ -72,6 +72,12 @@ from .const import ( from .helpers import async_get_blueprints from .trace import trace_script +if TYPE_CHECKING: + from functools import cached_property +else: + from homeassistant.backports.functools import cached_property + + SCRIPT_SERVICE_SCHEMA = vol.Schema(dict) SCRIPT_TURN_ONOFF_SCHEMA = make_entity_service_schema( {vol.Optional(ATTR_VARIABLES): {str: cv.match_all}} @@ -381,7 +387,7 @@ class BaseScriptEntity(ToggleEntity, ABC): raw_config: ConfigType | None - @property + @cached_property @abstractmethod def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" @@ -391,12 +397,12 @@ class BaseScriptEntity(ToggleEntity, ABC): def referenced_blueprint(self) -> str | None: """Return referenced blueprint or None.""" - @property + @cached_property @abstractmethod def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" - @property + @cached_property @abstractmethod def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" @@ -426,7 +432,7 @@ class UnavailableScriptEntity(BaseScriptEntity): """Return the name of the entity.""" return self._name - @property + @cached_property def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" return set() @@ -436,12 +442,12 @@ class UnavailableScriptEntity(BaseScriptEntity): """Return referenced blueprint or None.""" return None - @property + @cached_property def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" return set() - @property + @cached_property def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" return set() @@ -509,7 +515,7 @@ class ScriptEntity(BaseScriptEntity, RestoreEntity): """Return true if script is on.""" return self.script.is_running - @property + @cached_property def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" return self.script.referenced_areas @@ -521,12 +527,12 @@ class ScriptEntity(BaseScriptEntity, RestoreEntity): return None return self._blueprint_inputs[CONF_USE_BLUEPRINT][CONF_PATH] - @property + @cached_property def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" return self.script.referenced_devices - @property + @cached_property def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" return self.script.referenced_entities diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 040059276d3..2a31e02e3de 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -12,7 +12,7 @@ from functools import partial import itertools import logging from types import MappingProxyType -from typing import Any, TypedDict, TypeVar, cast +from typing import TYPE_CHECKING, Any, TypedDict, TypeVar, cast import voluptuous as vol @@ -101,6 +101,12 @@ from .trace import ( from .trigger import async_initialize_triggers, async_validate_trigger_config from .typing import UNDEFINED, ConfigType, UndefinedType +if TYPE_CHECKING: + from functools import cached_property +else: + from homeassistant.backports.functools import cached_property + + # mypy: allow-untyped-calls, allow-untyped-defs, no-check-untyped-defs _T = TypeVar("_T") @@ -1289,9 +1295,6 @@ class Script: self._choose_data: dict[int, _ChooseData] = {} self._if_data: dict[int, _IfData] = {} self._parallel_scripts: dict[int, list[Script]] = {} - self._referenced_entities: set[str] | None = None - self._referenced_devices: set[str] | None = None - self._referenced_areas: set[str] | None = None self.variables = variables self._variables_dynamic = template.is_complex(variables) if self._variables_dynamic: @@ -1362,15 +1365,12 @@ class Script: """Return true if the current mode support max.""" return self.script_mode in (SCRIPT_MODE_PARALLEL, SCRIPT_MODE_QUEUED) - @property + @cached_property def referenced_areas(self) -> set[str]: """Return a set of referenced areas.""" - if self._referenced_areas is not None: - return self._referenced_areas - - self._referenced_areas = set() - Script._find_referenced_areas(self._referenced_areas, self.sequence) - return self._referenced_areas + referenced_areas: set[str] = set() + Script._find_referenced_areas(referenced_areas, self.sequence) + return referenced_areas @staticmethod def _find_referenced_areas( @@ -1402,15 +1402,12 @@ class Script: for script in step[CONF_PARALLEL]: Script._find_referenced_areas(referenced, script[CONF_SEQUENCE]) - @property + @cached_property def referenced_devices(self) -> set[str]: """Return a set of referenced devices.""" - if self._referenced_devices is not None: - return self._referenced_devices - - self._referenced_devices = set() - Script._find_referenced_devices(self._referenced_devices, self.sequence) - return self._referenced_devices + referenced_devices: set[str] = set() + Script._find_referenced_devices(referenced_devices, self.sequence) + return referenced_devices @staticmethod def _find_referenced_devices( @@ -1452,15 +1449,12 @@ class Script: for script in step[CONF_PARALLEL]: Script._find_referenced_devices(referenced, script[CONF_SEQUENCE]) - @property + @cached_property def referenced_entities(self) -> set[str]: """Return a set of referenced entities.""" - if self._referenced_entities is not None: - return self._referenced_entities - - self._referenced_entities = set() - Script._find_referenced_entities(self._referenced_entities, self.sequence) - return self._referenced_entities + referenced_entities: set[str] = set() + Script._find_referenced_entities(referenced_entities, self.sequence) + return referenced_entities @staticmethod def _find_referenced_entities(