Convert States to dicts via as_dict only once (#41208)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
J. Nick Koston 2020-10-05 09:18:57 -05:00 committed by GitHub
parent 2f54bf29ba
commit 4798f37c6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 20 deletions

View file

@ -65,7 +65,7 @@ class Events(Base): # type: ignore
return Events(
event_type=event.event_type,
event_data=event_data or json.dumps(event.data, cls=JSONEncoder),
origin=str(event.origin),
origin=str(event.origin.value),
time_fired=event.time_fired,
context_id=event.context.id,
context_user_id=event.context.user_id,

View file

@ -21,6 +21,7 @@ from typing import (
Any,
Awaitable,
Callable,
Collection,
Coroutine,
Dict,
Iterable,
@ -561,8 +562,8 @@ class Event:
return {
"event_type": self.event_type,
"data": dict(self.data),
"origin": str(self.origin),
"time_fired": self.time_fired,
"origin": str(self.origin.value),
"time_fired": self.time_fired.isoformat(),
"context": self.context.as_dict(),
}
@ -626,6 +627,7 @@ class EventBus:
event_data: Optional[Dict] = None,
origin: EventOrigin = EventOrigin.local,
context: Optional[Context] = None,
time_fired: Optional[datetime.datetime] = None,
) -> None:
"""Fire an event.
@ -638,7 +640,7 @@ class EventBus:
if match_all_listeners is not None and event_type != EVENT_HOMEASSISTANT_CLOSE:
listeners = match_all_listeners + listeners
event = Event(event_type, event_data, origin, None, context)
event = Event(event_type, event_data, origin, time_fired, context)
if event_type != EVENT_TIME_CHANGED:
_LOGGER.debug("Bus:Handling %s", event)
@ -771,6 +773,7 @@ class State:
"context",
"domain",
"object_id",
"_as_dict",
]
def __init__(
@ -805,6 +808,7 @@ class State:
self.last_changed = last_changed or self.last_updated
self.context = context or Context()
self.domain, self.object_id = split_entity_id(self.entity_id)
self._as_dict: Optional[Dict[str, Collection[Any]]] = None
@property
def name(self) -> str:
@ -821,14 +825,21 @@ class State:
To be used for JSON serialization.
Ensures: state == State.from_dict(state.as_dict())
"""
return {
"entity_id": self.entity_id,
"state": self.state,
"attributes": dict(self.attributes),
"last_changed": self.last_changed,
"last_updated": self.last_updated,
"context": self.context.as_dict(),
}
if not self._as_dict:
last_changed_isoformat = self.last_changed.isoformat()
if self.last_changed == self.last_updated:
last_updated_isoformat = last_changed_isoformat
else:
last_updated_isoformat = self.last_updated.isoformat()
self._as_dict = {
"entity_id": self.entity_id,
"state": self.state,
"attributes": dict(self.attributes),
"last_changed": last_changed_isoformat,
"last_updated": last_updated_isoformat,
"context": self.context.as_dict(),
}
return self._as_dict
@classmethod
def from_dict(cls, json_dict: Dict) -> Any:
@ -1643,13 +1654,18 @@ def _async_create_timer(hass: HomeAssistant) -> None:
"""Fire next time event."""
now = dt_util.utcnow()
hass.bus.async_fire(EVENT_TIME_CHANGED, {ATTR_NOW: now}, context=timer_context)
hass.bus.async_fire(
EVENT_TIME_CHANGED, {ATTR_NOW: now}, time_fired=now, context=timer_context
)
# If we are more than a second late, a tick was missed
late = monotonic() - target
if late > 1:
hass.bus.async_fire(
EVENT_TIMER_OUT_OF_SYNC, {ATTR_SECONDS: late}, context=timer_context
EVENT_TIMER_OUT_OF_SYNC,
{ATTR_SECONDS: late},
time_fired=now,
context=timer_context,
)
schedule_tick(now)

View file

@ -201,10 +201,7 @@ async def test_get_states(hass, websocket_client):
states = []
for state in hass.states.async_all():
state = state.as_dict()
state["last_changed"] = state["last_changed"].isoformat()
state["last_updated"] = state["last_updated"].isoformat()
states.append(state)
states.append(state.as_dict())
assert msg["result"] == states

View file

@ -291,7 +291,7 @@ def test_event_repr():
def test_event_as_dict():
"""Test as Event as dictionary."""
"""Test an Event as dictionary."""
event_type = "some_type"
now = dt_util.utcnow()
data = {"some": "attr"}
@ -301,7 +301,7 @@ def test_event_as_dict():
"event_type": event_type,
"data": data,
"origin": "LOCAL",
"time_fired": now,
"time_fired": now.isoformat(),
"context": {
"id": event.context.id,
"parent_id": None,
@ -309,6 +309,36 @@ def test_event_as_dict():
},
}
assert event.as_dict() == expected
# 2nd time to verify cache
assert event.as_dict() == expected
def test_state_as_dict():
"""Test a State as dictionary."""
last_time = datetime(1984, 12, 8, 12, 0, 0)
state = ha.State(
"happy.happy",
"on",
{"pig": "dog"},
last_updated=last_time,
last_changed=last_time,
)
expected = {
"context": {
"id": state.context.id,
"parent_id": None,
"user_id": state.context.user_id,
},
"entity_id": "happy.happy",
"attributes": {"pig": "dog"},
"last_changed": last_time.isoformat(),
"last_updated": last_time.isoformat(),
"state": "on",
}
assert state.as_dict() == expected
# 2nd time to verify cache
assert state.as_dict() == expected
assert state.as_dict() is state.as_dict()
class TestEventBus(unittest.TestCase):