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
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:
'list': do_list,
'lower': do_lower,
'map': do_map,
+ 'min': do_min,
+ 'max': do_max,
'pprint': do_pprint,
'random': do_random,
'reject': do_reject,
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"