Skip to content

Commit

Permalink
Add support for complex template structures to data_template (home-as…
Browse files Browse the repository at this point in the history
  • Loading branch information
pvizeli authored and kellerza committed Sep 8, 2016
1 parent 94e3986 commit 267cda4
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 3 deletions.
16 changes: 15 additions & 1 deletion homeassistant/helpers/config_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,20 @@ def template(value):
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):
"""Validate time."""
time_val = dt_util.parse_time(value)
Expand Down Expand Up @@ -310,7 +324,7 @@ def validator(value):
vol.Exclusive('service', 'service name'): service,
vol.Exclusive('service_template', 'service name'): template,
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,
}), has_at_least_one_key('service', 'service_template'))

Expand Down
14 changes: 13 additions & 1 deletion homeassistant/helpers/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,21 @@ def call_from_config(hass, config, blocking=False, variables=None,
domain, service_name = domain_service.split('.', 1)
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:
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:
service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID]
Expand Down
18 changes: 17 additions & 1 deletion tests/helpers/test_config_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,16 +299,32 @@ def test_template():
"""Test template validator."""
schema = vol.Schema(cv.template)

for value in (None, '{{ partial_print }', '{% if True %}Hello', ['test']):
with pytest.raises(vol.MultipleInvalid):
schema(value)

for value in (
None, '{{ partial_print }', '{% if True %}Hello', {'dict': 'isbad'}
1, 'Hello',
'{{ beer }}',
'{% if 1 == 1 %}Hello{% else %}World{% endif %}',
):
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)

Expand Down
8 changes: 8 additions & 0 deletions tests/helpers/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ def test_template_service_call(self):
'entity_id': 'hello.world',
'data_template': {
'hello': '{{ \'goodbye\' }}',
'data': {
'value': '{{ \'complex\' }}',
'simple': 'simple'
},
'list': ['{{ \'list\' }}', '2'],
},
}
runs = []
Expand All @@ -54,6 +59,9 @@ def test_template_service_call(self):
self.hass.pool.block_till_done()

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):
"""Test passing variables to templates."""
Expand Down

0 comments on commit 267cda4

Please sign in to comment.