Restore __slots__ to core objects (#127441)

This commit is contained in:
J. Nick Koston 2024-10-03 15:23:47 -05:00 committed by GitHub
parent 68d58212a9
commit db494de809
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 67 additions and 38 deletions

View File

@ -28,6 +28,7 @@ class LegacyLazyState(State):
"_attributes", "_attributes",
"_last_changed_ts", "_last_changed_ts",
"_last_updated_ts", "_last_updated_ts",
"_last_reported_ts",
"_context", "_context",
"attr_cache", "attr_cache",
] ]

View File

@ -8,7 +8,7 @@ import itertools
import logging import logging
from typing import Any from typing import Any
from propcache import cached_property from propcache import under_cached_property
import voluptuous as vol import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
@ -302,7 +302,7 @@ class TemplateEntity(Entity): # pylint: disable=hass-enforce-class-module
super().__init__("unknown.unknown", STATE_UNKNOWN) super().__init__("unknown.unknown", STATE_UNKNOWN)
self.entity_id = None # type: ignore[assignment] self.entity_id = None # type: ignore[assignment]
@cached_property @under_cached_property
def name(self) -> str: def name(self) -> str:
"""Name of this state.""" """Name of this state."""
return "<None>" return "<None>"

View File

@ -44,7 +44,7 @@ from typing import (
) )
from urllib.parse import urlparse from urllib.parse import urlparse
from propcache import cached_property from propcache import cached_property, under_cached_property
from typing_extensions import TypeVar from typing_extensions import TypeVar
import voluptuous as vol import voluptuous as vol
import yarl import yarl
@ -335,6 +335,8 @@ class HassJob[**_P, _R_co]:
we run the job. we run the job.
""" """
__slots__ = ("target", "name", "_cancel_on_shutdown", "_cache")
def __init__( def __init__(
self, self,
target: Callable[_P, _R_co], target: Callable[_P, _R_co],
@ -347,12 +349,13 @@ class HassJob[**_P, _R_co]:
self.target: Final = target self.target: Final = target
self.name = name self.name = name
self._cancel_on_shutdown = cancel_on_shutdown self._cancel_on_shutdown = cancel_on_shutdown
self._cache: dict[str, Any] = {}
if job_type: if job_type:
# Pre-set the cached_property so we # Pre-set the cached_property so we
# avoid the function call # avoid the function call
self.__dict__["job_type"] = job_type self._cache["job_type"] = job_type
@cached_property @under_cached_property
def job_type(self) -> HassJobType: def job_type(self) -> HassJobType:
"""Return the job type.""" """Return the job type."""
return get_hassjob_callable_job_type(self.target) return get_hassjob_callable_job_type(self.target)
@ -1244,6 +1247,8 @@ class HomeAssistant:
class Context: class Context:
"""The context that triggered something.""" """The context that triggered something."""
__slots__ = ("id", "user_id", "parent_id", "origin_event", "_cache")
def __init__( def __init__(
self, self,
user_id: str | None = None, user_id: str | None = None,
@ -1255,6 +1260,7 @@ class Context:
self.user_id = user_id self.user_id = user_id
self.parent_id = parent_id self.parent_id = parent_id
self.origin_event: Event[Any] | None = None self.origin_event: Event[Any] | None = None
self._cache: dict[str, Any] = {}
def __eq__(self, other: object) -> bool: def __eq__(self, other: object) -> bool:
"""Compare contexts.""" """Compare contexts."""
@ -1268,7 +1274,7 @@ class Context:
"""Create a deep copy of this context.""" """Create a deep copy of this context."""
return Context(user_id=self.user_id, parent_id=self.parent_id, id=self.id) return Context(user_id=self.user_id, parent_id=self.parent_id, id=self.id)
@cached_property @under_cached_property
def _as_dict(self) -> dict[str, str | None]: def _as_dict(self) -> dict[str, str | None]:
"""Return a dictionary representation of the context. """Return a dictionary representation of the context.
@ -1285,12 +1291,12 @@ class Context:
"""Return a ReadOnlyDict representation of the context.""" """Return a ReadOnlyDict representation of the context."""
return self._as_read_only_dict return self._as_read_only_dict
@cached_property @under_cached_property
def _as_read_only_dict(self) -> ReadOnlyDict[str, str | None]: def _as_read_only_dict(self) -> ReadOnlyDict[str, str | None]:
"""Return a ReadOnlyDict representation of the context.""" """Return a ReadOnlyDict representation of the context."""
return ReadOnlyDict(self._as_dict) return ReadOnlyDict(self._as_dict)
@cached_property @under_cached_property
def json_fragment(self) -> json_fragment: def json_fragment(self) -> json_fragment:
"""Return a JSON fragment of the context.""" """Return a JSON fragment of the context."""
return json_fragment(json_bytes(self._as_dict)) return json_fragment(json_bytes(self._as_dict))
@ -1315,6 +1321,15 @@ class EventOrigin(enum.Enum):
class Event(Generic[_DataT]): class Event(Generic[_DataT]):
"""Representation of an event within the bus.""" """Representation of an event within the bus."""
__slots__ = (
"event_type",
"data",
"origin",
"time_fired_timestamp",
"context",
"_cache",
)
def __init__( def __init__(
self, self,
event_type: EventType[_DataT] | str, event_type: EventType[_DataT] | str,
@ -1333,13 +1348,14 @@ class Event(Generic[_DataT]):
self.context = context self.context = context
if not context.origin_event: if not context.origin_event:
context.origin_event = self context.origin_event = self
self._cache: dict[str, Any] = {}
@cached_property @under_cached_property
def time_fired(self) -> datetime.datetime: def time_fired(self) -> datetime.datetime:
"""Return time fired as a timestamp.""" """Return time fired as a timestamp."""
return dt_util.utc_from_timestamp(self.time_fired_timestamp) return dt_util.utc_from_timestamp(self.time_fired_timestamp)
@cached_property @under_cached_property
def _as_dict(self) -> dict[str, Any]: def _as_dict(self) -> dict[str, Any]:
"""Create a dict representation of this Event. """Create a dict representation of this Event.
@ -1364,7 +1380,7 @@ class Event(Generic[_DataT]):
""" """
return self._as_read_only_dict return self._as_read_only_dict
@cached_property @under_cached_property
def _as_read_only_dict(self) -> ReadOnlyDict[str, Any]: def _as_read_only_dict(self) -> ReadOnlyDict[str, Any]:
"""Create a ReadOnlyDict representation of this Event.""" """Create a ReadOnlyDict representation of this Event."""
as_dict = self._as_dict as_dict = self._as_dict
@ -1380,7 +1396,7 @@ class Event(Generic[_DataT]):
as_dict["context"] = ReadOnlyDict(context) as_dict["context"] = ReadOnlyDict(context)
return ReadOnlyDict(as_dict) return ReadOnlyDict(as_dict)
@cached_property @under_cached_property
def json_fragment(self) -> json_fragment: def json_fragment(self) -> json_fragment:
"""Return an event as a JSON fragment.""" """Return an event as a JSON fragment."""
return json_fragment(json_bytes(self._as_dict)) return json_fragment(json_bytes(self._as_dict))
@ -1751,6 +1767,21 @@ class State:
object_id: Object id of this state. object_id: Object id of this state.
""" """
__slots__ = (
"entity_id",
"state",
"attributes",
"last_changed",
"last_reported",
"last_updated",
"context",
"state_info",
"domain",
"object_id",
"last_updated_timestamp",
"_cache",
)
def __init__( def __init__(
self, self,
entity_id: str, entity_id: str,
@ -1765,6 +1796,7 @@ class State:
last_updated_timestamp: float | None = None, last_updated_timestamp: float | None = None,
) -> None: ) -> None:
"""Initialize a new state.""" """Initialize a new state."""
self._cache: dict[str, Any] = {}
state = str(state) state = str(state)
if validate_entity_id and not valid_entity_id(entity_id): if validate_entity_id and not valid_entity_id(entity_id):
@ -1798,31 +1830,31 @@ class State:
last_updated_timestamp = last_updated.timestamp() last_updated_timestamp = last_updated.timestamp()
self.last_updated_timestamp = last_updated_timestamp self.last_updated_timestamp = last_updated_timestamp
if self.last_changed == last_updated: if self.last_changed == last_updated:
self.__dict__["last_changed_timestamp"] = last_updated_timestamp self._cache["last_changed_timestamp"] = last_updated_timestamp
# If last_reported is the same as last_updated async_set will pass # If last_reported is the same as last_updated async_set will pass
# the same datetime object for both values so we can use an identity # the same datetime object for both values so we can use an identity
# check here. # check here.
if self.last_reported is last_updated: if self.last_reported is last_updated:
self.__dict__["last_reported_timestamp"] = last_updated_timestamp self._cache["last_reported_timestamp"] = last_updated_timestamp
@cached_property @under_cached_property
def name(self) -> str: def name(self) -> str:
"""Name of this state.""" """Name of this state."""
return self.attributes.get(ATTR_FRIENDLY_NAME) or self.object_id.replace( return self.attributes.get(ATTR_FRIENDLY_NAME) or self.object_id.replace(
"_", " " "_", " "
) )
@cached_property @under_cached_property
def last_changed_timestamp(self) -> float: def last_changed_timestamp(self) -> float:
"""Timestamp of last change.""" """Timestamp of last change."""
return self.last_changed.timestamp() return self.last_changed.timestamp()
@cached_property @under_cached_property
def last_reported_timestamp(self) -> float: def last_reported_timestamp(self) -> float:
"""Timestamp of last report.""" """Timestamp of last report."""
return self.last_reported.timestamp() return self.last_reported.timestamp()
@cached_property @under_cached_property
def _as_dict(self) -> dict[str, Any]: def _as_dict(self) -> dict[str, Any]:
"""Return a dict representation of the State. """Return a dict representation of the State.
@ -1863,7 +1895,7 @@ class State:
""" """
return self._as_read_only_dict return self._as_read_only_dict
@cached_property @under_cached_property
def _as_read_only_dict( def _as_read_only_dict(
self, self,
) -> ReadOnlyDict[str, datetime.datetime | Collection[Any]]: ) -> ReadOnlyDict[str, datetime.datetime | Collection[Any]]:
@ -1878,17 +1910,17 @@ class State:
as_dict["context"] = ReadOnlyDict(context) as_dict["context"] = ReadOnlyDict(context)
return ReadOnlyDict(as_dict) return ReadOnlyDict(as_dict)
@cached_property @under_cached_property
def as_dict_json(self) -> bytes: def as_dict_json(self) -> bytes:
"""Return a JSON string of the State.""" """Return a JSON string of the State."""
return json_bytes(self._as_dict) return json_bytes(self._as_dict)
@cached_property @under_cached_property
def json_fragment(self) -> json_fragment: def json_fragment(self) -> json_fragment:
"""Return a JSON fragment of the State.""" """Return a JSON fragment of the State."""
return json_fragment(self.as_dict_json) return json_fragment(self.as_dict_json)
@cached_property @under_cached_property
def as_compressed_state(self) -> CompressedState: def as_compressed_state(self) -> CompressedState:
"""Build a compressed dict of a state for adds. """Build a compressed dict of a state for adds.
@ -1916,7 +1948,7 @@ class State:
) )
return compressed_state return compressed_state
@cached_property @under_cached_property
def as_compressed_state_json(self) -> bytes: def as_compressed_state_json(self) -> bytes:
"""Build a compressed JSON key value pair of a state for adds. """Build a compressed JSON key value pair of a state for adds.
@ -2308,7 +2340,7 @@ class StateMachine:
# mypy does not understand this is only possible if old_state is not None # mypy does not understand this is only possible if old_state is not None
old_last_reported = old_state.last_reported # type: ignore[union-attr] old_last_reported = old_state.last_reported # type: ignore[union-attr]
old_state.last_reported = now # type: ignore[union-attr] old_state.last_reported = now # type: ignore[union-attr]
old_state.last_reported_timestamp = timestamp # type: ignore[union-attr] old_state._cache["last_reported_timestamp"] = timestamp # type: ignore[union-attr] # noqa: SLF001
# Avoid creating an EventStateReportedData # Avoid creating an EventStateReportedData
self._bus.async_fire_internal( # type: ignore[misc] self._bus.async_fire_internal( # type: ignore[misc]
EVENT_STATE_REPORTED, EVENT_STATE_REPORTED,

View File

@ -10,7 +10,7 @@ from collections.abc import Callable, Generator, Iterable
from contextlib import AbstractContextManager from contextlib import AbstractContextManager
from contextvars import ContextVar from contextvars import ContextVar
from datetime import date, datetime, time, timedelta from datetime import date, datetime, time, timedelta
from functools import cache, cached_property, lru_cache, partial, wraps from functools import cache, lru_cache, partial, wraps
import json import json
import logging import logging
import math import math
@ -34,6 +34,7 @@ from jinja2.sandbox import ImmutableSandboxedEnvironment
from jinja2.utils import Namespace from jinja2.utils import Namespace
from lru import LRU from lru import LRU
import orjson import orjson
from propcache import under_cached_property
import voluptuous as vol import voluptuous as vol
from homeassistant.const import ( from homeassistant.const import (
@ -1023,6 +1024,8 @@ class DomainStates:
class TemplateStateBase(State): class TemplateStateBase(State):
"""Class to represent a state object in a template.""" """Class to represent a state object in a template."""
__slots__ = ("_hass", "_collect", "_entity_id", "_state")
_state: State _state: State
__setitem__ = _readonly __setitem__ = _readonly
@ -1035,6 +1038,7 @@ class TemplateStateBase(State):
self._hass = hass self._hass = hass
self._collect = collect self._collect = collect
self._entity_id = entity_id self._entity_id = entity_id
self._cache: dict[str, Any] = {}
def _collect_state(self) -> None: def _collect_state(self) -> None:
if self._collect and (render_info := _render_info.get()): if self._collect and (render_info := _render_info.get()):
@ -1055,7 +1059,7 @@ class TemplateStateBase(State):
return self.state_with_unit return self.state_with_unit
raise KeyError raise KeyError
@cached_property @under_cached_property
def entity_id(self) -> str: # type: ignore[override] def entity_id(self) -> str: # type: ignore[override]
"""Wrap State.entity_id. """Wrap State.entity_id.
@ -1112,7 +1116,7 @@ class TemplateStateBase(State):
return self._state.object_id return self._state.object_id
@property @property
def name(self) -> str: def name(self) -> str: # type: ignore[override]
"""Wrap State.name.""" """Wrap State.name."""
self._collect_state() self._collect_state()
return self._state.name return self._state.name
@ -1149,7 +1153,7 @@ class TemplateStateBase(State):
class TemplateState(TemplateStateBase): class TemplateState(TemplateStateBase):
"""Class to represent a state object in a template.""" """Class to represent a state object in a template."""
__slots__ = ("_state",) __slots__ = ()
# Inheritance is done so functions that check against State keep working # Inheritance is done so functions that check against State keep working
def __init__(self, hass: HomeAssistant, state: State, collect: bool = True) -> None: def __init__(self, hass: HomeAssistant, state: State, collect: bool = True) -> None:
@ -1165,6 +1169,8 @@ class TemplateState(TemplateStateBase):
class TemplateStateFromEntityId(TemplateStateBase): class TemplateStateFromEntityId(TemplateStateBase):
"""Class to represent a state object in a template.""" """Class to represent a state object in a template."""
__slots__ = ()
def __init__( def __init__(
self, hass: HomeAssistant, entity_id: str, collect: bool = True self, hass: HomeAssistant, entity_id: str, collect: bool = True
) -> None: ) -> None:

View File

@ -348,8 +348,6 @@ class LazyState(State):
__slots__ = [ __slots__ = [
"_row", "_row",
"entity_id",
"state",
"_attributes", "_attributes",
"_last_changed", "_last_changed",
"_last_updated", "_last_updated",

View File

@ -361,8 +361,6 @@ class LazyState(State):
__slots__ = [ __slots__ = [
"_row", "_row",
"entity_id",
"state",
"_attributes", "_attributes",
"_last_changed", "_last_changed",
"_last_updated", "_last_updated",

View File

@ -480,8 +480,6 @@ class LazyState(State):
__slots__ = [ __slots__ = [
"_row", "_row",
"entity_id",
"state",
"_attributes", "_attributes",
"_last_changed", "_last_changed",
"_last_updated", "_last_updated",

View File

@ -470,8 +470,6 @@ class LazyState(State):
__slots__ = [ __slots__ = [
"_row", "_row",
"entity_id",
"state",
"_attributes", "_attributes",
"_last_changed", "_last_changed",
"_last_updated", "_last_updated",

View File

@ -594,8 +594,6 @@ class LazyState(State):
__slots__ = [ __slots__ = [
"_row", "_row",
"entity_id",
"state",
"_attributes", "_attributes",
"_last_changed", "_last_changed",
"_last_updated", "_last_updated",