Use python defaults for comparing State, LazyState, and Event objects (#86856)

* Speed up comparing State and Event objects

Use default python implementation for State and Event __hash__ and __eq__

The default implementation compared based on the id() of the object
which is effectively what we want here anyways. These overrides are
left over from the days when these used to be attrs objects

By avoiding implementing these ourselves all of the equality checks
can happen in native code

* tweak

* adjust tests

* write out some more

* fix test to not compare objects

* more test fixes

* more test fixes

* correct stats tests

* fix more tests

* fix more tests

* update sensor recorder tests
This commit is contained in:
J. Nick Koston 2023-01-29 08:31:43 -10:00 committed by GitHub
parent 80ffac48a3
commit c612a92cfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 389 additions and 174 deletions

View File

@ -233,15 +233,6 @@ class LazyStatePreSchema31(State):
"last_updated": last_updated_isoformat, "last_updated": last_updated_isoformat,
} }
def __eq__(self, other: Any) -> bool:
"""Return the comparison."""
return (
other.__class__ in [self.__class__, State]
and self.entity_id == other.entity_id
and self.state == other.state
and self.attributes == other.attributes
)
class LazyState(State): class LazyState(State):
"""A lazy version of core State after schema 31.""" """A lazy version of core State after schema 31."""
@ -341,15 +332,6 @@ class LazyState(State):
"last_updated": last_updated_isoformat, "last_updated": last_updated_isoformat,
} }
def __eq__(self, other: Any) -> bool:
"""Return the comparison."""
return (
other.__class__ in [self.__class__, State]
and self.entity_id == other.entity_id
and self.state == other.state
and self.attributes == other.attributes
)
def decode_attributes_from_row( def decode_attributes_from_row(
row: Row, attr_cache: dict[str, dict[str, Any]] row: Row, attr_cache: dict[str, dict[str, Any]]

View File

@ -813,11 +813,6 @@ class Event:
id=ulid_util.ulid(dt_util.utc_to_timestamp(self.time_fired)) id=ulid_util.ulid(dt_util.utc_to_timestamp(self.time_fired))
) )
def __hash__(self) -> int:
"""Make hashable."""
# The only event type that shares context are the TIME_CHANGED
return hash((self.event_type, self.context.id, self.time_fired))
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.
@ -841,17 +836,6 @@ class Event:
return f"<Event {self.event_type}[{str(self.origin)[0]}]>" return f"<Event {self.event_type}[{str(self.origin)[0]}]>"
def __eq__(self, other: Any) -> bool:
"""Return the comparison."""
return ( # type: ignore[no-any-return]
self.__class__ == other.__class__
and self.event_type == other.event_type
and self.data == other.data
and self.origin == other.origin
and self.time_fired == other.time_fired
and self.context == other.context
)
class _FilterableJob(NamedTuple): class _FilterableJob(NamedTuple):
"""Event listener job to be executed with optional filter.""" """Event listener job to be executed with optional filter."""
@ -1156,13 +1140,6 @@ class State:
self._as_dict: ReadOnlyDict[str, Collection[Any]] | None = None self._as_dict: ReadOnlyDict[str, Collection[Any]] | None = None
self._as_compressed_state: dict[str, Any] | None = None self._as_compressed_state: dict[str, Any] | None = None
def __hash__(self) -> int:
"""Make the state hashable.
State objects are effectively immutable.
"""
return hash((id(self), self.last_updated))
@property @property
def name(self) -> str: def name(self) -> str:
"""Name of this state.""" """Name of this state."""
@ -1274,16 +1251,6 @@ class State:
self.context.user_id, self.context.parent_id, self.context.id self.context.user_id, self.context.parent_id, self.context.id
) )
def __eq__(self, other: Any) -> bool:
"""Return the comparison of the state."""
return ( # type: ignore[no-any-return]
self.__class__ == other.__class__
and self.entity_id == other.entity_id
and self.state == other.state
and self.attributes == other.attributes
and self.context == other.context
)
def __repr__(self) -> str: def __repr__(self) -> str:
"""Return the representation of the states.""" """Return the representation of the states."""
attrs = f"; {util.repr_helper(self.attributes)}" if self.attributes else "" attrs = f"; {util.repr_helper(self.attributes)}" if self.attributes else ""

View File

@ -30,8 +30,9 @@ async def test_api_list_state_entities(hass, mock_api_client):
assert resp.status == HTTPStatus.OK assert resp.status == HTTPStatus.OK
json = await resp.json() json = await resp.json()
remote_data = [ha.State.from_dict(item) for item in json] remote_data = [ha.State.from_dict(item).as_dict() for item in json]
assert remote_data == hass.states.async_all() local_data = [state.as_dict() for state in hass.states.async_all()]
assert remote_data == local_data
async def test_api_get_state(hass, mock_api_client): async def test_api_get_state(hass, mock_api_client):

View File

@ -1,7 +1,7 @@
"""The tests for reproduction of state.""" """The tests for reproduction of state."""
from asyncio import Future from asyncio import Future
from unittest.mock import patch from unittest.mock import ANY, patch
from homeassistant.components.group.reproduce_state import async_reproduce_states from homeassistant.components.group.reproduce_state import async_reproduce_states
from homeassistant.core import Context, State from homeassistant.core import Context, State
@ -43,11 +43,12 @@ async def test_reproduce_group(hass):
fun.assert_called_once_with( fun.assert_called_once_with(
hass, hass,
[ ANY,
clone_state(state, "light.test1"),
clone_state(state, "light.test2"),
clone_state(state, "switch.test1"),
],
context=context, context=context,
reproduce_options=None, reproduce_options=None,
) )
entities = fun.call_args[0][1]
assert entities[0].entity_id == "light.test1"
assert entities[1].entity_id == "light.test2"
assert entities[2].entity_id == "switch.test1"

View File

@ -1 +1,5 @@
"""Tests for the history component.""" """Tests for the history component."""
import pytest
pytest.register_assert_rewrite("tests.components.recorder.common")

View File

