From: Sebastian Noack Date: Tue, 4 Aug 2015 20:11:55 +0000 (+0200) Subject: Added min and max filters X-Git-Tag: 2.10~19^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5435d35f97d1e74eba2854651b8ef7258f31292b;p=thirdparty%2Fjinja.git Added min and max filters --- diff --git a/jinja2/filters.py b/jinja2/filters.py index c0d105bd..cdd12774 100644 --- a/jinja2/filters.py +++ b/jinja2/filters.py @@ -12,7 +12,7 @@ import re import math import random -from itertools import groupby +from itertools import groupby, chain from collections import namedtuple from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ unicode_urlencode, htmlsafe_json_dumps @@ -313,6 +313,55 @@ def do_unique(environment, value, case_sensitive=False, attribute=None): yield item +def _min_or_max(func, value, environment, attribute, case_sensitive): + it = iter(value) + try: + first = next(it) + except StopIteration: + return environment.undefined('No aggregated item, sequence was empty') + + key_func = make_attrgetter(environment, attribute, not case_sensitive) + return func(chain([first], it), key=key_func) + + +@environmentfilter +def do_min(environment, value, attribute=None, case_sensitive=False): + """Return the smallest item from the sequence. + + .. sourcecode:: jinja + + {{ [1, 2, 3]|min }} + -> 1 + + It is also possible to get the item providing the smallest value for a + certain attribute: + + .. sourcecode:: jinja + + {{ users|min('last_login') }} + """ + return _min_or_max(min, value, environment, attribute, case_sensitive) + + +@environmentfilter +def do_max(environment, value, attribute=None, case_sensitive=False): + """Return the largest item from the sequence. + + .. sourcecode:: jinja + + {{ [1, 2, 3]|max }} + -> 3 + + It is also possible to get the item providing the largest value for a + certain attribute: + + .. sourcecode:: jinja + + {{ users|max('last_login') }} + """ + return _min_or_max(max, value, environment, attribute, case_sensitive) + + def do_default(value, default_value=u'', boolean=False): """If the value is undefined it will return the passed default value, otherwise the value of the variable: @@ -1097,6 +1146,8 @@ FILTERS = { 'list': do_list, 'lower': do_lower, 'map': do_map, + 'min': do_min, + 'max': do_max, 'pprint': do_pprint, 'random': do_random, 'reject': do_reject, diff --git a/tests/test_filters.py b/tests/test_filters.py index 01e4c3c1..9c4504a7 100644 --- a/tests/test_filters.py +++ b/tests/test_filters.py @@ -391,6 +391,30 @@ class TestFilter(object): tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''') assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234' + def test_min1(self, env): + tmpl = env.from_string('{{ ["a", "B"]|min }}') + assert tmpl.render() == 'a' + + def test_min2(self, env): + tmpl = env.from_string('{{ []|min }}') + assert tmpl.render() == '' + + def test_min3(self, env): + tmpl = env.from_string('{{ items|min("value") }}') + assert tmpl.render(items=map(Magic, [5, 1, 9])) == '1' + + def test_max1(self, env): + tmpl = env.from_string('{{ ["a", "B"]|max }}') + assert tmpl.render() == 'B' + + def test_max2(self, env): + tmpl = env.from_string('{{ []|max }}') + assert tmpl.render() == '' + + def test_max3(self, env): + tmpl = env.from_string('{{ items|max("value") }}') + assert tmpl.render(items=map(Magic, [5, 9, 1])) == '9' + def test_unique(self, env): t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}') assert t.render() == "bA"