Add as_dict cache to Context and Event (#92162)

This commit is contained in:
J. Nick Koston 2023-04-28 21:15:39 +02:00 committed by GitHub
parent 67a7de1869
commit 07d1a16efd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 17 deletions

View file

@ -91,7 +91,7 @@ async def async_attach_trigger(
if event_data_schema: if event_data_schema:
event_data_schema(event.data) event_data_schema(event.data)
if event_context_schema: if event_context_schema:
event_context_schema(event.context.as_dict()) event_context_schema(dict(event.context.as_dict()))
except vol.Invalid: except vol.Invalid:
# If event doesn't match, skip event # If event doesn't match, skip event
return False return False

View file

@ -850,7 +850,7 @@ class HomeAssistant:
class Context: class Context:
"""The context that triggered something.""" """The context that triggered something."""
__slots__ = ("user_id", "parent_id", "id", "origin_event") __slots__ = ("user_id", "parent_id", "id", "origin_event", "_as_dict")
def __init__( def __init__(
self, self,
@ -863,14 +863,23 @@ 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 | None = None self.origin_event: Event | None = None
self._as_dict: ReadOnlyDict[str, str | None] | None = None
def __eq__(self, other: Any) -> bool: def __eq__(self, other: Any) -> bool:
"""Compare contexts.""" """Compare contexts."""
return bool(self.__class__ == other.__class__ and self.id == other.id) return bool(self.__class__ == other.__class__ and self.id == other.id)
def as_dict(self) -> dict[str, str | None]: def as_dict(self) -> ReadOnlyDict[str, str | None]:
"""Return a dictionary representation of the context.""" """Return a dictionary representation of the context."""
return {"id": self.id, "parent_id": self.parent_id, "user_id": self.user_id} if not self._as_dict:
self._as_dict = ReadOnlyDict(
{
"id": self.id,
"parent_id": self.parent_id,
"user_id": self.user_id,
}
)
return self._as_dict
class EventOrigin(enum.Enum): class EventOrigin(enum.Enum):
@ -887,7 +896,7 @@ class EventOrigin(enum.Enum):
class Event: class Event:
"""Representation of an event within the bus.""" """Representation of an event within the bus."""
__slots__ = ["event_type", "data", "origin", "time_fired", "context"] __slots__ = ("event_type", "data", "origin", "time_fired", "context", "_as_dict")
def __init__( def __init__(
self, self,
@ -905,19 +914,24 @@ class Event:
self.context: Context = context or Context( self.context: Context = context or Context(
id=ulid_util.ulid_at_time(dt_util.utc_to_timestamp(self.time_fired)) id=ulid_util.ulid_at_time(dt_util.utc_to_timestamp(self.time_fired))
) )
self._as_dict: ReadOnlyDict[str, Any] | None = None
def as_dict(self) -> dict[str, Any]: def as_dict(self) -> ReadOnlyDict[str, Any]:
"""Create a dict representation of this Event. """Create a dict representation of this Event.
Async friendly. Async friendly.
""" """
return { if not self._as_dict:
self._as_dict = ReadOnlyDict(
{
"event_type": self.event_type, "event_type": self.event_type,
"data": dict(self.data), "data": ReadOnlyDict(self.data),
"origin": str(self.origin.value), "origin": str(self.origin.value),
"time_fired": self.time_fired.isoformat(), "time_fired": self.time_fired.isoformat(),
"context": self.context.as_dict(), "context": self.context.as_dict(),
} }
)
return self._as_dict
def __repr__(self) -> str: def __repr__(self) -> str:
"""Return the representation.""" """Return the representation."""
@ -1189,7 +1203,7 @@ class State:
object_id: Object id of this state. object_id: Object id of this state.
""" """
__slots__ = [ __slots__ = (
"entity_id", "entity_id",
"state", "state",
"attributes", "attributes",
@ -1200,7 +1214,7 @@ class State:
"object_id", "object_id",
"_as_dict", "_as_dict",
"_as_compressed_state", "_as_compressed_state",
] )
def __init__( def __init__(
self, self,
@ -1265,7 +1279,7 @@ class State:
"attributes": self.attributes, "attributes": self.attributes,
"last_changed": last_changed_isoformat, "last_changed": last_changed_isoformat,
"last_updated": last_updated_isoformat, "last_updated": last_updated_isoformat,
"context": ReadOnlyDict(self.context.as_dict()), "context": self.context.as_dict(),
} }
) )
return self._as_dict return self._as_dict

View file

@ -256,7 +256,9 @@ async def test_event_to_db_model() -> None:
assert native.as_dict() == event.as_dict() assert native.as_dict() == event.as_dict()
native = Events.from_event(event).to_native() native = Events.from_event(event).to_native()
event.data = {} native.data = (
event.data
) # data is not set by from_event as its in the event_data table
native.event_type = event.event_type native.event_type = event.event_type
assert native.as_dict() == event.as_dict() assert native.as_dict() == event.as_dict()