From 877eedf6d7255da63febb88a4f5e38a5a2c65020 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 13 Sep 2023 14:38:40 -0500 Subject: [PATCH] Use cached_property in entity_registry (#100302) --- homeassistant/helpers/entity_registry.py | 33 +++++++----------------- tests/syrupy.py | 5 +--- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 09f92a88882..42de4749215 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -20,6 +20,7 @@ from typing import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict, TypeVar, import attr import voluptuous as vol +from homeassistant.backports.functools import cached_property from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, @@ -148,7 +149,7 @@ def _protect_entity_options( return ReadOnlyDict({key: ReadOnlyDict(val) for key, val in data.items()}) -@attr.s(slots=True, frozen=True) +@attr.s(frozen=True) class RegistryEntry: """Entity Registry Entry.""" @@ -183,13 +184,6 @@ class RegistryEntry: translation_key: str | None = attr.ib(default=None) unit_of_measurement: str | None = attr.ib(default=None) - _partial_repr: str | None | UndefinedType = attr.ib( - cmp=False, default=UNDEFINED, init=False, repr=False - ) - _display_repr: str | None | UndefinedType = attr.ib( - cmp=False, default=UNDEFINED, init=False, repr=False - ) - @domain.default def _domain_default(self) -> str: """Compute domain value.""" @@ -231,21 +225,17 @@ class RegistryEntry: display_dict["dp"] = precision return display_dict - @property + @cached_property def display_json_repr(self) -> str | None: """Return a cached partial JSON representation of the entry. This version only includes what's needed for display. """ - if self._display_repr is not UNDEFINED: - return self._display_repr - try: dict_repr = self._as_display_dict json_repr: str | None = JSON_DUMP(dict_repr) if dict_repr else None - object.__setattr__(self, "_display_repr", json_repr) + return json_repr except (ValueError, TypeError): - object.__setattr__(self, "_display_repr", None) _LOGGER.error( "Unable to serialize entry %s to JSON. Bad data found at %s", self.entity_id, @@ -253,8 +243,8 @@ class RegistryEntry: find_paths_unserializable_data(dict_repr, dump=JSON_DUMP) ), ) - # Mypy doesn't understand the __setattr__ business - return self._display_repr # type: ignore[return-value] + + return None @property def as_partial_dict(self) -> dict[str, Any]: @@ -278,17 +268,13 @@ class RegistryEntry: "unique_id": self.unique_id, } - @property + @cached_property def partial_json_repr(self) -> str | None: """Return a cached partial JSON representation of the entry.""" - if self._partial_repr is not UNDEFINED: - return self._partial_repr - try: dict_repr = self.as_partial_dict - object.__setattr__(self, "_partial_repr", JSON_DUMP(dict_repr)) + return JSON_DUMP(dict_repr) except (ValueError, TypeError): - object.__setattr__(self, "_partial_repr", None) _LOGGER.error( "Unable to serialize entry %s to JSON. Bad data found at %s", self.entity_id, @@ -296,8 +282,7 @@ class RegistryEntry: find_paths_unserializable_data(dict_repr, dump=JSON_DUMP) ), ) - # Mypy doesn't understand the __setattr__ business - return self._partial_repr # type: ignore[return-value] + return None @callback def write_unavailable_state(self, hass: HomeAssistant) -> None: diff --git a/tests/syrupy.py b/tests/syrupy.py index c7d114a4812..4846e013f5d 100644 --- a/tests/syrupy.py +++ b/tests/syrupy.py @@ -166,7 +166,7 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer): cls, data: er.RegistryEntry ) -> SerializableData: """Prepare a Home Assistant entity registry entry for serialization.""" - serialized = EntityRegistryEntrySnapshot( + return EntityRegistryEntrySnapshot( attrs.asdict(data) | { "config_entry_id": ANY, @@ -175,9 +175,6 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer): "options": {k: dict(v) for k, v in data.options.items()}, } ) - serialized.pop("_partial_repr") - serialized.pop("_display_repr") - return serialized @classmethod def _serializable_flow_result(cls, data: FlowResult) -> SerializableData: