mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 20:27:08 +00:00
Update TrackTemplateResultInfo to remove side effects from init (#38934)
* Verify and case * Review comments * Update homeassistant/helpers/event.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/helpers/event.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
66a5f24d4a
commit
472b12bef5
@ -28,7 +28,7 @@ from homeassistant.core import (
|
|||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
||||||
from homeassistant.helpers.sun import get_astral_event_next
|
from homeassistant.helpers.sun import get_astral_event_next
|
||||||
from homeassistant.helpers.template import Template, result_as_boolean
|
from homeassistant.helpers.template import RenderInfo, Template, result_as_boolean
|
||||||
from homeassistant.helpers.typing import TemplateVarsType
|
from homeassistant.helpers.typing import TemplateVarsType
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
@ -431,7 +431,7 @@ track_template = threaded_listener_factory(async_track_template)
|
|||||||
_UNCHANGED = object()
|
_UNCHANGED = object()
|
||||||
|
|
||||||
|
|
||||||
class TrackTemplateResultInfo:
|
class _TrackTemplateResultInfo:
|
||||||
"""Handle removal / refresh of tracker."""
|
"""Handle removal / refresh of tracker."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -451,7 +451,12 @@ class TrackTemplateResultInfo:
|
|||||||
self._all_listener: Optional[Callable] = None
|
self._all_listener: Optional[Callable] = None
|
||||||
self._domains_listener: Optional[Callable] = None
|
self._domains_listener: Optional[Callable] = None
|
||||||
self._entities_listener: Optional[Callable] = None
|
self._entities_listener: Optional[Callable] = None
|
||||||
self._info = template.async_render_to_info(variables)
|
self._info: Optional[RenderInfo] = None
|
||||||
|
self._last_info: Optional[RenderInfo] = None
|
||||||
|
|
||||||
|
def async_setup(self) -> None:
|
||||||
|
"""Activation of template tracking."""
|
||||||
|
self._info = self._template.async_render_to_info(self._variables)
|
||||||
if self._info.exception:
|
if self._info.exception:
|
||||||
self._last_exception = True
|
self._last_exception = True
|
||||||
_LOGGER.exception(self._info.exception)
|
_LOGGER.exception(self._info.exception)
|
||||||
@ -460,6 +465,8 @@ class TrackTemplateResultInfo:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _needs_all_listener(self) -> bool:
|
def _needs_all_listener(self) -> bool:
|
||||||
|
assert self._info
|
||||||
|
|
||||||
# Tracking all states
|
# Tracking all states
|
||||||
if self._info.all_states:
|
if self._info.all_states:
|
||||||
return True
|
return True
|
||||||
@ -480,6 +487,8 @@ class TrackTemplateResultInfo:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _create_listeners(self) -> None:
|
def _create_listeners(self) -> None:
|
||||||
|
assert self._info
|
||||||
|
|
||||||
if self._info.is_static:
|
if self._info.is_static:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -516,6 +525,9 @@ class TrackTemplateResultInfo:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_listeners(self) -> None:
|
def _update_listeners(self) -> None:
|
||||||
|
assert self._info
|
||||||
|
assert self._last_info
|
||||||
|
|
||||||
if self._needs_all_listener:
|
if self._needs_all_listener:
|
||||||
if self._all_listener:
|
if self._all_listener:
|
||||||
return
|
return
|
||||||
@ -544,6 +556,8 @@ class TrackTemplateResultInfo:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _setup_entities_listener(self) -> None:
|
def _setup_entities_listener(self) -> None:
|
||||||
|
assert self._info
|
||||||
|
|
||||||
entities = set(self._info.entities)
|
entities = set(self._info.entities)
|
||||||
for entity_id in self.hass.states.async_entity_ids(self._info.domains):
|
for entity_id in self.hass.states.async_entity_ids(self._info.domains):
|
||||||
entities.add(entity_id)
|
entities.add(entity_id)
|
||||||
@ -553,6 +567,8 @@ class TrackTemplateResultInfo:
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _setup_domains_listener(self) -> None:
|
def _setup_domains_listener(self) -> None:
|
||||||
|
assert self._info
|
||||||
|
|
||||||
self._domains_listener = async_track_state_added_domain(
|
self._domains_listener = async_track_state_added_domain(
|
||||||
self.hass, self._info.domains, self._refresh
|
self.hass, self._info.domains, self._refresh
|
||||||
)
|
)
|
||||||
@ -631,7 +647,7 @@ def async_track_template_result(
|
|||||||
template: Template,
|
template: Template,
|
||||||
action: TrackTemplateResultListener,
|
action: TrackTemplateResultListener,
|
||||||
variables: Optional[TemplateVarsType] = None,
|
variables: Optional[TemplateVarsType] = None,
|
||||||
) -> TrackTemplateResultInfo:
|
) -> _TrackTemplateResultInfo:
|
||||||
"""Add a listener that fires when a the result of a template changes.
|
"""Add a listener that fires when a the result of a template changes.
|
||||||
|
|
||||||
The action will fire with the initial result from the template, and
|
The action will fire with the initial result from the template, and
|
||||||
@ -662,7 +678,9 @@ def async_track_template_result(
|
|||||||
Info object used to unregister the listener, and refresh the template.
|
Info object used to unregister the listener, and refresh the template.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return TrackTemplateResultInfo(hass, template, action, variables)
|
tracker = _TrackTemplateResultInfo(hass, template, action, variables)
|
||||||
|
tracker.async_setup()
|
||||||
|
return tracker
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -796,6 +796,52 @@ async def test_track_template_result_with_group(hass):
|
|||||||
assert specific_runs[-1] == str(100.1 + 200.2 + 0 + 800.8)
|
assert specific_runs[-1] == str(100.1 + 200.2 + 0 + 800.8)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_track_template_result_and_conditional(hass):
|
||||||
|
"""Test tracking template with an and conditional."""
|
||||||
|
specific_runs = []
|
||||||
|
hass.states.async_set("light.a", "off")
|
||||||
|
hass.states.async_set("light.b", "off")
|
||||||
|
template_str = '{% if states.light.a.state == "on" and states.light.b.state == "on" %}on{% else %}off{% endif %}'
|
||||||
|
|
||||||
|
template = Template(template_str, hass)
|
||||||
|
|
||||||
|
def specific_run_callback(event, template, old_result, new_result):
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
pprint.pprint([event, template, old_result, new_result])
|
||||||
|
specific_runs.append(new_result)
|
||||||
|
|
||||||
|
async_track_template_result(hass, template, specific_run_callback)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
hass.states.async_set("light.b", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 0
|
||||||
|
|
||||||
|
hass.states.async_set("light.a", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 1
|
||||||
|
assert specific_runs[0] == "on"
|
||||||
|
|
||||||
|
hass.states.async_set("light.b", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 2
|
||||||
|
assert specific_runs[1] == "off"
|
||||||
|
|
||||||
|
hass.states.async_set("light.a", "off")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 2
|
||||||
|
|
||||||
|
hass.states.async_set("light.b", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 2
|
||||||
|
|
||||||
|
hass.states.async_set("light.a", "on")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert len(specific_runs) == 3
|
||||||
|
assert specific_runs[2] == "on"
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_result_iterator(hass):
|
async def test_track_template_result_iterator(hass):
|
||||||
"""Test tracking template."""
|
"""Test tracking template."""
|
||||||
iterator_runs = []
|
iterator_runs = []
|
||||||
|
Loading…
x
Reference in New Issue
Block a user