Add support for complex template structures to data_template (#3255)
This commit is contained in:
parent
94e3986d54
commit
267cda447e
4 changed files with 55 additions and 5 deletions
|
@ -244,6 +244,20 @@ def template(value):
|
||||||
raise vol.Invalid('invalid template ({})'.format(ex))
|
raise vol.Invalid('invalid template ({})'.format(ex))
|
||||||
|
|
||||||
|
|
||||||
|
def template_complex(value):
|
||||||
|
"""Validate a complex jinja2 template."""
|
||||||
|
if isinstance(value, list):
|
||||||
|
for idx, element in enumerate(value):
|
||||||
|
value[idx] = template_complex(element)
|
||||||
|
return value
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for key, element in value.items():
|
||||||
|
value[key] = template_complex(element)
|
||||||
|
return value
|
||||||
|
|
||||||
|
return template(value)
|
||||||
|
|
||||||
|
|
||||||
def time(value):
|
def time(value):
|
||||||
"""Validate time."""
|
"""Validate time."""
|
||||||
time_val = dt_util.parse_time(value)
|
time_val = dt_util.parse_time(value)
|
||||||
|
@ -310,7 +324,7 @@ SERVICE_SCHEMA = vol.All(vol.Schema({
|
||||||
vol.Exclusive('service', 'service name'): service,
|
vol.Exclusive('service', 'service name'): service,
|
||||||
vol.Exclusive('service_template', 'service name'): template,
|
vol.Exclusive('service_template', 'service name'): template,
|
||||||
vol.Optional('data'): dict,
|
vol.Optional('data'): dict,
|
||||||
vol.Optional('data_template'): {match_all: template},
|
vol.Optional('data_template'): {match_all: template_complex},
|
||||||
vol.Optional(CONF_ENTITY_ID): entity_ids,
|
vol.Optional(CONF_ENTITY_ID): entity_ids,
|
||||||
}), has_at_least_one_key('service', 'service_template'))
|
}), has_at_least_one_key('service', 'service_template'))
|
||||||
|
|
||||||
|
|
|
@ -63,9 +63,21 @@ def call_from_config(hass, config, blocking=False, variables=None,
|
||||||
domain, service_name = domain_service.split('.', 1)
|
domain, service_name = domain_service.split('.', 1)
|
||||||
service_data = dict(config.get(CONF_SERVICE_DATA, {}))
|
service_data = dict(config.get(CONF_SERVICE_DATA, {}))
|
||||||
|
|
||||||
|
def _data_template_creator(value):
|
||||||
|
"""Recursive template creator helper function."""
|
||||||
|
if isinstance(value, list):
|
||||||
|
for idx, element in enumerate(value):
|
||||||
|
value[idx] = _data_template_creator(element)
|
||||||
|
return value
|
||||||
|
if isinstance(value, dict):
|
||||||
|
for key, element in value.items():
|
||||||
|
value[key] = _data_template_creator(element)
|
||||||
|
return value
|
||||||
|
return template.render(hass, value, variables)
|
||||||
|
|
||||||
if CONF_SERVICE_DATA_TEMPLATE in config:
|
if CONF_SERVICE_DATA_TEMPLATE in config:
|
||||||
for key, value in config[CONF_SERVICE_DATA_TEMPLATE].items():
|
for key, value in config[CONF_SERVICE_DATA_TEMPLATE].items():
|
||||||
service_data[key] = template.render(hass, value, variables)
|
service_data[key] = _data_template_creator(value)
|
||||||
|
|
||||||
if CONF_SERVICE_ENTITY_ID in config:
|
if CONF_SERVICE_ENTITY_ID in config:
|
||||||
service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID]
|
service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID]
|
||||||
|
|
|
@ -299,9 +299,7 @@ def test_template():
|
||||||
"""Test template validator."""
|
"""Test template validator."""
|
||||||
schema = vol.Schema(cv.template)
|
schema = vol.Schema(cv.template)
|
||||||
|
|
||||||
for value in (
|
for value in (None, '{{ partial_print }', '{% if True %}Hello', ['test']):
|
||||||
None, '{{ partial_print }', '{% if True %}Hello', {'dict': 'isbad'}
|
|
||||||
):
|
|
||||||
with pytest.raises(vol.MultipleInvalid):
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
@ -313,6 +311,24 @@ def test_template():
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_template_complex():
|
||||||
|
"""Test template_complex validator."""
|
||||||
|
schema = vol.Schema(cv.template_complex)
|
||||||
|
|
||||||
|
for value in (None, '{{ partial_print }', '{% if True %}Hello'):
|
||||||
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
|
schema(value)
|
||||||
|
|
||||||
|
for value in (
|
||||||
|
1, 'Hello',
|
||||||
|
'{{ beer }}',
|
||||||
|
'{% if 1 == 1 %}Hello{% else %}World{% endif %}',
|
||||||
|
{'test': 1, 'test': '{{ beer }}'},
|
||||||
|
['{{ beer }}', 1]
|
||||||
|
):
|
||||||
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
def test_time_zone():
|
def test_time_zone():
|
||||||
"""Test time zone validation."""
|
"""Test time zone validation."""
|
||||||
schema = vol.Schema(cv.time_zone)
|
schema = vol.Schema(cv.time_zone)
|
||||||
|
|
|
@ -43,6 +43,11 @@ class TestServiceHelpers(unittest.TestCase):
|
||||||
'entity_id': 'hello.world',
|
'entity_id': 'hello.world',
|
||||||
'data_template': {
|
'data_template': {
|
||||||
'hello': '{{ \'goodbye\' }}',
|
'hello': '{{ \'goodbye\' }}',
|
||||||
|
'data': {
|
||||||
|
'value': '{{ \'complex\' }}',
|
||||||
|
'simple': 'simple'
|
||||||
|
},
|
||||||
|
'list': ['{{ \'list\' }}', '2'],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
runs = []
|
runs = []
|
||||||
|
@ -54,6 +59,9 @@ class TestServiceHelpers(unittest.TestCase):
|
||||||
self.hass.pool.block_till_done()
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
self.assertEqual('goodbye', runs[0].data['hello'])
|
self.assertEqual('goodbye', runs[0].data['hello'])
|
||||||
|
self.assertEqual('complex', runs[0].data['data']['value'])
|
||||||
|
self.assertEqual('simple', runs[0].data['data']['simple'])
|
||||||
|
self.assertEqual('list', runs[0].data['list'][0])
|
||||||
|
|
||||||
def test_passing_variables_to_templates(self):
|
def test_passing_variables_to_templates(self):
|
||||||
"""Test passing variables to templates."""
|
"""Test passing variables to templates."""
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue