mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 01:38:02 +00:00
Improve trace of template conditions (#49101)
* Improve trace of template conditions * Refactor * Fix wait_template trace * Update tests
This commit is contained in:
parent
106dc4d28a
commit
ff5fbea1fb
@ -96,6 +96,18 @@ def condition_trace_set_result(result: bool, **kwargs: Any) -> None:
|
||||
node.set_result(result=result, **kwargs)
|
||||
|
||||
|
||||
def condition_trace_update_result(result: bool, **kwargs: Any) -> None:
|
||||
"""Update the result of TraceElement at the top of the stack."""
|
||||
node = trace_stack_top(trace_stack_cv)
|
||||
|
||||
# The condition function may be called directly, in which case tracing
|
||||
# is not setup
|
||||
if not node:
|
||||
return
|
||||
|
||||
node.update_result(result=result, **kwargs)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def trace_condition(variables: TemplateVarsType) -> Generator:
|
||||
"""Trace condition evaluation."""
|
||||
@ -118,7 +130,7 @@ def trace_condition_function(condition: ConditionCheckerType) -> ConditionChecke
|
||||
"""Trace condition."""
|
||||
with trace_condition(variables):
|
||||
result = condition(hass, variables)
|
||||
condition_trace_set_result(result)
|
||||
condition_trace_update_result(result)
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
@ -644,15 +656,22 @@ def template(
|
||||
|
||||
|
||||
def async_template(
|
||||
hass: HomeAssistant, value_template: Template, variables: TemplateVarsType = None
|
||||
hass: HomeAssistant,
|
||||
value_template: Template,
|
||||
variables: TemplateVarsType = None,
|
||||
trace_result: bool = True,
|
||||
) -> bool:
|
||||
"""Test if template condition matches."""
|
||||
try:
|
||||
value: str = value_template.async_render(variables, parse_result=False)
|
||||
info = value_template.async_render_to_info(variables, parse_result=False)
|
||||
value = info.result()
|
||||
except TemplateError as ex:
|
||||
raise ConditionErrorMessage("template", str(ex)) from ex
|
||||
|
||||
return value.lower() == "true"
|
||||
result = value.lower() == "true"
|
||||
if trace_result:
|
||||
condition_trace_set_result(result, entities=list(info.entities))
|
||||
return result
|
||||
|
||||
|
||||
def async_template_from_config(
|
||||
|
@ -456,7 +456,7 @@ class _ScriptRun:
|
||||
wait_template.hass = self._hass
|
||||
|
||||
# check if condition already okay
|
||||
if condition.async_template(self._hass, wait_template, self._variables):
|
||||
if condition.async_template(self._hass, wait_template, self._variables, False):
|
||||
self._variables["wait"]["completed"] = True
|
||||
return
|
||||
|
||||
|
@ -51,6 +51,11 @@ class TraceElement:
|
||||
"""Set result."""
|
||||
self._result = {**kwargs}
|
||||
|
||||
def update_result(self, **kwargs: Any) -> None:
|
||||
"""Set result."""
|
||||
old_result = self._result or {}
|
||||
self._result = {**old_result, **kwargs}
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
"""Return dictionary version of this TraceElement."""
|
||||
result: dict[str, Any] = {"path": self.path, "timestamp": self._timestamp}
|
||||
|
@ -223,7 +223,8 @@ async def test_get_trace(
|
||||
assert len(trace["trace"].get("condition/0", [])) == len(condition_results)
|
||||
for idx, condition_result in enumerate(condition_results):
|
||||
assert trace["trace"]["condition/0"][idx]["result"] == {
|
||||
"result": condition_result
|
||||
"result": condition_result,
|
||||
"entities": [],
|
||||
}
|
||||
contexts[trace["context"]["id"]] = {
|
||||
"run_id": trace["run_id"],
|
||||
@ -261,7 +262,10 @@ async def test_get_trace(
|
||||
trace = response["result"]
|
||||
assert set(trace["trace"]) == extra_trace_keys[2]
|
||||
assert len(trace["trace"]["condition/0"]) == 1
|
||||
assert trace["trace"]["condition/0"][0]["result"] == {"result": False}
|
||||
assert trace["trace"]["condition/0"][0]["result"] == {
|
||||
"result": False,
|
||||
"entities": [],
|
||||
}
|
||||
assert trace["config"] == moon_config
|
||||
assert trace["context"]
|
||||
assert "error" not in trace
|
||||
@ -303,7 +307,10 @@ async def test_get_trace(
|
||||
assert "error" not in trace["trace"][f"{prefix}/0"][0]
|
||||
assert trace["trace"][f"{prefix}/0"][0]["result"] == moon_action
|
||||
assert len(trace["trace"]["condition/0"]) == 1
|
||||
assert trace["trace"]["condition/0"][0]["result"] == {"result": True}
|
||||
assert trace["trace"]["condition/0"][0]["result"] == {
|
||||
"result": True,
|
||||
"entities": [],
|
||||
}
|
||||
assert trace["config"] == moon_config
|
||||
assert trace["context"]
|
||||
assert "error" not in trace
|
||||
|
@ -237,6 +237,14 @@ async def test_and_condition_with_template(hass):
|
||||
|
||||
hass.states.async_set("sensor.temperature", 120)
|
||||
assert not test(hass)
|
||||
assert_condition_trace(
|
||||
{
|
||||
"": [{"result": {"result": False}}],
|
||||
"conditions/0": [
|
||||
{"result": {"entities": ["sensor.temperature"], "result": False}}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
hass.states.async_set("sensor.temperature", 105)
|
||||
assert not test(hass)
|
||||
|
@ -1449,7 +1449,7 @@ async def test_condition_basic(hass, caplog):
|
||||
{
|
||||
"0": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||
"1": [{"result": {"result": True}}],
|
||||
"1/condition": [{"result": {"result": True}}],
|
||||
"1/condition": [{"result": {"entities": ["test.entity"], "result": True}}],
|
||||
"2": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||
}
|
||||
)
|
||||
@ -1466,7 +1466,7 @@ async def test_condition_basic(hass, caplog):
|
||||
{
|
||||
"0": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||
"1": [{"error_type": script._StopScript, "result": {"result": False}}],
|
||||
"1/condition": [{"result": {"result": False}}],
|
||||
"1/condition": [{"result": {"entities": ["test.entity"], "result": False}}],
|
||||
},
|
||||
expected_script_execution="aborted",
|
||||
)
|
||||
@ -1764,9 +1764,9 @@ async def test_repeat_var_in_condition(hass, condition):
|
||||
},
|
||||
],
|
||||
"0/repeat/while/0": [
|
||||
{"result": {"result": True}},
|
||||
{"result": {"result": True}},
|
||||
{"result": {"result": False}},
|
||||
{"result": {"entities": [], "result": True}},
|
||||
{"result": {"entities": [], "result": True}},
|
||||
{"result": {"entities": [], "result": False}},
|
||||
],
|
||||
"0/repeat/sequence/0": [
|
||||
{"result": {"event": "test_event", "event_data": {}}}
|
||||
@ -1797,8 +1797,8 @@ async def test_repeat_var_in_condition(hass, condition):
|
||||
},
|
||||
],
|
||||
"0/repeat/until/0": [
|
||||
{"result": {"result": False}},
|
||||
{"result": {"result": True}},
|
||||
{"result": {"entities": [], "result": False}},
|
||||
{"result": {"entities": [], "result": True}},
|
||||
],
|
||||
}
|
||||
assert_action_trace(expected_trace)
|
||||
@ -2058,10 +2058,14 @@ async def test_choose(hass, caplog, var, result):
|
||||
expected_trace = {"0": [{"result": {"choice": expected_choice}}]}
|
||||
if var >= 1:
|
||||
expected_trace["0/choose/0"] = [{"result": {"result": var == 1}}]
|
||||
expected_trace["0/choose/0/conditions/0"] = [{"result": {"result": var == 1}}]
|
||||
expected_trace["0/choose/0/conditions/0"] = [
|
||||
{"result": {"entities": [], "result": var == 1}}
|
||||
]
|
||||
if var >= 2:
|
||||
expected_trace["0/choose/1"] = [{"result": {"result": var == 2}}]
|
||||
expected_trace["0/choose/1/conditions/0"] = [{"result": {"result": var == 2}}]
|
||||
expected_trace["0/choose/1/conditions/0"] = [
|
||||
{"result": {"entities": [], "result": var == 2}}
|
||||
]
|
||||
if var == 1:
|
||||
expected_trace["0/choose/0/sequence/0"] = [
|
||||
{"result": {"event": "test_event", "event_data": {"choice": "first"}}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user