From 607aaa0efe95017c8a54205339c513b431ed7c9f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 May 2024 01:09:12 -1000 Subject: [PATCH] Speed up template result parsing (#118168) --- homeassistant/helpers/template.py | 54 ++++++++++++++++--------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 6da13807ad4..314e58290ad 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -327,7 +327,33 @@ def _false(arg: str) -> bool: return False -_cached_literal_eval = lru_cache(maxsize=EVAL_CACHE_SIZE)(literal_eval) +@lru_cache(maxsize=EVAL_CACHE_SIZE) +def _cached_parse_result(render_result: str) -> Any: + """Parse a result and cache the result.""" + result = literal_eval(render_result) + if type(result) in RESULT_WRAPPERS: + result = RESULT_WRAPPERS[type(result)](result, render_result=render_result) + + # If the literal_eval result is a string, use the original + # 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. + # 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 + + return render_result class RenderInfo: @@ -588,31 +614,7 @@ class Template: def _parse_result(self, render_result: str) -> Any: """Parse the result.""" try: - result = _cached_literal_eval(render_result) - - if type(result) in RESULT_WRAPPERS: - result = RESULT_WRAPPERS[type(result)]( - result, render_result=render_result - ) - - # If the literal_eval result is a string, use the original - # 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. - # 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 + return _cached_parse_result(render_result) except (ValueError, TypeError, SyntaxError, MemoryError): pass