Skip to content

Commit d6798af

Browse files
authored
Handle script referenced entity extraction errors (#1305)
1 parent 65d4170 commit d6798af

2 files changed

Lines changed: 72 additions & 1 deletion

File tree

custom_components/spook/ectoplasms/script/repairs/unknown_entity_references.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ def extract_entities_from_trigger_config(config: dict[str, Any] | list) -> set[s
5151
return entities
5252

5353

54+
def extract_referenced_entities_from_script(entity: script.ScriptEntity) -> set[str]:
55+
"""Return entity references from a script entity."""
56+
try:
57+
return set(entity.script.referenced_entities)
58+
except TypeError as err:
59+
if str(err) != "unhashable type: 'dict'":
60+
raise
61+
return set()
62+
63+
5464
async def extract_template_entities_from_script_entity(
5565
hass: HomeAssistant, entity: Any
5666
) -> set[str]:
@@ -135,7 +145,7 @@ async def async_inspect(self) -> None:
135145
continue
136146

137147
# Get all referenced entities from the script
138-
all_entities = set(entity.script.referenced_entities)
148+
all_entities = extract_referenced_entities_from_script(entity)
139149

140150
# Check for blueprint trigger inputs
141151
blueprint_entities = self._get_blueprint_trigger_entities(entity)

tests/ectoplasms/script/repairs/test_unknown_entity_references.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from custom_components.spook.ectoplasms.script.repairs.unknown_entity_references import (
1010
extract_entities_from_trigger_config,
11+
extract_referenced_entities_from_script,
1112
)
1213

1314

@@ -95,3 +96,63 @@ def test_trigger_blueprint_input_shape() -> None:
9596
"light.a",
9697
"light.b",
9798
}
99+
100+
101+
class MockScript: # pylint: disable=too-few-public-methods
102+
"""Mock script object."""
103+
104+
def __init__(self, referenced_entities: set[str]) -> None:
105+
"""Initialize the mock script."""
106+
self.referenced_entities = referenced_entities
107+
108+
109+
class MockBrokenScript: # pylint: disable=too-few-public-methods
110+
"""Mock script object with broken referenced entity extraction."""
111+
112+
@property
113+
def referenced_entities(self) -> set[str]:
114+
"""Raise the same error Home Assistant can raise for dict entity IDs."""
115+
msg = "unhashable type: 'dict'"
116+
raise TypeError(msg)
117+
118+
119+
class MockUnexpectedBrokenScript: # pylint: disable=too-few-public-methods
120+
"""Mock script object with an unrelated TypeError."""
121+
122+
@property
123+
def referenced_entities(self) -> set[str]:
124+
"""Raise an unexpected TypeError."""
125+
msg = "unexpected failure"
126+
raise TypeError(msg)
127+
128+
129+
class MockScriptEntity: # pylint: disable=too-few-public-methods
130+
"""Mock script entity."""
131+
132+
def __init__(
133+
self, script: MockScript | MockBrokenScript | MockUnexpectedBrokenScript
134+
) -> None:
135+
"""Initialize the mock script entity."""
136+
self.script = script
137+
138+
139+
def test_extract_referenced_entities_from_script() -> None:
140+
"""Test script referenced entities are returned as a set."""
141+
entity = MockScriptEntity(MockScript({"light.kitchen"}))
142+
143+
assert extract_referenced_entities_from_script(entity) == {"light.kitchen"}
144+
145+
146+
def test_extract_referenced_entities_handles_home_assistant_type_error() -> None:
147+
"""Test broken Home Assistant referenced entity extraction is ignored."""
148+
entity = MockScriptEntity(MockBrokenScript())
149+
150+
assert extract_referenced_entities_from_script(entity) == set()
151+
152+
153+
def test_extract_referenced_entities_reraises_unexpected_type_error() -> None:
154+
"""Test unrelated TypeErrors are not swallowed."""
155+
entity = MockScriptEntity(MockUnexpectedBrokenScript())
156+
157+
with pytest.raises(TypeError, match="unexpected failure"):
158+
extract_referenced_entities_from_script(entity)

0 commit comments

Comments
 (0)