]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
allow using comparison operator symbols as tests 665/head
authorDavid Lord <davidism@gmail.com>
Fri, 20 Jan 2017 04:40:31 +0000 (20:40 -0800)
committerDavid Lord <davidism@gmail.com>
Thu, 6 Jul 2017 19:59:28 +0000 (12:59 -0700)
add tests and aliases for all comparison operators
adjust docs to prefer short names for compare tests
closes #664

CHANGES
docs/jinjaext.py
jinja2/tests.py
tests/test_tests.py

diff --git a/CHANGES b/CHANGES
index 31a5bb8aadcfcdefa2d66f3a04a2c453c25bf44a..6276b1157793e6e39ff11349d95274f184d01be8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -26,10 +26,13 @@ Version 2.10
   produce a new random choice each time the template is rendered. (`#478`_)
 - Add a ``unique`` filter. (`#469`_)
 - Add ``min`` and ``max`` filters. (`#475`_)
+- Add tests for all comparison operators: ``eq``, ``ne``, ``lt``, ``le``,
+  ``gt``, ``ge``. (`#665`_)
 
 .. _#469: https://github.com/pallets/jinja/pull/469
 .. _#475: https://github.com/pallets/jinja/pull/475
 .. _#478: https://github.com/pallets/jinja/pull/478
+.. _#665: https://github.com/pallets/jinja/pull/665
 
 Version 2.9.6
 -------------
index cdacba9d9cf62f4001ee1070e73396c7b3ac9367..bb508089206d7252e2b485d6cf571629dfdd7645 100644 (file)
@@ -12,6 +12,9 @@ import collections
 import os
 import re
 import inspect
+
+import logging
+
 import jinja2
 from itertools import islice
 from types import BuiltinFunctionType
@@ -108,19 +111,27 @@ def format_function(name, aliases, func):
 
 
 def dump_functions(mapping):
-    def directive(dirname, arguments, options, content, lineno,
-                      content_offset, block_text, state, state_machine):
+    def directive(
+        dirname, arguments, options, content, lineno, content_offset,
+        block_text, state, state_machine
+    ):
         reverse_mapping = {}
+
         for name, func in mapping.items():
             reverse_mapping.setdefault(func, []).append(name)
+
         filters = []
+        compare_ops = set(('lt', 'le', 'eq', 'ne', 'ge', 'gt'))
+
         for func, names in reverse_mapping.items():
-            aliases = sorted(names, key=lambda x: len(x))
+            aliases = sorted(names, key=len)
+            aliases = sorted(aliases, key=lambda x: x in compare_ops)
             name = aliases.pop()
             filters.append((name, aliases, func))
-        filters.sort()
 
+        filters.sort()
         result = ViewList()
+
         for name, aliases, func in filters:
             for item in format_function(name, aliases, func):
                 result.append(item, '<jinjaext>')
@@ -128,6 +139,7 @@ def dump_functions(mapping):
         node = nodes.paragraph()
         state.nested_parse(result, content_offset, node)
         return node.children
+
     return directive
 
 
index 40b2b35a67d2f8bc8ff7036eb7e7c4088cf8ae99..0adc3d4dbcbb881910bfd90214534449fafddcb3 100644 (file)
@@ -8,6 +8,7 @@
     :copyright: (c) 2017 by the Jinja Team.
     :license: BSD, see LICENSE for more details.
 """
+import operator
 import re
 from collections import Mapping
 from jinja2.runtime import Undefined
@@ -103,28 +104,6 @@ def test_sequence(value):
     return True
 
 
-def test_equalto(value, other):
-    """Check if an object has the same value as another object:
-
-    .. sourcecode:: jinja
-
-        {% if foo.expression is equalto 42 %}
-            the foo attribute evaluates to the constant 42
-        {% endif %}
-
-    This appears to be a useless test as it does exactly the same as the
-    ``==`` operator, but it can be useful when used together with the
-    `selectattr` function:
-
-    .. sourcecode:: jinja
-
-        {{ users|selectattr("email", "equalto", "foo@bar.invalid") }}
-
-    .. versionadded:: 2.8
-    """
-    return value == other
-
-
 def test_sameas(value, other):
     """Check if an object points to the same memory address than another
     object:
@@ -152,16 +131,6 @@ def test_escaped(value):
     return hasattr(value, '__html__')
 
 
-def test_greaterthan(value, other):
-    """Check if value is greater than other."""
-    return value > other
-
-
-def test_lessthan(value, other):
-    """Check if value is less than other."""
-    return value < other
-
-
 def test_in(value, seq):
     """Check if value is in seq.
 
@@ -186,9 +155,21 @@ TESTS = {
     'iterable':         test_iterable,
     'callable':         test_callable,
     'sameas':           test_sameas,
-    'equalto':          test_equalto,
     'escaped':          test_escaped,
-    'greaterthan':      test_greaterthan,
-    'lessthan':         test_lessthan,
-    'in':               test_in
+    'in':               test_in,
+    '==':               operator.eq,
+    'eq':               operator.eq,
+    'equalto':          operator.eq,
+    '!=':               operator.ne,
+    'ne':               operator.ne,
+    '>':                operator.gt,
+    'gt':               operator.gt,
+    'greaterthan':      operator.gt,
+    'ge':               operator.ge,
+    '>=':               operator.ge,
+    '<':                operator.lt,
+    'lt':               operator.lt,
+    'lessthan':         operator.lt,
+    '<=':               operator.le,
+    'le':               operator.le,
 }
index 3539a1fd37e1aa547dbf47359deeeec99cdae854..84df5ea7577495ea5c76f29dfcd1416248d2b2e0 100644 (file)
@@ -78,17 +78,37 @@ class TestTestsCase(object):
         assert tmpl.render() == 'True|False'
 
     def test_equalto(self, env):
-        tmpl = env.from_string('{{ foo is equalto 12 }}|'
-                               '{{ foo is equalto 0 }}|'
-                               '{{ foo is equalto (3 * 4) }}|'
-                               '{{ bar is equalto "baz" }}|'
-                               '{{ bar is equalto "zab" }}|'
-                               '{{ bar is equalto ("ba" + "z") }}|'
-                               '{{ bar is equalto bar }}|'
-                               '{{ bar is equalto foo }}')
+        tmpl = env.from_string(
+            '{{ foo is eq 12 }}|'
+            '{{ foo is eq 0 }}|'
+            '{{ foo is eq (3 * 4) }}|'
+            '{{ bar is eq "baz" }}|'
+            '{{ bar is eq "zab" }}|'
+            '{{ bar is eq ("ba" + "z") }}|'
+            '{{ bar is eq bar }}|'
+            '{{ bar is eq foo }}'
+        )
         assert tmpl.render(foo=12, bar="baz") \
             == 'True|False|True|True|False|True|True|False'
 
+    @pytest.mark.parametrize('op,expect', (
+        ('eq 2', True),
+        ('eq 3', False),
+        ('ne 3', True),
+        ('ne 2', False),
+        ('lt 3', True),
+        ('lt 2', False),
+        ('le 2', True),
+        ('le 1', False),
+        ('gt 1', True),
+        ('gt 2', False),
+        ('ge 2', True),
+        ('ge 3', False),
+    ))
+    def test_compare_aliases(self, env, op, expect):
+        t = env.from_string('{{{{ 2 is {op} }}}}'.format(op=op))
+        assert t.render() == str(expect)
+
     def test_sameas(self, env):
         tmpl = env.from_string('{{ foo is sameas false }}|'
                                '{{ 0 is sameas false }}')