@ -23,6 +23,10 @@ from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from tests.components.recorder.common import ( from tests.components.recorder.common import (
assert_dict_of_states_equal_without_context_and_last_changed,
assert_multiple_states_equal_without_context,
assert_multiple_states_equal_without_context_and_last_changed,
assert_states_equal_without_context,
async_wait_recording_done, async_wait_recording_done,
wait_recording_done, wait_recording_done,
) )
@ -53,7 +57,7 @@ def test_get_significant_states(hass_history):
hass = hass_history hass = hass_history
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = get_significant_states(hass, zero, four, filters=history.Filters()) hist = get_significant_states(hass, zero, four, filters=history.Filters())
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_minimal_response(hass_history): def test_get_significant_states_minimal_response(hass_history):
@ -95,7 +99,30 @@ def test_get_significant_states_minimal_response(hass_history):
"last_changed": orig_last_changed, "last_changed": orig_last_changed,
"state": orig_state, "state": orig_state,
} }
assert states == hist assert len(hist) == len(states)
assert_states_equal_without_context(
states["media_player.test"][0], hist["media_player.test"][0]
)
assert states["media_player.test"][1] == hist["media_player.test"][1]
assert states["media_player.test"][2] == hist["media_player.test"][2]
assert_multiple_states_equal_without_context(
states["media_player.test2"], hist["media_player.test2"]
)
assert_states_equal_without_context(
states["media_player.test3"][0], hist["media_player.test3"][0]
)
assert states["media_player.test3"][1] == hist["media_player.test3"][1]
assert_multiple_states_equal_without_context(
states["script.can_cancel_this_one"], hist["script.can_cancel_this_one"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test2"], hist["thermostat.test2"]
)
def test_get_significant_states_with_initial(hass_history): def test_get_significant_states_with_initial(hass_history):
@ -123,7 +150,7 @@ def test_get_significant_states_with_initial(hass_history):
filters=history.Filters(), filters=history.Filters(),
include_start_time_state=True, include_start_time_state=True,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_without_initial(hass_history): def test_get_significant_states_without_initial(hass_history):
@ -150,7 +177,7 @@ def test_get_significant_states_without_initial(hass_history):
filters=history.Filters(), filters=history.Filters(),
include_start_time_state=False, include_start_time_state=False,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_entity_id(hass_history): def test_get_significant_states_entity_id(hass_history):
@ -166,7 +193,7 @@ def test_get_significant_states_entity_id(hass_history):
hist = get_significant_states( hist = get_significant_states(
hass, zero, four, ["media_player.test"], filters=history.Filters() hass, zero, four, ["media_player.test"], filters=history.Filters()
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_multiple_entity_ids(hass_history): def test_get_significant_states_multiple_entity_ids(hass_history):
@ -185,7 +212,7 @@ def test_get_significant_states_multiple_entity_ids(hass_history):
["media_player.test", "thermostat.test"], ["media_player.test", "thermostat.test"],
filters=history.Filters(), filters=history.Filters(),
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_exclude_domain(hass_history): def test_get_significant_states_exclude_domain(hass_history):
@ -490,14 +517,22 @@ def test_get_significant_states_only(hass_history):
hist = get_significant_states(hass, start, significant_changes_only=True) hist = get_significant_states(hass, start, significant_changes_only=True)
assert len(hist[entity_id]) == 2 assert len(hist[entity_id]) == 2
assert states[0] not in hist[entity_id] assert not any(
assert states[1] in hist[entity_id] state.last_updated == states[0].last_updated for state in hist[entity_id]
assert states[2] in hist[entity_id] )
assert any(
state.last_updated == states[1].last_updated for state in hist[entity_id]
)
assert any(
state.last_updated == states[2].last_updated for state in hist[entity_id]
)
hist = get_significant_states(hass, start, significant_changes_only=False) hist = get_significant_states(hass, start, significant_changes_only=False)
assert len(hist[entity_id]) == 3 assert len(hist[entity_id]) == 3
assert states == hist[entity_id] assert_multiple_states_equal_without_context_and_last_changed(
states, hist[entity_id]
)
def check_significant_states(hass, zero, four, states, config): def check_significant_states(hass, zero, four, states, config):
@ -513,7 +548,7 @@ def check_significant_states(hass, zero, four, states, config):
filters.included_domains = include.get(CONF_DOMAINS, []) filters.included_domains = include.get(CONF_DOMAINS, [])
hist = get_significant_states(hass, zero, four, filters=filters) hist = get_significant_states(hass, zero, four, filters=filters)
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def record_states(hass): def record_states(hass):

View File

@ -24,6 +24,10 @@ from homeassistant.setup import async_setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from tests.components.recorder.common import ( from tests.components.recorder.common import (
assert_dict_of_states_equal_without_context_and_last_changed,
assert_multiple_states_equal_without_context,
assert_multiple_states_equal_without_context_and_last_changed,
assert_states_equal_without_context,
async_recorder_block_till_done, async_recorder_block_till_done,
async_wait_recording_done, async_wait_recording_done,
wait_recording_done, wait_recording_done,
@ -91,7 +95,7 @@ def test_get_significant_states(hass_history):
hass = hass_history hass = hass_history
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = get_significant_states(hass, zero, four, filters=history.Filters()) hist = get_significant_states(hass, zero, four, filters=history.Filters())
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_minimal_response(hass_history): def test_get_significant_states_minimal_response(hass_history):
@ -133,7 +137,31 @@ def test_get_significant_states_minimal_response(hass_history):
"last_changed": orig_last_changed, "last_changed": orig_last_changed,
"state": orig_state, "state": orig_state,
} }
assert states == hist
assert len(hist) == len(states)
assert_states_equal_without_context(
states["media_player.test"][0], hist["media_player.test"][0]
)
assert states["media_player.test"][1] == hist["media_player.test"][1]
assert states["media_player.test"][2] == hist["media_player.test"][2]
assert_multiple_states_equal_without_context(
states["media_player.test2"], hist["media_player.test2"]
)
assert_states_equal_without_context(
states["media_player.test3"][0], hist["media_player.test3"][0]
)
assert states["media_player.test3"][1] == hist["media_player.test3"][1]
assert_multiple_states_equal_without_context(
states["script.can_cancel_this_one"], hist["script.can_cancel_this_one"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test2"], hist["thermostat.test2"]
)
def test_get_significant_states_with_initial(hass_history): def test_get_significant_states_with_initial(hass_history):
@ -153,6 +181,7 @@ def test_get_significant_states_with_initial(hass_history):
for state in states[entity_id]: for state in states[entity_id]:
if state.last_changed == one: if state.last_changed == one:
state.last_changed = one_and_half state.last_changed = one_and_half
state.last_updated = one_and_half
hist = get_significant_states( hist = get_significant_states(
hass, hass,
@ -161,7 +190,7 @@ def test_get_significant_states_with_initial(hass_history):
filters=history.Filters(), filters=history.Filters(),
include_start_time_state=True, include_start_time_state=True,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_without_initial(hass_history): def test_get_significant_states_without_initial(hass_history):
@ -188,7 +217,7 @@ def test_get_significant_states_without_initial(hass_history):
filters=history.Filters(), filters=history.Filters(),
include_start_time_state=False, include_start_time_state=False,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_entity_id(hass_history): def test_get_significant_states_entity_id(hass_history):
@ -204,7 +233,7 @@ def test_get_significant_states_entity_id(hass_history):
hist = get_significant_states( hist = get_significant_states(
hass, zero, four, ["media_player.test"], filters=history.Filters() hass, zero, four, ["media_player.test"], filters=history.Filters()
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_multiple_entity_ids(hass_history): def test_get_significant_states_multiple_entity_ids(hass_history):
@ -223,7 +252,7 @@ def test_get_significant_states_multiple_entity_ids(hass_history):
["media_player.test", "thermostat.test"], ["media_player.test", "thermostat.test"],
filters=history.Filters(), filters=history.Filters(),
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_exclude_domain(hass_history): def test_get_significant_states_exclude_domain(hass_history):
@ -528,14 +557,22 @@ def test_get_significant_states_only(hass_history):
hist = get_significant_states(hass, start, significant_changes_only=True) hist = get_significant_states(hass, start, significant_changes_only=True)
assert len(hist[entity_id]) == 2 assert len(hist[entity_id]) == 2
assert states[0] not in hist[entity_id] assert not any(
assert states[1] in hist[entity_id] state.last_updated == states[0].last_updated for state in hist[entity_id]
assert states[2] in hist[entity_id] )
assert any(
state.last_updated == states[1].last_updated for state in hist[entity_id]
)
assert any(
state.last_updated == states[2].last_updated for state in hist[entity_id]
)
hist = get_significant_states(hass, start, significant_changes_only=False) hist = get_significant_states(hass, start, significant_changes_only=False)
assert len(hist[entity_id]) == 3 assert len(hist[entity_id]) == 3
assert states == hist[entity_id] assert_multiple_states_equal_without_context_and_last_changed(
states, hist[entity_id]
)
def check_significant_states(hass, zero, four, states, config): def check_significant_states(hass, zero, four, states, config):
@ -551,7 +588,7 @@ def check_significant_states(hass, zero, four, states, config):
filters.included_domains = include.get(CONF_DOMAINS, []) filters.included_domains = include.get(CONF_DOMAINS, [])
hist = get_significant_states(hass, zero, four, filters=filters) hist = get_significant_states(hass, zero, four, filters=filters)
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def record_states(hass): def record_states(hass):

View File

@ -1 +1,5 @@
"""Tests for Recorder component.""" """Tests for Recorder component."""
import pytest
pytest.register_assert_rewrite("tests.components.recorder.common")

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from collections.abc import Iterable
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
import time import time
@ -16,7 +17,7 @@ from homeassistant.components.recorder import get_instance, statistics
from homeassistant.components.recorder.core import Recorder from homeassistant.components.recorder.core import Recorder
from homeassistant.components.recorder.db_schema import RecorderRuns from homeassistant.components.recorder.db_schema import RecorderRuns
from homeassistant.components.recorder.tasks import RecorderTask, StatisticsTask from homeassistant.components.recorder.tasks import RecorderTask, StatisticsTask
from homeassistant.core import HomeAssistant from homeassistant.core import Event, HomeAssistant, State
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from . import db_schema_0 from . import db_schema_0
@ -155,3 +156,68 @@ def statistics_during_period(
return statistics.statistics_during_period( return statistics.statistics_during_period(
hass, start_time, end_time, statistic_ids, period, units, types hass, start_time, end_time, statistic_ids, period, units, types
) )
def assert_states_equal_without_context(state: State, other: State) -> None:
"""Assert that two states are equal, ignoring context."""
assert_states_equal_without_context_and_last_changed(state, other)
assert state.last_changed == other.last_changed
def assert_states_equal_without_context_and_last_changed(
state: State, other: State
) -> None:
"""Assert that two states are equal, ignoring context and last_changed."""
assert state.state == other.state
assert state.attributes == other.attributes
assert state.last_updated == other.last_updated
def assert_multiple_states_equal_without_context_and_last_changed(
states: Iterable[State], others: Iterable[State]
) -> None:
"""Assert that multiple states are equal, ignoring context and last_changed."""
states_list = list(states)
others_list = list(others)
assert len(states_list) == len(others_list)
for i, state in enumerate(states_list):
assert_states_equal_without_context_and_last_changed(state, others_list[i])
def assert_multiple_states_equal_without_context(
states: Iterable[State], others: Iterable[State]
) -> None:
"""Assert that multiple states are equal, ignoring context."""
states_list = list(states)
others_list = list(others)
assert len(states_list) == len(others_list)
for i, state in enumerate(states_list):
assert_states_equal_without_context(state, others_list[i])
def assert_events_equal_without_context(event: Event, other: Event) -> None:
"""Assert that two events are equal, ignoring context."""
assert event.data == other.data
assert event.event_type == other.event_type
assert event.origin == other.origin
assert event.time_fired == other.time_fired
def assert_dict_of_states_equal_without_context(
states: dict[str, list[State]], others: dict[str, list[State]]
) -> None:
"""Assert that two dicts of states are equal, ignoring context."""
assert len(states) == len(others)
for entity_id, state in states.items():
assert_multiple_states_equal_without_context(state, others[entity_id])
def assert_dict_of_states_equal_without_context_and_last_changed(
states: dict[str, list[State]], others: dict[str, list[State]]
) -> None:
"""Assert that two dicts of states are equal, ignoring context and last_changed."""
assert len(states) == len(others)
for entity_id, state in states.items():
assert_multiple_states_equal_without_context_and_last_changed(
state, others[entity_id]
)

View File

@ -30,6 +30,10 @@ from homeassistant.helpers.json import JSONEncoder
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .common import ( from .common import (
assert_dict_of_states_equal_without_context_and_last_changed,
assert_multiple_states_equal_without_context,
assert_multiple_states_equal_without_context_and_last_changed,
assert_states_equal_without_context,
async_recorder_block_till_done, async_recorder_block_till_done,
async_wait_recording_done, async_wait_recording_done,
wait_recording_done, wait_recording_done,
@ -250,7 +254,7 @@ def test_state_changes_during_period(hass_recorder, attributes, no_attributes, l
hass, start, end, entity_id, no_attributes, limit=limit hass, start, end, entity_id, no_attributes, limit=limit
) )
assert states[:limit] == hist[entity_id] assert_multiple_states_equal_without_context(states[:limit], hist[entity_id])
def test_state_changes_during_period_descending(hass_recorder): def test_state_changes_during_period_descending(hass_recorder):
@ -303,12 +307,14 @@ def test_state_changes_during_period_descending(hass_recorder):
hist = history.state_changes_during_period( hist = history.state_changes_during_period(
hass, start, end, entity_id, no_attributes=False, descending=False hass, start, end, entity_id, no_attributes=False, descending=False
) )
assert states == hist[entity_id] assert_multiple_states_equal_without_context(states, hist[entity_id])
hist = history.state_changes_during_period( hist = history.state_changes_during_period(
hass, start, end, entity_id, no_attributes=False, descending=True hass, start, end, entity_id, no_attributes=False, descending=True
) )
assert states == list(reversed(list(hist[entity_id]))) assert_multiple_states_equal_without_context(
states, list(reversed(list(hist[entity_id])))
)
def test_get_last_state_changes(hass_recorder): def test_get_last_state_changes(hass_recorder):
@ -344,7 +350,7 @@ def test_get_last_state_changes(hass_recorder):
hist = history.get_last_state_changes(hass, 2, entity_id) hist = history.get_last_state_changes(hass, 2, entity_id)
assert states == hist[entity_id] assert_multiple_states_equal_without_context(states, hist[entity_id])
def test_ensure_state_can_be_copied(hass_recorder): def test_ensure_state_can_be_copied(hass_recorder):
@ -377,8 +383,8 @@ def test_ensure_state_can_be_copied(hass_recorder):
hist = history.get_last_state_changes(hass, 2, entity_id) hist = history.get_last_state_changes(hass, 2, entity_id)
assert copy(hist[entity_id][0]) == hist[entity_id][0] assert_states_equal_without_context(copy(hist[entity_id][0]), hist[entity_id][0])
assert copy(hist[entity_id][1]) == hist[entity_id][1] assert_states_equal_without_context(copy(hist[entity_id][1]), hist[entity_id][1])
def test_get_significant_states(hass_recorder): def test_get_significant_states(hass_recorder):
@ -391,7 +397,7 @@ def test_get_significant_states(hass_recorder):
hass = hass_recorder() hass = hass_recorder()
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_minimal_response(hass_recorder): def test_get_significant_states_minimal_response(hass_recorder):
@ -431,7 +437,31 @@ def test_get_significant_states_minimal_response(hass_recorder):
"last_changed": orig_last_changed, "last_changed": orig_last_changed,
"state": orig_state, "state": orig_state,
} }
assert states == hist
assert len(hist) == len(states)
assert_states_equal_without_context(
states["media_player.test"][0], hist["media_player.test"][0]
)
assert states["media_player.test"][1] == hist["media_player.test"][1]
assert states["media_player.test"][2] == hist["media_player.test"][2]
assert_multiple_states_equal_without_context(
states["media_player.test2"], hist["media_player.test2"]
)
assert_states_equal_without_context(
states["media_player.test3"][0], hist["media_player.test3"][0]
)
assert states["media_player.test3"][1] == hist["media_player.test3"][1]
assert_multiple_states_equal_without_context(
states["script.can_cancel_this_one"], hist["script.can_cancel_this_one"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test2"], hist["thermostat.test2"]
)
@pytest.mark.parametrize("time_zone", ["Europe/Berlin", "US/Hawaii", "UTC"]) @pytest.mark.parametrize("time_zone", ["Europe/Berlin", "US/Hawaii", "UTC"])
@ -460,7 +490,7 @@ def test_get_significant_states_with_initial(time_zone, hass_recorder):
four, four,
include_start_time_state=True, include_start_time_state=True,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_without_initial(hass_recorder): def test_get_significant_states_without_initial(hass_recorder):
@ -486,7 +516,7 @@ def test_get_significant_states_without_initial(hass_recorder):
four, four,
include_start_time_state=False, include_start_time_state=False,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_entity_id(hass_recorder): def test_get_significant_states_entity_id(hass_recorder):
@ -500,17 +530,13 @@ def test_get_significant_states_entity_id(hass_recorder):
del states["script.can_cancel_this_one"] del states["script.can_cancel_this_one"]
hist = history.get_significant_states(hass, zero, four, ["media_player.test"]) hist = history.get_significant_states(hass, zero, four, ["media_player.test"])
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_multiple_entity_ids(hass_recorder): def test_get_significant_states_multiple_entity_ids(hass_recorder):
"""Test that only significant states are returned for one entity.""" """Test that only significant states are returned for one entity."""
hass = hass_recorder() hass = hass_recorder()
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
del states["media_player.test2"]
del states["media_player.test3"]
del states["thermostat.test2"]
del states["script.can_cancel_this_one"]
hist = history.get_significant_states( hist = history.get_significant_states(
hass, hass,
@ -518,7 +544,13 @@ def test_get_significant_states_multiple_entity_ids(hass_recorder):
four, four,
["media_player.test", "thermostat.test"], ["media_player.test", "thermostat.test"],
) )
assert states == hist
assert_multiple_states_equal_without_context_and_last_changed(
states["media_player.test"], hist["media_player.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
def test_get_significant_states_are_ordered(hass_recorder): def test_get_significant_states_are_ordered(hass_recorder):
@ -583,14 +615,22 @@ def test_get_significant_states_only(hass_recorder):
hist = history.get_significant_states(hass, start, significant_changes_only=True) hist = history.get_significant_states(hass, start, significant_changes_only=True)
assert len(hist[entity_id]) == 2 assert len(hist[entity_id]) == 2
assert states[0] not in hist[entity_id] assert not any(
assert states[1] in hist[entity_id] state.last_updated == states[0].last_updated for state in hist[entity_id]
assert states[2] in hist[entity_id] )
assert any(
state.last_updated == states[1].last_updated for state in hist[entity_id]
)
assert any(
state.last_updated == states[2].last_updated for state in hist[entity_id]
)
hist = history.get_significant_states(hass, start, significant_changes_only=False) hist = history.get_significant_states(hass, start, significant_changes_only=False)
assert len(hist[entity_id]) == 3 assert len(hist[entity_id]) == 3
assert states == hist[entity_id] assert_multiple_states_equal_without_context_and_last_changed(
states, hist[entity_id]
)
async def test_get_significant_states_only_minimal_response(recorder_mock, hass): async def test_get_significant_states_only_minimal_response(recorder_mock, hass):
@ -885,8 +925,8 @@ async def test_get_full_significant_states_handles_empty_last_changed(
states = await recorder.get_instance(hass).async_add_executor_job(_get_entries) states = await recorder.get_instance(hass).async_add_executor_job(_get_entries)
sensor_one_states: list[State] = states["sensor.one"] sensor_one_states: list[State] = states["sensor.one"]
assert sensor_one_states[0] == state0 assert_states_equal_without_context(sensor_one_states[0], state0)
assert sensor_one_states[1] == state1 assert_states_equal_without_context(sensor_one_states[1], state1)
assert sensor_one_states[0].last_changed == sensor_one_states[1].last_changed assert sensor_one_states[0].last_changed == sensor_one_states[1].last_changed
assert sensor_one_states[0].last_updated != sensor_one_states[1].last_updated assert sensor_one_states[0].last_updated != sensor_one_states[1].last_updated
@ -908,8 +948,8 @@ async def test_get_full_significant_states_handles_empty_last_changed(
native_sensor_one_states = await recorder.get_instance(hass).async_add_executor_job( native_sensor_one_states = await recorder.get_instance(hass).async_add_executor_job(
_fetch_native_states _fetch_native_states
) )
assert native_sensor_one_states[0] == state0 assert_states_equal_without_context(native_sensor_one_states[0], state0)
assert native_sensor_one_states[1] == state1 assert_states_equal_without_context(native_sensor_one_states[1], state1)
assert ( assert (
native_sensor_one_states[0].last_changed native_sensor_one_states[0].last_changed
== native_sensor_one_states[1].last_changed == native_sensor_one_states[1].last_changed
@ -1004,7 +1044,7 @@ async def test_get_full_significant_states_past_year_2038(
states = await recorder.get_instance(hass).async_add_executor_job(_get_entries) states = await recorder.get_instance(hass).async_add_executor_job(_get_entries)
sensor_one_states: list[State] = states["sensor.one"] sensor_one_states: list[State] = states["sensor.one"]
assert sensor_one_states[0] == state0 assert_states_equal_without_context(sensor_one_states[0], state0)
assert sensor_one_states[1] == state1 assert_states_equal_without_context(sensor_one_states[1], state1)
assert sensor_one_states[0].last_changed == past_2038_time assert sensor_one_states[0].last_changed == past_2038_time
assert sensor_one_states[0].last_updated == past_2038_time assert sensor_one_states[0].last_updated == past_2038_time

View File

@ -21,7 +21,13 @@ from homeassistant.core import State
from homeassistant.helpers.json import JSONEncoder from homeassistant.helpers.json import JSONEncoder
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .common import wait_recording_done from .common import (
assert_dict_of_states_equal_without_context_and_last_changed,
assert_multiple_states_equal_without_context,
assert_multiple_states_equal_without_context_and_last_changed,
assert_states_equal_without_context,
wait_recording_done,
)
CREATE_ENGINE_TARGET = "homeassistant.components.recorder.core.create_engine" CREATE_ENGINE_TARGET = "homeassistant.components.recorder.core.create_engine"
SCHEMA_MODULE = "tests.components.recorder.db_schema_30" SCHEMA_MODULE = "tests.components.recorder.db_schema_30"
@ -175,7 +181,7 @@ def test_state_changes_during_period(hass_recorder, attributes, no_attributes, l
hass, start, end, entity_id, no_attributes, limit=limit hass, start, end, entity_id, no_attributes, limit=limit
) )
assert states[:limit] == hist[entity_id] assert_multiple_states_equal_without_context(states[:limit], hist[entity_id])
def test_state_changes_during_period_descending(hass_recorder): def test_state_changes_during_period_descending(hass_recorder):
@ -228,12 +234,14 @@ def test_state_changes_during_period_descending(hass_recorder):
hist = history.state_changes_during_period( hist = history.state_changes_during_period(
hass, start, end, entity_id, no_attributes=False, descending=False hass, start, end, entity_id, no_attributes=False, descending=False
) )
assert states == hist[entity_id] assert_multiple_states_equal_without_context(states, hist[entity_id])
hist = history.state_changes_during_period( hist = history.state_changes_during_period(
hass, start, end, entity_id, no_attributes=False, descending=True hass, start, end, entity_id, no_attributes=False, descending=True
) )
assert states == list(reversed(list(hist[entity_id]))) assert_multiple_states_equal_without_context(
states, list(reversed(list(hist[entity_id])))
)
def test_get_last_state_changes(hass_recorder): def test_get_last_state_changes(hass_recorder):
@ -269,7 +277,7 @@ def test_get_last_state_changes(hass_recorder):
hist = history.get_last_state_changes(hass, 2, entity_id) hist = history.get_last_state_changes(hass, 2, entity_id)
assert states == hist[entity_id] assert_multiple_states_equal_without_context(states, hist[entity_id])
def test_ensure_state_can_be_copied(hass_recorder): def test_ensure_state_can_be_copied(hass_recorder):
@ -302,8 +310,8 @@ def test_ensure_state_can_be_copied(hass_recorder):
hist = history.get_last_state_changes(hass, 2, entity_id) hist = history.get_last_state_changes(hass, 2, entity_id)
assert copy(hist[entity_id][0]) == hist[entity_id][0] assert_states_equal_without_context(copy(hist[entity_id][0]), hist[entity_id][0])
assert copy(hist[entity_id][1]) == hist[entity_id][1] assert_states_equal_without_context(copy(hist[entity_id][1]), hist[entity_id][1])
def test_get_significant_states(hass_recorder): def test_get_significant_states(hass_recorder):
@ -316,7 +324,7 @@ def test_get_significant_states(hass_recorder):
hass = hass_recorder() hass = hass_recorder()
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_minimal_response(hass_recorder): def test_get_significant_states_minimal_response(hass_recorder):
@ -355,7 +363,31 @@ def test_get_significant_states_minimal_response(hass_recorder):
"last_changed": orig_last_changed, "last_changed": orig_last_changed,
"state": orig_state, "state": orig_state,
} }
assert states == hist
assert len(hist) == len(states)
assert_states_equal_without_context(
states["media_player.test"][0], hist["media_player.test"][0]
)
assert states["media_player.test"][1] == hist["media_player.test"][1]
assert states["media_player.test"][2] == hist["media_player.test"][2]
assert_multiple_states_equal_without_context(
states["media_player.test2"], hist["media_player.test2"]
)
assert_states_equal_without_context(
states["media_player.test3"][0], hist["media_player.test3"][0]
)
assert states["media_player.test3"][1] == hist["media_player.test3"][1]
assert_multiple_states_equal_without_context(
states["script.can_cancel_this_one"], hist["script.can_cancel_this_one"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test2"], hist["thermostat.test2"]
)
def test_get_significant_states_with_initial(hass_recorder): def test_get_significant_states_with_initial(hass_recorder):
@ -375,6 +407,7 @@ def test_get_significant_states_with_initial(hass_recorder):
for state in states[entity_id]: for state in states[entity_id]:
if state.last_changed == one: if state.last_changed == one:
state.last_changed = one_and_half state.last_changed = one_and_half
state.last_updated = one_and_half
hist = history.get_significant_states( hist = history.get_significant_states(
hass, hass,
@ -382,7 +415,7 @@ def test_get_significant_states_with_initial(hass_recorder):
four, four,
include_start_time_state=True, include_start_time_state=True,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_without_initial(hass_recorder): def test_get_significant_states_without_initial(hass_recorder):
@ -408,7 +441,7 @@ def test_get_significant_states_without_initial(hass_recorder):
four, four,
include_start_time_state=False, include_start_time_state=False,
) )
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_entity_id(hass_recorder): def test_get_significant_states_entity_id(hass_recorder):
@ -422,7 +455,7 @@ def test_get_significant_states_entity_id(hass_recorder):
del states["script.can_cancel_this_one"] del states["script.can_cancel_this_one"]
hist = history.get_significant_states(hass, zero, four, ["media_player.test"]) hist = history.get_significant_states(hass, zero, four, ["media_player.test"])
assert states == hist assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
def test_get_significant_states_multiple_entity_ids(hass_recorder): def test_get_significant_states_multiple_entity_ids(hass_recorder):
@ -440,7 +473,12 @@ def test_get_significant_states_multiple_entity_ids(hass_recorder):
four, four,
["media_player.test", "thermostat.test"], ["media_player.test", "thermostat.test"],
) )
assert states == hist assert_multiple_states_equal_without_context_and_last_changed(
states["media_player.test"], hist["media_player.test"]
)
assert_multiple_states_equal_without_context_and_last_changed(
states["thermostat.test"], hist["thermostat.test"]
)
def test_get_significant_states_are_ordered(hass_recorder): def test_get_significant_states_are_ordered(hass_recorder):
@ -505,14 +543,22 @@ def test_get_significant_states_only(hass_recorder):
hist = history.get_significant_states(hass, start, significant_changes_only=True) hist = history.get_significant_states(hass, start, significant_changes_only=True)
assert len(hist[entity_id]) == 2 assert len(hist[entity_id]) == 2
assert states[0] not in hist[entity_id] assert not any(
assert states[1] in hist[entity_id] state.last_updated == states[0].last_updated for state in hist[entity_id]
assert states[2] in hist[entity_id] )
assert any(
state.last_updated == states[1].last_updated for state in hist[entity_id]
)
assert any(
state.last_updated == states[2].last_updated for state in hist[entity_id]
)
hist = history.get_significant_states(hass, start, significant_changes_only=False) hist = history.get_significant_states(hass, start, significant_changes_only=False)
assert len(hist[entity_id]) == 3 assert len(hist[entity_id]) == 3
assert states == hist[entity_id] assert_multiple_states_equal_without_context_and_last_changed(
states, hist[entity_id]
)
def record_states(hass) -> tuple[datetime, datetime, dict[str, list[State]]]: def record_states(hass) -> tuple[datetime, datetime, dict[str, list[State]]]:

View File

@ -221,7 +221,7 @@ async def test_saving_state(recorder_mock, hass: HomeAssistant):
assert len(db_states) == 1 assert len(db_states) == 1
assert db_states[0].event_id is None assert db_states[0].event_id is None
assert state == _state_with_context(hass, entity_id) assert state.as_dict() == _state_with_context(hass, entity_id).as_dict()
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -257,7 +257,7 @@ async def test_saving_state_with_nul(
expected = _state_with_context(hass, entity_id) expected = _state_with_context(hass, entity_id)
expected.attributes = expected_attributes expected.attributes = expected_attributes
assert state == expected assert state.as_dict() == expected.as_dict()
async def test_saving_many_states( async def test_saving_many_states(
@ -547,7 +547,7 @@ def test_saving_state_include_domains(hass_recorder):
hass = hass_recorder({"include": {"domains": "test2"}}) hass = hass_recorder({"include": {"domains": "test2"}})
states = _add_entities(hass, ["test.recorder", "test2.recorder"]) states = _add_entities(hass, ["test.recorder", "test2.recorder"])
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
def test_saving_state_include_domains_globs(hass_recorder): def test_saving_state_include_domains_globs(hass_recorder):
@ -559,8 +559,11 @@ def test_saving_state_include_domains_globs(hass_recorder):
hass, ["test.recorder", "test2.recorder", "test3.included_entity"] hass, ["test.recorder", "test2.recorder", "test3.included_entity"]
) )
assert len(states) == 2 assert len(states) == 2
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
assert _state_with_context(hass, "test3.included_entity") == states[1] assert (
_state_with_context(hass, "test3.included_entity").as_dict()
== states[1].as_dict()
)
def test_saving_state_incl_entities(hass_recorder): def test_saving_state_incl_entities(hass_recorder):
@ -568,7 +571,7 @@ def test_saving_state_incl_entities(hass_recorder):
hass = hass_recorder({"include": {"entities": "test2.recorder"}}) hass = hass_recorder({"include": {"entities": "test2.recorder"}})
states = _add_entities(hass, ["test.recorder", "test2.recorder"]) states = _add_entities(hass, ["test.recorder", "test2.recorder"])
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
def test_saving_event_exclude_event_type(hass_recorder): def test_saving_event_exclude_event_type(hass_recorder):
@ -597,7 +600,7 @@ def test_saving_state_exclude_domains(hass_recorder):
hass = hass_recorder({"exclude": {"domains": "test"}}) hass = hass_recorder({"exclude": {"domains": "test"}})
states = _add_entities(hass, ["test.recorder", "test2.recorder"]) states = _add_entities(hass, ["test.recorder", "test2.recorder"])
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
def test_saving_state_exclude_domains_globs(hass_recorder): def test_saving_state_exclude_domains_globs(hass_recorder):
@ -609,7 +612,7 @@ def test_saving_state_exclude_domains_globs(hass_recorder):
hass, ["test.recorder", "test2.recorder", "test2.excluded_entity"] hass, ["test.recorder", "test2.recorder", "test2.excluded_entity"]
) )
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
def test_saving_state_exclude_entities(hass_recorder): def test_saving_state_exclude_entities(hass_recorder):
@ -617,7 +620,7 @@ def test_saving_state_exclude_entities(hass_recorder):
hass = hass_recorder({"exclude": {"entities": "test.recorder"}}) hass = hass_recorder({"exclude": {"entities": "test.recorder"}})
states = _add_entities(hass, ["test.recorder", "test2.recorder"]) states = _add_entities(hass, ["test.recorder", "test2.recorder"])
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test2.recorder") == states[0] assert _state_with_context(hass, "test2.recorder").as_dict() == states[0].as_dict()
def test_saving_state_exclude_domain_include_entity(hass_recorder): def test_saving_state_exclude_domain_include_entity(hass_recorder):
@ -650,7 +653,7 @@ def test_saving_state_include_domain_exclude_entity(hass_recorder):
) )
states = _add_entities(hass, ["test.recorder", "test2.recorder", "test.ok"]) states = _add_entities(hass, ["test.recorder", "test2.recorder", "test.ok"])
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test.ok") == states[0] assert _state_with_context(hass, "test.ok").as_dict() == states[0].as_dict()
assert _state_with_context(hass, "test.ok").state == "state2" assert _state_with_context(hass, "test.ok").state == "state2"
@ -666,7 +669,7 @@ def test_saving_state_include_domain_glob_exclude_entity(hass_recorder):
hass, ["test.recorder", "test2.recorder", "test.ok", "test2.included_entity"] hass, ["test.recorder", "test2.recorder", "test.ok", "test2.included_entity"]
) )
assert len(states) == 1 assert len(states) == 1
assert _state_with_context(hass, "test.ok") == states[0] assert _state_with_context(hass, "test.ok").as_dict() == states[0].as_dict()
assert _state_with_context(hass, "test.ok").state == "state2" assert _state_with_context(hass, "test.ok").state == "state2"
@ -1314,7 +1317,10 @@ def test_service_disable_states_not_recording(hass, hass_recorder):
db_states = list(session.query(States)) db_states = list(session.query(States))
assert len(db_states) == 1 assert len(db_states) == 1
assert db_states[0].event_id is None assert db_states[0].event_id is None
assert db_states[0].to_native() == _state_with_context(hass, "test.two") assert (
db_states[0].to_native().as_dict()
== _state_with_context(hass, "test.two").as_dict()
)
def test_service_disable_run_information_recorded(tmpdir): def test_service_disable_run_information_recorded(tmpdir):

View File

@ -32,7 +32,7 @@ def test_from_event_to_db_event():
event = ha.Event("test_event", {"some_data": 15}) event = ha.Event("test_event", {"some_data": 15})
db_event = Events.from_event(event) db_event = Events.from_event(event)
db_event.event_data = EventData.from_event(event).shared_data db_event.event_data = EventData.from_event(event).shared_data
assert event == db_event.to_native() assert event.as_dict() == db_event.to_native().as_dict()
def test_from_event_to_db_state(): def test_from_event_to_db_state():
@ -43,7 +43,7 @@ def test_from_event_to_db_state():
{"entity_id": "sensor.temperature", "old_state": None, "new_state": state}, {"entity_id": "sensor.temperature", "old_state": None, "new_state": state},
context=state.context, context=state.context,
) )
assert state == States.from_event(event).to_native() assert state.as_dict() == States.from_event(event).to_native().as_dict()
def test_from_event_to_db_state_attributes(): def test_from_event_to_db_state_attributes():
@ -293,11 +293,11 @@ async def test_event_to_db_model():
db_event = Events.from_event(event) db_event = Events.from_event(event)
db_event.event_data = EventData.from_event(event).shared_data db_event.event_data = EventData.from_event(event).shared_data
native = db_event.to_native() native = db_event.to_native()
assert native == event assert native.as_dict() == event.as_dict()
native = Events.from_event(event).to_native() native = Events.from_event(event).to_native()
event.data = {} event.data = {}
assert native == event assert native.as_dict() == event.as_dict()
async def test_lazy_state_handles_include_json(caplog): async def test_lazy_state_handles_include_json(caplog):

View File

@ -37,6 +37,7 @@ from homeassistant.setup import setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from .common import ( from .common import (
assert_dict_of_states_equal_without_context_and_last_changed,
async_wait_recording_done, async_wait_recording_done,
do_adhoc_statistics, do_adhoc_statistics,
statistics_during_period, statistics_during_period,
@ -55,7 +56,7 @@ def test_compile_hourly_statistics(hass_recorder):
setup_component(hass, "sensor", {}) setup_component(hass, "sensor", {})
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
# Should not fail if there is nothing there yet # Should not fail if there is nothing there yet
stats = get_latest_short_term_statistics( stats = get_latest_short_term_statistics(
@ -316,7 +317,7 @@ def test_rename_entity(hass_recorder):
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}): for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}):
stats = statistics_during_period(hass, zero, period="5minute", **kwargs) stats = statistics_during_period(hass, zero, period="5minute", **kwargs)
@ -382,7 +383,7 @@ def test_rename_entity_collision(hass_recorder, caplog):
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}): for kwargs in ({}, {"statistic_ids": ["sensor.test1"]}):
stats = statistics_during_period(hass, zero, period="5minute", **kwargs) stats = statistics_during_period(hass, zero, period="5minute", **kwargs)
@ -447,7 +448,7 @@ def test_statistics_duplicated(hass_recorder, caplog):
setup_component(hass, "sensor", {}) setup_component(hass, "sensor", {})
zero, four, states = record_states(hass) zero, four, states = record_states(hass)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
wait_recording_done(hass) wait_recording_done(hass)
assert "Compiling statistics for" not in caplog.text assert "Compiling statistics for" not in caplog.text

View File

@ -1 +1,4 @@
"""The tests for Sensor platforms.""" """The tests for Sensor platforms."""
import pytest
pytest.register_assert_rewrite("tests.components.recorder.common")

View File

@ -34,6 +34,8 @@ from homeassistant.util.unit_system import METRIC_SYSTEM, US_CUSTOMARY_SYSTEM
from tests.common import async_fire_time_changed from tests.common import async_fire_time_changed
from tests.components.recorder.common import ( from tests.components.recorder.common import (
assert_dict_of_states_equal_without_context_and_last_changed,
assert_multiple_states_equal_without_context_and_last_changed,
async_recorder_block_till_done, async_recorder_block_till_done,
async_wait_recording_done, async_wait_recording_done,
do_adhoc_statistics, do_adhoc_statistics,
@ -139,7 +141,7 @@ def test_compile_hourly_statistics(
} }
four, states = record_states(hass, zero, "sensor.test1", attributes) four, states = record_states(hass, zero, "sensor.test1", attributes)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -201,7 +203,7 @@ def test_compile_hourly_statistics_purged_state_changes(
} }
four, states = record_states(hass, zero, "sensor.test1", attributes) four, states = record_states(hass, zero, "sensor.test1", attributes)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
mean = min = max = float(hist["sensor.test1"][-1].state) mean = min = max = float(hist["sensor.test1"][-1].state)
@ -282,7 +284,7 @@ def test_compile_hourly_statistics_wrong_unit(hass_recorder, caplog, attributes)
states = {**states, **_states} states = {**states, **_states}
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -474,7 +476,9 @@ async def test_compile_hourly_sum_statistics_amount(
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
await async_wait_recording_done(hass) await async_wait_recording_done(hass)
@ -667,7 +671,9 @@ def test_compile_hourly_sum_statistics_amount_reset_every_state_change(
two + timedelta.resolution, two + timedelta.resolution,
significant_changes_only=False, significant_changes_only=False,
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
do_adhoc_statistics(hass, start=zero + timedelta(minutes=5)) do_adhoc_statistics(hass, start=zero + timedelta(minutes=5))
@ -765,7 +771,9 @@ def test_compile_hourly_sum_statistics_amount_invalid_last_reset(
one + timedelta.resolution, one + timedelta.resolution,
significant_changes_only=False, significant_changes_only=False,
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -849,7 +857,9 @@ def test_compile_hourly_sum_statistics_nan_inf_state(
one + timedelta.resolution, one + timedelta.resolution,
significant_changes_only=False, significant_changes_only=False,
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -978,7 +988,9 @@ def test_compile_hourly_sum_statistics_negative_state(
one + timedelta.resolution, one + timedelta.resolution,
significant_changes_only=False, significant_changes_only=False,
) )
assert dict(states)[entity_id] == dict(hist)[entity_id] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)[entity_id], dict(hist)[entity_id]
)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -1060,7 +1072,9 @@ def test_compile_hourly_sum_statistics_total_no_reset(
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
wait_recording_done(hass) wait_recording_done(hass)
@ -1160,7 +1174,9 @@ def test_compile_hourly_sum_statistics_total_increasing(
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
wait_recording_done(hass) wait_recording_done(hass)
@ -1258,7 +1274,9 @@ def test_compile_hourly_sum_statistics_total_increasing_small_dip(
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
wait_recording_done(hass) wait_recording_done(hass)
@ -1363,7 +1381,9 @@ def test_compile_hourly_energy_statistics_unsupported(hass_recorder, caplog):
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
wait_recording_done(hass) wait_recording_done(hass)
@ -1453,7 +1473,9 @@ def test_compile_hourly_energy_statistics_multiple(hass_recorder, caplog):
hist = history.get_significant_states( hist = history.get_significant_states(
hass, period0 - timedelta.resolution, eight + timedelta.resolution hass, period0 - timedelta.resolution, eight + timedelta.resolution
) )
assert dict(states)["sensor.test1"] == dict(hist)["sensor.test1"] assert_multiple_states_equal_without_context_and_last_changed(
dict(states)["sensor.test1"], dict(hist)["sensor.test1"]
)
do_adhoc_statistics(hass, start=period0) do_adhoc_statistics(hass, start=period0)
wait_recording_done(hass) wait_recording_done(hass)
@ -1635,7 +1657,7 @@ def test_compile_hourly_statistics_unchanged(
} }
four, states = record_states(hass, zero, "sensor.test1", attributes) four, states = record_states(hass, zero, "sensor.test1", attributes)
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=four) do_adhoc_statistics(hass, start=four)
wait_recording_done(hass) wait_recording_done(hass)
@ -1667,7 +1689,7 @@ def test_compile_hourly_statistics_partially_unavailable(hass_recorder, caplog):
hass, zero, "sensor.test1", TEMPERATURE_SENSOR_ATTRIBUTES hass, zero, "sensor.test1", TEMPERATURE_SENSOR_ATTRIBUTES
) )
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -1736,7 +1758,7 @@ def test_compile_hourly_statistics_unavailable(
_, _states = record_states(hass, zero, "sensor.test2", attributes) _, _states = record_states(hass, zero, "sensor.test2", attributes)
states = {**states, **_states} states = {**states, **_states}
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=four) do_adhoc_statistics(hass, start=four)
wait_recording_done(hass) wait_recording_done(hass)
@ -1944,7 +1966,7 @@ def test_compile_hourly_statistics_changing_units_1(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -2054,7 +2076,7 @@ def test_compile_hourly_statistics_changing_units_2(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5)) do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5))
wait_recording_done(hass) wait_recording_done(hass)
@ -2122,7 +2144,7 @@ def test_compile_hourly_statistics_changing_units_3(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -2270,7 +2292,7 @@ def test_compile_hourly_statistics_convert_units_1(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10)) do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
wait_recording_done(hass) wait_recording_done(hass)
assert "The unit of sensor.test1 is changing" not in caplog.text assert "The unit of sensor.test1 is changing" not in caplog.text
@ -2362,7 +2384,7 @@ def test_compile_hourly_statistics_equivalent_units_1(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero) do_adhoc_statistics(hass, start=zero)
wait_recording_done(hass) wait_recording_done(hass)
@ -2476,7 +2498,7 @@ def test_compile_hourly_statistics_equivalent_units_2(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5)) do_adhoc_statistics(hass, start=zero + timedelta(seconds=30 * 5))
wait_recording_done(hass) wait_recording_done(hass)
@ -2591,7 +2613,7 @@ def test_compile_hourly_statistics_changing_device_class_1(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
# Run statistics again, additional statistics is generated # Run statistics again, additional statistics is generated
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10)) do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
@ -2646,7 +2668,7 @@ def test_compile_hourly_statistics_changing_device_class_1(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
# Run statistics again, additional statistics is generated # Run statistics again, additional statistics is generated
do_adhoc_statistics(hass, start=zero + timedelta(minutes=20)) do_adhoc_statistics(hass, start=zero + timedelta(minutes=20))
@ -2781,7 +2803,7 @@ def test_compile_hourly_statistics_changing_device_class_2(
) )
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, zero, four) hist = history.get_significant_states(hass, zero, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
# Run statistics again, additional statistics is generated # Run statistics again, additional statistics is generated
do_adhoc_statistics(hass, start=zero + timedelta(minutes=10)) do_adhoc_statistics(hass, start=zero + timedelta(minutes=10))
@ -2897,7 +2919,7 @@ def test_compile_hourly_statistics_changing_state_class(
four, _states = record_states(hass, period1, "sensor.test1", attributes_2) four, _states = record_states(hass, period1, "sensor.test1", attributes_2)
states["sensor.test1"] += _states["sensor.test1"] states["sensor.test1"] += _states["sensor.test1"]
hist = history.get_significant_states(hass, period0, four) hist = history.get_significant_states(hass, period0, four)
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
do_adhoc_statistics(hass, start=period1) do_adhoc_statistics(hass, start=period1)
wait_recording_done(hass) wait_recording_done(hass)
@ -3083,7 +3105,7 @@ def test_compile_statistics_hourly_daily_monthly_summary(hass_recorder, caplog):
hist = history.get_significant_states( hist = history.get_significant_states(
hass, zero - timedelta.resolution, four, significant_changes_only=False hass, zero - timedelta.resolution, four, significant_changes_only=False
) )
assert dict(states) == dict(hist) assert_dict_of_states_equal_without_context_and_last_changed(states, hist)
wait_recording_done(hass) wait_recording_done(hass)
# Generate 5-minute statistics for two hours # Generate 5-minute statistics for two hours

View File

@ -331,7 +331,7 @@ def test_event_eq():
ha.Event("some_type", data, time_fired=now, context=context) for _ in range(2) ha.Event("some_type", data, time_fired=now, context=context) for _ in range(2)
) )
assert event1 == event2 assert event1.as_dict() == event2.as_dict()
def test_event_repr(): def test_event_repr():
@ -685,7 +685,7 @@ def test_state_name_if_friendly_name_attr():
def test_state_dict_conversion(): def test_state_dict_conversion():
"""Test conversion of dict.""" """Test conversion of dict."""
state = ha.State("domain.hello", "world", {"some": "attr"}) state = ha.State("domain.hello", "world", {"some": "attr"})
assert state == ha.State.from_dict(state.as_dict()) assert state.as_dict() == ha.State.from_dict(state.as_dict()).as_dict()
def test_state_dict_conversion_with_wrong_data(): def test_state_dict_conversion_with_wrong_data():