Restore __slots__ to registry entries (#127481)

This commit is contained in:
J. Nick Koston 2024-10-05 05:16:52 -05:00 committed by GitHub
parent c104e66964
commit 24fbc366a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 51 additions and 23 deletions

View File

@ -104,8 +104,12 @@ async def async_get_config_entry_diagnostics(
if state := hass.states.get(entity.entity_id):
state_dict = dict(state.as_dict())
state_dict.pop("context", None)
entities.append({"entity": asdict(entity), "state": state_dict})
device_entities.append({"device": asdict(device), "entities": entities})
entity_dict = asdict(entity)
entity_dict.pop("_cache", None)
entities.append({"entity": entity_dict, "state": state_dict})
device_dict = asdict(device)
device_dict.pop("_cache", None)
device_entities.append({"device": device_dict, "entities": entities})
# remove envoy serial
old_serial = coordinator.envoy_serial_number

View File

@ -7,9 +7,7 @@ from collections.abc import Iterable
import dataclasses
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Literal, TypedDict
from propcache import cached_property
from typing import TYPE_CHECKING, Any, Literal, TypedDict
from homeassistant.core import HomeAssistant, callback
from homeassistant.util.dt import utc_from_timestamp, utcnow
@ -27,6 +25,13 @@ from .singleton import singleton
from .storage import Store
from .typing import UNDEFINED, UndefinedType
if TYPE_CHECKING:
# mypy cannot workout _cache Protocol with dataclasses
from propcache import cached_property as under_cached_property
else:
from propcache import under_cached_property
DATA_REGISTRY: HassKey[AreaRegistry] = HassKey("area_registry")
EVENT_AREA_REGISTRY_UPDATED: EventType[EventAreaRegistryUpdatedData] = EventType(
"area_registry_updated"
@ -63,7 +68,7 @@ class EventAreaRegistryUpdatedData(TypedDict):
area_id: str
@dataclass(frozen=True, kw_only=True)
@dataclass(frozen=True, kw_only=True, slots=True)
class AreaEntry(NormalizedNameBaseRegistryEntry):
"""Area Registry Entry."""
@ -73,8 +78,9 @@ class AreaEntry(NormalizedNameBaseRegistryEntry):
id: str
labels: set[str] = field(default_factory=set)
picture: str | None
_cache: dict[str, Any] = field(default_factory=dict, compare=False, init=False)
@cached_property
@under_cached_property
def json_fragment(self) -> json_fragment:
"""Return a JSON representation of this AreaEntry."""
return json_fragment(

View File

@ -12,7 +12,6 @@ import time
from typing import TYPE_CHECKING, Any, Literal, TypedDict
import attr
from propcache import cached_property
from yarl import URL
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP
@ -46,9 +45,14 @@ from .singleton import singleton
from .typing import UNDEFINED, UndefinedType
if TYPE_CHECKING:
# mypy cannot workout _cache Protocol with attrs
from propcache import cached_property as under_cached_property
from homeassistant.config_entries import ConfigEntry
from . import entity_registry
else:
from propcache import under_cached_property
_LOGGER = logging.getLogger(__name__)
@ -278,7 +282,7 @@ def _validate_configuration_url(value: Any) -> str | None:
return url_as_str
@attr.s(frozen=True)
@attr.s(frozen=True, slots=True)
class DeviceEntry:
"""Device Registry Entry."""
@ -306,6 +310,7 @@ class DeviceEntry:
via_device_id: str | None = attr.ib(default=None)
# This value is not stored, just used to keep track of events to fire.
is_new: bool = attr.ib(default=False)
_cache: dict[str, Any] = attr.ib(factory=dict, eq=False, init=False)
@property
def disabled(self) -> bool:
@ -342,7 +347,7 @@ class DeviceEntry:
"via_device_id": self.via_device_id,
}
@cached_property
@under_cached_property
def json_repr(self) -> bytes | None:
"""Return a cached JSON representation of the entry."""
try:
@ -358,7 +363,7 @@ class DeviceEntry:
)
return None
@cached_property
@under_cached_property
def as_storage_fragment(self) -> json_fragment:
"""Return a json fragment for storage."""
return json_fragment(
@ -390,7 +395,7 @@ class DeviceEntry:
)
@attr.s(frozen=True)
@attr.s(frozen=True, slots=True)
class DeletedDeviceEntry:
"""Deleted Device Registry Entry."""
@ -401,6 +406,7 @@ class DeletedDeviceEntry:
orphaned_timestamp: float | None = attr.ib()
created_at: datetime = attr.ib(factory=utcnow)
modified_at: datetime = attr.ib(factory=utcnow)
_cache: dict[str, Any] = attr.ib(factory=dict, eq=False, init=False)
def to_device_entry(
self,
@ -419,7 +425,7 @@ class DeletedDeviceEntry:
is_new=True,
)
@cached_property
@under_cached_property
def as_storage_fragment(self) -> json_fragment:
"""Return a json fragment for storage."""
return json_fragment(

View File

@ -19,7 +19,6 @@ import time
from typing import TYPE_CHECKING, Any, Literal, NotRequired, TypedDict
import attr
from propcache import cached_property
import voluptuous as vol
from homeassistant.const import (
@ -65,7 +64,12 @@ from .singleton import singleton
from .typing import UNDEFINED, UndefinedType
if TYPE_CHECKING:
# mypy cannot workout _cache Protocol with attrs
from propcache import cached_property as under_cached_property
from homeassistant.config_entries import ConfigEntry
else:
from propcache import under_cached_property
DATA_REGISTRY: HassKey[EntityRegistry] = HassKey("entity_registry")
EVENT_ENTITY_REGISTRY_UPDATED: EventType[EventEntityRegistryUpdatedData] = EventType(
@ -162,7 +166,7 @@ def _protect_entity_options(
return ReadOnlyDict({key: ReadOnlyDict(val) for key, val in data.items()})
@attr.s(frozen=True)
@attr.s(frozen=True, slots=True)
class RegistryEntry:
"""Entity Registry Entry."""
@ -201,6 +205,7 @@ class RegistryEntry:
supported_features: int = attr.ib(default=0)
translation_key: str | None = attr.ib(default=None)
unit_of_measurement: str | None = attr.ib(default=None)
_cache: dict[str, Any] = attr.ib(factory=dict, eq=False, init=False)
@domain.default
def _domain_default(self) -> str:
@ -247,7 +252,7 @@ class RegistryEntry:
display_dict["dp"] = precision
return display_dict
@cached_property
@under_cached_property
def display_json_repr(self) -> bytes | None:
"""Return a cached partial JSON representation of the entry.
@ -267,7 +272,7 @@ class RegistryEntry:
return None
return json_repr
@cached_property
@under_cached_property
def as_partial_dict(self) -> dict[str, Any]:
"""Return a partial dict representation of the entry."""
# Convert sets and tuples to lists
@ -296,7 +301,7 @@ class RegistryEntry:
"unique_id": self.unique_id,
}
@cached_property
@under_cached_property
def extended_dict(self) -> dict[str, Any]:
"""Return a extended dict representation of the entry."""
# Convert sets and tuples to lists
@ -311,7 +316,7 @@ class RegistryEntry:
"original_icon": self.original_icon,
}
@cached_property
@under_cached_property
def partial_json_repr(self) -> bytes | None:
"""Return a cached partial JSON representation of the entry."""
try:
@ -327,7 +332,7 @@ class RegistryEntry:
)
return None
@cached_property
@under_cached_property
def as_storage_fragment(self) -> json_fragment:
"""Return a json fragment for storage."""
return json_fragment(
@ -394,7 +399,7 @@ class RegistryEntry:
hass.states.async_set(self.entity_id, STATE_UNAVAILABLE, attrs)
@attr.s(frozen=True)
@attr.s(frozen=True, slots=True)
class DeletedRegistryEntry:
"""Deleted Entity Registry Entry."""
@ -407,13 +412,14 @@ class DeletedRegistryEntry:
orphaned_timestamp: float | None = attr.ib()
created_at: datetime = attr.ib(factory=utcnow)
modified_at: datetime = attr.ib(factory=utcnow)
_cache: dict[str, Any] = attr.ib(factory=dict, eq=False, init=False)
@domain.default
def _domain_default(self) -> str:
"""Compute domain value."""
return split_entity_id(self.entity_id)[0]
@cached_property
@under_cached_property
def as_storage_fragment(self) -> json_fragment:
"""Return a json fragment for storage."""
return json_fragment(

View File

@ -27,7 +27,7 @@ from tests.common import MockConfigEntry, MockModule, mock_integration, mock_pla
from tests.typing import WebSocketGenerator
@attr.s(frozen=True)
@attr.s(frozen=True, slots=True)
class MockDeviceEntry(dr.DeviceEntry):
"""Device Registry Entry with fixed UUID."""

View File

@ -289,6 +289,7 @@ async def test_snapshots(
entry.pop("device_id", None)
entry.pop("created_at", None)
entry.pop("modified_at", None)
entry.pop("_cache", None)
entities.append({"entry": entry, "state": state_dict})
@ -297,6 +298,8 @@ async def test_snapshots(
device_dict.pop("via_device_id", None)
device_dict.pop("created_at", None)
device_dict.pop("modified_at", None)
device_dict.pop("_cache", None)
devices.append({"device": device_dict, "entities": entities})
assert snapshot == devices

View File

@ -132,6 +132,7 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
"""Prepare a Home Assistant area registry entry for serialization."""
serialized = AreaRegistryEntrySnapshot(dataclasses.asdict(data) | {"id": ANY})
serialized.pop("_json_repr")
serialized.pop("_cache")
return serialized
@classmethod
@ -156,6 +157,7 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
serialized["via_device_id"] = ANY
if serialized["primary_config_entry"] is not None:
serialized["primary_config_entry"] = ANY
serialized.pop("_cache")
return cls._remove_created_and_modified_at(serialized)
@classmethod
@ -182,6 +184,7 @@ class HomeAssistantSnapshotSerializer(AmberDataSerializer):
}
)
serialized.pop("categories")
serialized.pop("_cache")
return cls._remove_created_and_modified_at(serialized)
@classmethod