]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Added min and max filters
authorSebastian Noack <sebastian.noack@gmail.com>
Tue, 4 Aug 2015 20:11:55 +0000 (22:11 +0200)
committerDavid Lord <davidism@gmail.com>
Thu, 6 Jul 2017 15:02:22 +0000 (08:02 -0700)
jinja2/filters.py
tests/test_filters.py

index c0d105bd0d7b04cb6aa667883f15bfd375b7e7bd..cdd12774a5efe48b91c50e832065557b97917511 100644 (file)
@@ -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,
index 01e4c3c15ea9bf486c44fba5a174b3badbf7f398..9c4504a7393c2b81b4e88698bbab9ed677185ec1 100644 (file)
@@ -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"