diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 083d0e530aa..f04231ce78a 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -1657,7 +1657,7 @@ def min_max_from_filter(builtin_filter: Any, name: str) -> Any: return pass_environment(wrapper) -def average(*args: Any) -> float: +def average(*args: Any, default: Any = _SENTINEL) -> Any: """ Filter and function to calculate the arithmetic mean of an iterable or of two or more arguments. @@ -1666,13 +1666,23 @@ def average(*args: Any) -> float: if len(args) == 0: raise TypeError("average expected at least 1 argument, got 0") - if len(args) == 1: - if isinstance(args[0], Iterable): - return statistics.fmean(args[0]) - + # If first argument is iterable and more then 1 argument provided but not a named default, + # then use 2nd argument as default. + if isinstance(args[0], Iterable): + average_list = args[0] + if len(args) > 1 and default is _SENTINEL: + default = args[1] + elif len(args) == 1: raise TypeError(f"'{type(args[0]).__name__}' object is not iterable") + else: + average_list = args - return statistics.fmean(args) + try: + return statistics.fmean(average_list) + except (TypeError, statistics.StatisticsError): + if default is _SENTINEL: + raise_no_default("average", args) + return default def forgiving_float(value, default=_SENTINEL): diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 9c9a1e42a98..265706c9713 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -973,12 +973,27 @@ def test_average(hass): assert template.Template("{{ average([1, 2, 3]) }}", hass).async_render() == 2 assert template.Template("{{ average(1, 2, 3) }}", hass).async_render() == 2 + # Testing of default values + assert template.Template("{{ average([1, 2, 3], -1) }}", hass).async_render() == 2 + assert template.Template("{{ average([], -1) }}", hass).async_render() == -1 + assert template.Template("{{ average([], default=-1) }}", hass).async_render() == -1 + assert ( + template.Template("{{ average([], 5, default=-1) }}", hass).async_render() == -1 + ) + assert ( + template.Template("{{ average(1, 'a', 3, default=-1) }}", hass).async_render() + == -1 + ) + with pytest.raises(TemplateError): template.Template("{{ 1 | average }}", hass).async_render() with pytest.raises(TemplateError): template.Template("{{ average() }}", hass).async_render() + with pytest.raises(TemplateError): + template.Template("{{ average([]) }}", hass).async_render() + def test_min(hass): """Test the min filter."""