From 3d1c8ee467697805f383158af20f14fb6eee4b71 Mon Sep 17 00:00:00 2001 From: Rohan Kapoor Date: Fri, 21 Sep 2018 02:57:01 -0700 Subject: [PATCH] Implement support for complex templates in script delays (#16442) * Implement support for complex templates in script delays * Swap out dict instead of collections.Mapping --- homeassistant/helpers/config_validation.py | 2 +- homeassistant/helpers/script.py | 5 ++ tests/helpers/test_script.py | 64 ++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 3363b199b0b..bb4dcf6a55f 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -590,7 +590,7 @@ _SCRIPT_DELAY_SCHEMA = vol.Schema({ vol.Optional(CONF_ALIAS): string, vol.Required("delay"): vol.Any( vol.All(time_period, positive_timedelta), - template) + template, template_complex) }) _SCRIPT_WAIT_TEMPLATE_SCHEMA = vol.Schema({ diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 8a33b57e9d1..96f9b2d5069 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -107,6 +107,11 @@ class Script(): cv.time_period, cv.positive_timedelta)( delay.async_render(variables)) + elif isinstance(delay, dict): + delay_data = {} + delay_data.update( + template.render_complex(delay, variables)) + delay = cv.time_period(delay_data) except (TemplateError, vol.Invalid) as ex: _LOGGER.error("Error rendering '%s' delay template: %s", self.name, ex) diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 2956d82c2ba..d217b99b3a8 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -255,6 +255,70 @@ class TestScriptHelper(unittest.TestCase): assert not script_obj.is_running assert len(events) == 1 + def test_delay_complex_template(self): + """Test the delay with a working complex template.""" + event = 'test_event' + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.bus.listen(event, record_event) + + script_obj = script.Script(self.hass, cv.SCRIPT_SCHEMA([ + {'event': event}, + {'delay': { + 'seconds': '{{ 5 }}' + }}, + {'event': event}])) + + script_obj.run() + self.hass.block_till_done() + + assert script_obj.is_running + assert script_obj.can_cancel + assert script_obj.last_action == event + assert len(events) == 1 + + future = dt_util.utcnow() + timedelta(seconds=5) + fire_time_changed(self.hass, future) + self.hass.block_till_done() + + assert not script_obj.is_running + assert len(events) == 2 + + def test_delay_complex_invalid_template(self): + """Test the delay with a complex template that fails.""" + event = 'test_event' + events = [] + + @callback + def record_event(event): + """Add recorded event to set.""" + events.append(event) + + self.hass.bus.listen(event, record_event) + + script_obj = script.Script(self.hass, cv.SCRIPT_SCHEMA([ + {'event': event}, + {'delay': { + 'seconds': '{{ invalid_delay }}' + }}, + {'delay': { + 'seconds': '{{ 5 }}' + }}, + {'event': event}])) + + with mock.patch.object(script, '_LOGGER') as mock_logger: + script_obj.run() + self.hass.block_till_done() + assert mock_logger.error.called + + assert not script_obj.is_running + assert len(events) == 1 + def test_cancel_while_delay(self): """Test the cancelling while the delay is present.""" event = 'test_event'