Add average template function and filter (#57727)

pull/58502/head
Petro31 2021-10-26 16:43:45 -04:00 committed by GitHub
parent 953ad71d22
commit 11034a93c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 0 deletions

View File

@ -16,6 +16,7 @@ import math
from operator import attrgetter
import random
import re
import statistics
import sys
from typing import Any, cast
from urllib.parse import urlencode as urllib_urlencode
@ -1489,6 +1490,24 @@ def fail_when_undefined(value):
return value
def average(*args: Any) -> float:
"""
Filter and function to calculate the arithmetic mean of an iterable or of two or more arguments.
The parameters may be passed as an iterable or as separate arguments.
"""
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])
raise TypeError(f"'{type(args[0]).__name__}' object is not iterable")
return statistics.fmean(args)
def forgiving_float(value, default=_SENTINEL):
"""Try to convert value to a float."""
try:
@ -1758,6 +1777,7 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
self.filters["to_json"] = to_json
self.filters["from_json"] = from_json
self.filters["is_defined"] = fail_when_undefined
self.filters["average"] = average
self.filters["max"] = max
self.filters["min"] = min
self.filters["random"] = random_every_time
@ -1796,6 +1816,7 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment):
self.globals["timedelta"] = timedelta
self.globals["strptime"] = strptime
self.globals["urlencode"] = urlencode
self.globals["average"] = average
self.globals["max"] = max
self.globals["min"] = min
self.globals["is_number"] = is_number

View File

@ -758,6 +758,19 @@ def test_from_json(hass):
assert actual_result == expected_result
def test_average(hass):
"""Test the average filter."""
assert template.Template("{{ [1, 2, 3] | average }}", hass).async_render() == 2
assert template.Template("{{ average([1, 2, 3]) }}", hass).async_render() == 2
assert template.Template("{{ average(1, 2, 3) }}", hass).async_render() == 2
with pytest.raises(TemplateError):
template.Template("{{ 1 | average }}", hass).async_render()
with pytest.raises(TemplateError):
template.Template("{{ average() }}", hass).async_render()
def test_min(hass):
"""Test the min filter."""
assert template.Template("{{ [1, 2, 3] | min }}", hass).async_render() == 1