From b1bf6a609e4e187543ac72d592cb3ecdbabff532 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 11 Dec 2015 19:07:03 -0800 Subject: [PATCH 1/2] Catch exceptions when error rendering templates --- homeassistant/exceptions.py | 7 +++++++ homeassistant/util/template.py | 20 ++++++++++++++++---- tests/util/test_template.py | 6 +++++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/homeassistant/exceptions.py b/homeassistant/exceptions.py index bd32d356670..510bc9b4e54 100644 --- a/homeassistant/exceptions.py +++ b/homeassistant/exceptions.py @@ -14,3 +14,10 @@ class InvalidEntityFormatError(HomeAssistantError): class NoEntitySpecifiedError(HomeAssistantError): """ When no entity is specified. """ pass + + +class TemplateError(HomeAssistantError): + """ Error during template rendering. """ + def __init__(self, exception): + super().__init__('{}: {}'.format(exception.__class__.__name__, + exception)) diff --git a/homeassistant/util/template.py b/homeassistant/util/template.py index bc89d053e60..b7fc3197e08 100644 --- a/homeassistant/util/template.py +++ b/homeassistant/util/template.py @@ -6,7 +6,12 @@ Template utility methods for rendering strings with HA data. """ # pylint: disable=too-few-public-methods import json +import logging +import jinja2 from jinja2.sandbox import ImmutableSandboxedEnvironment +from homeassistant.exceptions import TemplateError + +_LOGGER = logging.getLogger(__name__) def render_with_possible_json_value(hass, template, value): @@ -20,7 +25,11 @@ def render_with_possible_json_value(hass, template, value): except ValueError: pass - return render(hass, template, variables) + try: + return render(hass, template, variables) + except TemplateError: + _LOGGER.exception('Error parsing value') + return value def render(hass, template, variables=None, **kwargs): @@ -28,9 +37,12 @@ def render(hass, template, variables=None, **kwargs): if variables is not None: kwargs.update(variables) - return ENV.from_string(template, { - 'states': AllStates(hass) - }).render(kwargs) + try: + return ENV.from_string(template, { + 'states': AllStates(hass) + }).render(kwargs) + except jinja2.TemplateError as err: + raise TemplateError(err) class AllStates(object): diff --git a/tests/util/test_template.py b/tests/util/test_template.py index bbb4de31626..16e1f8b6a04 100644 --- a/tests/util/test_template.py +++ b/tests/util/test_template.py @@ -7,7 +7,7 @@ Tests Home Assistant util methods. # pylint: disable=too-many-public-methods import unittest import homeassistant.core as ha - +from homeassistant.exceptions import TemplateError from homeassistant.util import template @@ -84,3 +84,7 @@ class TestUtilTemplate(unittest.TestCase): '', template.render_with_possible_json_value( self.hass, '{{ value_json }}', '{ I AM NOT JSON }')) + + def test_raise_exception_on_error(self): + with self.assertRaises(TemplateError): + template.render(self.hass, '{{ invalid_syntax') From 2b975c8620e0e420df30327d08b6d654ced1dbda Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 12 Dec 2015 10:35:15 -0800 Subject: [PATCH 2/2] Add flexible error value for value template parsing --- homeassistant/util/template.py | 6 ++++-- tests/util/test_template.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/homeassistant/util/template.py b/homeassistant/util/template.py index b7fc3197e08..ad0fabdab53 100644 --- a/homeassistant/util/template.py +++ b/homeassistant/util/template.py @@ -12,9 +12,11 @@ from jinja2.sandbox import ImmutableSandboxedEnvironment from homeassistant.exceptions import TemplateError _LOGGER = logging.getLogger(__name__) +_SENTINEL = object() -def render_with_possible_json_value(hass, template, value): +def render_with_possible_json_value(hass, template, value, + error_value=_SENTINEL): """ Renders template with value exposed. If valid JSON will expose value_json too. """ variables = { @@ -29,7 +31,7 @@ def render_with_possible_json_value(hass, template, value): return render(hass, template, variables) except TemplateError: _LOGGER.exception('Error parsing value') - return value + return value if error_value is _SENTINEL else error_value def render(hass, template, variables=None, **kwargs): diff --git a/tests/util/test_template.py b/tests/util/test_template.py index 16e1f8b6a04..ba354f3e7be 100644 --- a/tests/util/test_template.py +++ b/tests/util/test_template.py @@ -85,6 +85,18 @@ class TestUtilTemplate(unittest.TestCase): template.render_with_possible_json_value( self.hass, '{{ value_json }}', '{ I AM NOT JSON }')) + def test_render_with_possible_json_value_with_template_error(self): + self.assertEqual( + 'hello', + template.render_with_possible_json_value( + self.hass, '{{ value_json', 'hello')) + + def test_render_with_possible_json_value_with_template_error_error_value(self): + self.assertEqual( + '-', + template.render_with_possible_json_value( + self.hass, '{{ value_json', 'hello', '-')) + def test_raise_exception_on_error(self): with self.assertRaises(TemplateError): template.render(self.hass, '{{ invalid_syntax')