mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Make core States use cached_property (#100312)
Need to validate this is worth removing __slots__
This commit is contained in:
parent
3cc9410a62
commit
547f32818c
@ -202,11 +202,11 @@ class APIStatesView(HomeAssistantView):
|
|||||||
user: User = request["hass_user"]
|
user: User = request["hass_user"]
|
||||||
hass: HomeAssistant = request.app["hass"]
|
hass: HomeAssistant = request.app["hass"]
|
||||||
if user.is_admin:
|
if user.is_admin:
|
||||||
states = (state.as_dict_json() for state in hass.states.async_all())
|
states = (state.as_dict_json for state in hass.states.async_all())
|
||||||
else:
|
else:
|
||||||
entity_perm = user.permissions.check_entity
|
entity_perm = user.permissions.check_entity
|
||||||
states = (
|
states = (
|
||||||
state.as_dict_json()
|
state.as_dict_json
|
||||||
for state in hass.states.async_all()
|
for state in hass.states.async_all()
|
||||||
if entity_perm(state.entity_id, "read")
|
if entity_perm(state.entity_id, "read")
|
||||||
)
|
)
|
||||||
@ -233,7 +233,7 @@ class APIEntityStateView(HomeAssistantView):
|
|||||||
|
|
||||||
if state := hass.states.get(entity_id):
|
if state := hass.states.get(entity_id):
|
||||||
return web.Response(
|
return web.Response(
|
||||||
body=state.as_dict_json(),
|
body=state.as_dict_json,
|
||||||
content_type=CONTENT_TYPE_JSON,
|
content_type=CONTENT_TYPE_JSON,
|
||||||
)
|
)
|
||||||
return self.json_message("Entity not found.", HTTPStatus.NOT_FOUND)
|
return self.json_message("Entity not found.", HTTPStatus.NOT_FOUND)
|
||||||
|
@ -270,7 +270,7 @@ def handle_get_states(
|
|||||||
states = _async_get_allowed_states(hass, connection)
|
states = _async_get_allowed_states(hass, connection)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
serialized_states = [state.as_dict_json() for state in states]
|
serialized_states = [state.as_dict_json for state in states]
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@ -281,7 +281,7 @@ def handle_get_states(
|
|||||||
serialized_states = []
|
serialized_states = []
|
||||||
for state in states:
|
for state in states:
|
||||||
try:
|
try:
|
||||||
serialized_states.append(state.as_dict_json())
|
serialized_states.append(state.as_dict_json)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
connection.logger.error(
|
connection.logger.error(
|
||||||
"Unable to serialize to JSON. Bad data found at %s",
|
"Unable to serialize to JSON. Bad data found at %s",
|
||||||
@ -358,7 +358,7 @@ def handle_subscribe_entities(
|
|||||||
# to succeed for the UI to show.
|
# to succeed for the UI to show.
|
||||||
try:
|
try:
|
||||||
serialized_states = [
|
serialized_states = [
|
||||||
state.as_compressed_state_json()
|
state.as_compressed_state_json
|
||||||
for state in states
|
for state in states
|
||||||
if not entity_ids or state.entity_id in entity_ids
|
if not entity_ids or state.entity_id in entity_ids
|
||||||
]
|
]
|
||||||
@ -371,7 +371,7 @@ def handle_subscribe_entities(
|
|||||||
serialized_states = []
|
serialized_states = []
|
||||||
for state in states:
|
for state in states:
|
||||||
try:
|
try:
|
||||||
serialized_states.append(state.as_compressed_state_json())
|
serialized_states.append(state.as_compressed_state_json)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
connection.logger.error(
|
connection.logger.error(
|
||||||
"Unable to serialize to JSON. Bad data found at %s",
|
"Unable to serialize to JSON. Bad data found at %s",
|
||||||
|
@ -141,7 +141,7 @@ def _state_diff_event(event: Event) -> dict:
|
|||||||
if (event_old_state := event.data["old_state"]) is None:
|
if (event_old_state := event.data["old_state"]) is None:
|
||||||
return {
|
return {
|
||||||
ENTITY_EVENT_ADD: {
|
ENTITY_EVENT_ADD: {
|
||||||
event_new_state.entity_id: event_new_state.as_compressed_state()
|
event_new_state.entity_id: event_new_state.as_compressed_state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -35,6 +35,7 @@ import voluptuous as vol
|
|||||||
import yarl
|
import yarl
|
||||||
|
|
||||||
from . import block_async_io, util
|
from . import block_async_io, util
|
||||||
|
from .backports.functools import cached_property
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_DOMAIN,
|
ATTR_DOMAIN,
|
||||||
ATTR_FRIENDLY_NAME,
|
ATTR_FRIENDLY_NAME,
|
||||||
@ -1239,20 +1240,6 @@ class State:
|
|||||||
object_id: Object id of this state.
|
object_id: Object id of this state.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = (
|
|
||||||
"entity_id",
|
|
||||||
"state",
|
|
||||||
"attributes",
|
|
||||||
"last_changed",
|
|
||||||
"last_updated",
|
|
||||||
"context",
|
|
||||||
"domain",
|
|
||||||
"object_id",
|
|
||||||
"_as_dict",
|
|
||||||
"_as_dict_json",
|
|
||||||
"_as_compressed_state_json",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
entity_id: str,
|
entity_id: str,
|
||||||
@ -1282,8 +1269,6 @@ class State:
|
|||||||
self.context = context or Context()
|
self.context = context or Context()
|
||||||
self.domain, self.object_id = split_entity_id(self.entity_id)
|
self.domain, self.object_id = split_entity_id(self.entity_id)
|
||||||
self._as_dict: ReadOnlyDict[str, Collection[Any]] | None = None
|
self._as_dict: ReadOnlyDict[str, Collection[Any]] | None = None
|
||||||
self._as_dict_json: str | None = None
|
|
||||||
self._as_compressed_state_json: str | None = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
@ -1318,12 +1303,12 @@ class State:
|
|||||||
)
|
)
|
||||||
return self._as_dict
|
return self._as_dict
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def as_dict_json(self) -> str:
|
def as_dict_json(self) -> str:
|
||||||
"""Return a JSON string of the State."""
|
"""Return a JSON string of the State."""
|
||||||
if not self._as_dict_json:
|
return json_dumps(self.as_dict())
|
||||||
self._as_dict_json = json_dumps(self.as_dict())
|
|
||||||
return self._as_dict_json
|
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def as_compressed_state(self) -> dict[str, Any]:
|
def as_compressed_state(self) -> dict[str, Any]:
|
||||||
"""Build a compressed dict of a state for adds.
|
"""Build a compressed dict of a state for adds.
|
||||||
|
|
||||||
@ -1348,6 +1333,7 @@ class State:
|
|||||||
)
|
)
|
||||||
return compressed_state
|
return compressed_state
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def as_compressed_state_json(self) -> str:
|
def as_compressed_state_json(self) -> str:
|
||||||
"""Build a compressed JSON key value pair of a state for adds.
|
"""Build a compressed JSON key value pair of a state for adds.
|
||||||
|
|
||||||
@ -1355,11 +1341,7 @@ class State:
|
|||||||
|
|
||||||
It is used for sending multiple states in a single message.
|
It is used for sending multiple states in a single message.
|
||||||
"""
|
"""
|
||||||
if not self._as_compressed_state_json:
|
return json_dumps({self.entity_id: self.as_compressed_state})[1:-1]
|
||||||
self._as_compressed_state_json = json_dumps(
|
|
||||||
{self.entity_id: self.as_compressed_state()}
|
|
||||||
)[1:-1]
|
|
||||||
return self._as_compressed_state_json
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, json_dict: dict[str, Any]) -> Self | None:
|
def from_dict(cls, json_dict: dict[str, Any]) -> Self | None:
|
||||||
|
@ -929,8 +929,6 @@ 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", "__dict__")
|
|
||||||
|
|
||||||
_state: State
|
_state: State
|
||||||
|
|
||||||
__setitem__ = _readonly
|
__setitem__ = _readonly
|
||||||
|
@ -671,11 +671,11 @@ def test_state_as_dict_json() -> None:
|
|||||||
'"last_changed":"1984-12-08T12:00:00","last_updated":"1984-12-08T12:00:00",'
|
'"last_changed":"1984-12-08T12:00:00","last_updated":"1984-12-08T12:00:00",'
|
||||||
'"context":{"id":"01H0D6K3RFJAYAV2093ZW30PCW","parent_id":null,"user_id":null}}'
|
'"context":{"id":"01H0D6K3RFJAYAV2093ZW30PCW","parent_id":null,"user_id":null}}'
|
||||||
)
|
)
|
||||||
as_dict_json_1 = state.as_dict_json()
|
as_dict_json_1 = state.as_dict_json
|
||||||
assert as_dict_json_1 == expected
|
assert as_dict_json_1 == expected
|
||||||
# 2nd time to verify cache
|
# 2nd time to verify cache
|
||||||
assert state.as_dict_json() == expected
|
assert state.as_dict_json == expected
|
||||||
assert state.as_dict_json() is as_dict_json_1
|
assert state.as_dict_json is as_dict_json_1
|
||||||
|
|
||||||
|
|
||||||
def test_state_as_compressed_state() -> None:
|
def test_state_as_compressed_state() -> None:
|
||||||
@ -694,12 +694,12 @@ def test_state_as_compressed_state() -> None:
|
|||||||
"lc": last_time.timestamp(),
|
"lc": last_time.timestamp(),
|
||||||
"s": "on",
|
"s": "on",
|
||||||
}
|
}
|
||||||
as_compressed_state = state.as_compressed_state()
|
as_compressed_state = state.as_compressed_state
|
||||||
# We are not too concerned about these being ReadOnlyDict
|
# We are not too concerned about these being ReadOnlyDict
|
||||||
# since we don't expect them to be called by external callers
|
# since we don't expect them to be called by external callers
|
||||||
assert as_compressed_state == expected
|
assert as_compressed_state == expected
|
||||||
# 2nd time to verify cache
|
# 2nd time to verify cache
|
||||||
assert state.as_compressed_state() == expected
|
assert state.as_compressed_state == expected
|
||||||
|
|
||||||
|
|
||||||
def test_state_as_compressed_state_unique_last_updated() -> None:
|
def test_state_as_compressed_state_unique_last_updated() -> None:
|
||||||
@ -720,12 +720,12 @@ def test_state_as_compressed_state_unique_last_updated() -> None:
|
|||||||
"lu": last_updated.timestamp(),
|
"lu": last_updated.timestamp(),
|
||||||
"s": "on",
|
"s": "on",
|
||||||
}
|
}
|
||||||
as_compressed_state = state.as_compressed_state()
|
as_compressed_state = state.as_compressed_state
|
||||||
# We are not too concerned about these being ReadOnlyDict
|
# We are not too concerned about these being ReadOnlyDict
|
||||||
# since we don't expect them to be called by external callers
|
# since we don't expect them to be called by external callers
|
||||||
assert as_compressed_state == expected
|
assert as_compressed_state == expected
|
||||||
# 2nd time to verify cache
|
# 2nd time to verify cache
|
||||||
assert state.as_compressed_state() == expected
|
assert state.as_compressed_state == expected
|
||||||
|
|
||||||
|
|
||||||
def test_state_as_compressed_state_json() -> None:
|
def test_state_as_compressed_state_json() -> None:
|
||||||
@ -740,13 +740,13 @@ def test_state_as_compressed_state_json() -> None:
|
|||||||
context=ha.Context(id="01H0D6H5K3SZJ3XGDHED1TJ79N"),
|
context=ha.Context(id="01H0D6H5K3SZJ3XGDHED1TJ79N"),
|
||||||
)
|
)
|
||||||
expected = '"happy.happy":{"s":"on","a":{"pig":"dog"},"c":"01H0D6H5K3SZJ3XGDHED1TJ79N","lc":471355200.0}'
|
expected = '"happy.happy":{"s":"on","a":{"pig":"dog"},"c":"01H0D6H5K3SZJ3XGDHED1TJ79N","lc":471355200.0}'
|
||||||
as_compressed_state = state.as_compressed_state_json()
|
as_compressed_state = state.as_compressed_state_json
|
||||||
# We are not too concerned about these being ReadOnlyDict
|
# We are not too concerned about these being ReadOnlyDict
|
||||||
# since we don't expect them to be called by external callers
|
# since we don't expect them to be called by external callers
|
||||||
assert as_compressed_state == expected
|
assert as_compressed_state == expected
|
||||||
# 2nd time to verify cache
|
# 2nd time to verify cache
|
||||||
assert state.as_compressed_state_json() == expected
|
assert state.as_compressed_state_json == expected
|
||||||
assert state.as_compressed_state_json() is as_compressed_state
|
assert state.as_compressed_state_json is as_compressed_state
|
||||||
|
|
||||||
|
|
||||||
async def test_eventbus_add_remove_listener(hass: HomeAssistant) -> None:
|
async def test_eventbus_add_remove_listener(hass: HomeAssistant) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user