diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index c6efa717fa75..09a9170c79aa 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -49,6 +49,8 @@ _RENDER_INFO = "template.render_info" _ENVIRONMENT = "template.environment" _RE_JINJA_DELIMITERS = re.compile(r"\{%|\{\{|\{#") +# Match "simple" ints and floats. -1.0, 1, +5, 5.0 +_IS_NUMERIC = re.compile(r"^[+-]?\d*(?:\.\d*)?$") _RESERVED_NAMES = {"contextfunction", "evalcontextfunction", "environmentfunction"} @@ -373,7 +375,19 @@ class Template: # render, by not returning right here. The evaluation of strings # resulting in strings impacts quotes, to avoid unexpected # output; use the original render instead of the evaluated one. - if not isinstance(result, str): + # Complex and scientific values are also unexpected. Filter them out. + if ( + # Filter out string and complex numbers + not isinstance(result, (str, complex)) + and ( + # Pass if not numeric and not a boolean + not isinstance(result, (int, float)) + # Or it's a boolean (inherit from int) + or isinstance(result, bool) + # Or if it's a digit + or _IS_NUMERIC.match(render_result) is not None + ) + ): return result except (ValueError, TypeError, SyntaxError, MemoryError): pass diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index fe2f23c00332..53186ed35a18 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -346,7 +346,7 @@ def test_tan(hass): (0, 0.0), (math.pi, -0.0), (math.pi / 180 * 45, 1.0), - (math.pi / 180 * 90, 1.633123935319537e16), + (math.pi / 180 * 90, "1.633123935319537e+16"), (math.pi / 180 * 135, -1.0), ("'error'", "error"), ] @@ -2416,5 +2416,16 @@ async def test_parse_result(hass): ('{{ "{{}}" }}', "{{}}"), ("not-something", "not-something"), ("2a", "2a"), + ("123E5", "123E5"), + ("1j", "1j"), + ("1e+100", "1e+100"), + ("0xface", "0xface"), + ("123", 123), + ("123.0", 123.0), + (".5", 0.5), + ("-1", -1), + ("-1.0", -1.0), + ("+1", 1), + ("5.", 5.0), ): assert template.Template(tpl, hass).async_render() == result