From f27066e77369d09563d24f835ee8e03c2267ffd6 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Tue, 9 Feb 2021 09:46:36 +0100 Subject: [PATCH] Raise ConditionError for state errors (#46244) --- .../components/bayesian/binary_sensor.py | 7 +++- homeassistant/helpers/condition.py | 15 ++++++-- tests/helpers/test_condition.py | 36 +++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/bayesian/binary_sensor.py b/homeassistant/components/bayesian/binary_sensor.py index 15176d45349..69553e921eb 100644 --- a/homeassistant/components/bayesian/binary_sensor.py +++ b/homeassistant/components/bayesian/binary_sensor.py @@ -356,7 +356,12 @@ class BayesianBinarySensor(BinarySensorEntity): """Return True if state conditions are met.""" entity = entity_observation["entity_id"] - return condition.state(self.hass, entity, entity_observation.get("to_state")) + try: + return condition.state( + self.hass, entity, entity_observation.get("to_state") + ) + except ConditionError: + return False @property def name(self): diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index e47374a9d17..126513608c7 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -314,11 +314,22 @@ def state( Async friendly. """ + if entity is None: + raise ConditionError("No entity specified") + if isinstance(entity, str): + entity_id = entity entity = hass.states.get(entity) - if entity is None or (attribute is not None and attribute not in entity.attributes): - return False + if entity is None: + raise ConditionError(f"Unknown entity {entity_id}") + else: + entity_id = entity.entity_id + + if attribute is not None and attribute not in entity.attributes: + raise ConditionError( + f"Attribute '{attribute}' (of entity {entity_id}) does not exist" + ) assert isinstance(entity, State) diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index cd4039f5262..485c51a8bb7 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -359,6 +359,37 @@ async def test_if_numeric_state_raises_on_unavailable(hass, caplog): assert len(caplog.record_tuples) == 0 +async def test_state_raises(hass): + """Test that state raises ConditionError on errors.""" + # Unknown entity_id + with pytest.raises(ConditionError, match="Unknown entity"): + test = await condition.async_from_config( + hass, + { + "condition": "state", + "entity_id": "sensor.door_unknown", + "state": "open", + }, + ) + + test(hass) + + # Unknown attribute + with pytest.raises(ConditionError, match=r"Attribute .* does not exist"): + test = await condition.async_from_config( + hass, + { + "condition": "state", + "entity_id": "sensor.door", + "attribute": "model", + "state": "acme", + }, + ) + + hass.states.async_set("sensor.door", "open") + test(hass) + + async def test_state_multiple_entities(hass): """Test with multiple entities in condition.""" test = await condition.async_from_config( @@ -466,7 +497,8 @@ async def test_state_attribute_boolean(hass): assert not test(hass) hass.states.async_set("sensor.temperature", 100, {"no_happening": 201}) - assert not test(hass) + with pytest.raises(ConditionError): + test(hass) hass.states.async_set("sensor.temperature", 100, {"happening": False}) assert test(hass) @@ -567,7 +599,7 @@ async def test_numeric_state_raises(hass): }, ) - assert test(hass) + test(hass) # Unknown attribute with pytest.raises(ConditionError, match=r"Attribute .* does not exist"):