From f4528d0db288e7b908ae9ec685e12c19e63d93ee Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 24 Jun 2020 22:43:08 -0500 Subject: [PATCH] Ensure history states can be copied (#37081) The filter integration makes a copy of a state object obtained from history. --- homeassistant/components/history/__init__.py | 14 ++++++-- tests/components/history/test_init.py | 34 ++++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/history/__init__.py b/homeassistant/components/history/__init__.py index 9b81ffa08ed..f943c126d3e 100644 --- a/homeassistant/components/history/__init__.py +++ b/homeassistant/components/history/__init__.py @@ -616,7 +616,7 @@ class LazyState(State): self._last_updated = None self._context = None - @property + @property # type: ignore def attributes(self): """State attributes.""" if not self._attributes: @@ -628,13 +628,23 @@ class LazyState(State): self._attributes = {} return self._attributes - @property + @attributes.setter + def attributes(self, value): + """Set attributes.""" + self._attributes = value + + @property # type: ignore def context(self): """State context.""" if not self._context: self._context = Context(id=None) return self._context + @context.setter + def context(self, value): + """Set context.""" + self._context = value + @property # type: ignore def last_changed(self): """Last changed datetime.""" diff --git a/tests/components/history/test_init.py b/tests/components/history/test_init.py index 89e16ad0205..34b22481400 100644 --- a/tests/components/history/test_init.py +++ b/tests/components/history/test_init.py @@ -1,5 +1,6 @@ """The tests the History component.""" # pylint: disable=protected-access,invalid-name +from copy import copy from datetime import timedelta import json import unittest @@ -188,6 +189,39 @@ class TestComponentHistory(unittest.TestCase): assert states == hist[entity_id] + def test_ensure_state_can_be_copied(self): + """Ensure a state can pass though copy(). + + The filter integration uses copy() on states + from history. + """ + self.init_recorder() + entity_id = "sensor.test" + + def set_state(state): + """Set the state.""" + self.hass.states.set(entity_id, state) + wait_recording_done(self.hass) + return self.hass.states.get(entity_id) + + start = dt_util.utcnow() - timedelta(minutes=2) + point = start + timedelta(minutes=1) + + with patch( + "homeassistant.components.recorder.dt_util.utcnow", return_value=start + ): + set_state("1") + + with patch( + "homeassistant.components.recorder.dt_util.utcnow", return_value=point + ): + set_state("2") + + hist = history.get_last_state_changes(self.hass, 2, entity_id) + + assert copy(hist[entity_id][0]) == hist[entity_id][0] + assert copy(hist[entity_id][1]) == hist[entity_id][1] + def test_get_significant_states(self): """Test that only significant states are returned.