diff --git a/homeassistant/components/configurator.py b/homeassistant/components/configurator.py index 6fb584635f9..591cdc0dc61 100644 --- a/homeassistant/components/configurator.py +++ b/homeassistant/components/configurator.py @@ -141,7 +141,7 @@ class Configurator(object): state = self.hass.states.get(entity_id) - new_data = state.attributes + new_data = dict(state.attributes) new_data[ATTR_ERRORS] = error self.hass.states.set(entity_id, STATE_CONFIGURE, new_data) diff --git a/homeassistant/components/recorder.py b/homeassistant/components/recorder.py index 98077a26aae..5476d082b38 100644 --- a/homeassistant/components/recorder.py +++ b/homeassistant/components/recorder.py @@ -232,7 +232,7 @@ class Recorder(threading.Thread): else: state_domain = state.domain state_state = state.state - state_attr = json.dumps(state.attributes) + state_attr = json.dumps(dict(state.attributes)) last_changed = state.last_changed last_updated = state.last_updated diff --git a/homeassistant/core.py b/homeassistant/core.py index b9bf49f261c..c4715a7cd9f 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -10,6 +10,7 @@ import time import logging import signal import threading +from types import MappingProxyType import enum import functools as ft from collections import namedtuple @@ -353,7 +354,7 @@ class State(object): self.entity_id = entity_id.lower() self.state = state - self.attributes = attributes or {} + self.attributes = MappingProxyType(attributes or {}) self.last_updated = dt_util.strip_microseconds( last_updated or dt_util.utcnow()) @@ -381,12 +382,6 @@ class State(object): self.attributes.get(ATTR_FRIENDLY_NAME) or self.object_id.replace('_', ' ')) - def copy(self): - """Return a copy of the state.""" - return State(self.entity_id, self.state, - dict(self.attributes), self.last_changed, - self.last_updated) - def as_dict(self): """Return a dict representation of the State. @@ -395,7 +390,7 @@ class State(object): """ return {'entity_id': self.entity_id, 'state': self.state, - 'attributes': self.attributes, + 'attributes': dict(self.attributes), 'last_changed': dt_util.datetime_to_str(self.last_changed), 'last_updated': dt_util.datetime_to_str(self.last_updated)} @@ -459,14 +454,11 @@ class StateMachine(object): def all(self): """Create a list of all states.""" with self._lock: - return [state.copy() for state in self._states.values()] + return list(self._states.values()) def get(self, entity_id): """Retrieve state of entity_id or None if not found.""" - state = self._states.get(entity_id.lower()) - - # Make a copy so people won't mutate the state - return state.copy() if state else None + return self._states.get(entity_id.lower()) def is_state(self, entity_id, state): """Test if entity exists and is specified state.""" diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index c8f6f05661a..9c74d59844e 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -85,7 +85,7 @@ def reproduce_state(hass, states, blocking=False): # We group service calls for entities by service call # json used to create a hashable version of dict with maybe lists in it key = (service_domain, service, - json.dumps(state.attributes, sort_keys=True)) + json.dumps(dict(state.attributes), sort_keys=True)) to_call[key].append(state.entity_id) for (service_domain, service, service_data), entity_ids in to_call.items(): diff --git a/homeassistant/util/__init__.py b/homeassistant/util/__init__.py index e177606fb62..89b2ab0e1f3 100644 --- a/homeassistant/util/__init__.py +++ b/homeassistant/util/__init__.py @@ -15,6 +15,7 @@ import socket import random import string from functools import wraps +from types import MappingProxyType from .dt import datetime_to_local_str, utcnow @@ -42,7 +43,7 @@ def slugify(text): def repr_helper(inp): """ Helps creating a more readable string representation of objects. """ - if isinstance(inp, dict): + if isinstance(inp, (dict, MappingProxyType)): return ", ".join( repr_helper(key)+"="+repr_helper(item) for key, item in inp.items()) diff --git a/tests/test_core.py b/tests/test_core.py index 4a0096809c8..5525cbae2ee 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -267,18 +267,6 @@ class TestState(unittest.TestCase): {ATTR_FRIENDLY_NAME: name}) self.assertEqual(name, state.name) - def test_copy(self): - state = ha.State('domain.hello', 'world', {'some': 'attr'}) - # Patch dt_util.utcnow() so we know last_updated got copied too - with patch('homeassistant.core.dt_util.utcnow', - return_value=dt_util.utcnow() + timedelta(seconds=10)): - copy = state.copy() - self.assertEqual(state.entity_id, copy.entity_id) - self.assertEqual(state.state, copy.state) - self.assertEqual(state.attributes, copy.attributes) - self.assertEqual(state.last_changed, copy.last_changed) - self.assertEqual(state.last_updated, copy.last_updated) - def test_dict_conversion(self): state = ha.State('domain.hello', 'world', {'some': 'attr'}) self.assertEqual(state, ha.State.from_dict(state.as_dict()))