Skip to content

Commit

Permalink
Merge pull request #665 from pallets/operator-tests
Browse files Browse the repository at this point in the history
Allow using comparison operator symbols as tests
  • Loading branch information
davidism committed Jul 6, 2017
2 parents 05b55d5 + d62f050 commit ca1abd4
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 48 deletions.
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -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
-------------
Expand Down
20 changes: 16 additions & 4 deletions docs/jinjaext.py
Expand Up @@ -12,6 +12,9 @@
import os
import re
import inspect

import logging

import jinja2
from itertools import islice
from types import BuiltinFunctionType
Expand Down Expand Up @@ -108,26 +111,35 @@ 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>')

node = nodes.paragraph()
state.nested_parse(result, content_offset, node)
return node.children

return directive


Expand Down
53 changes: 17 additions & 36 deletions jinja2/tests.py
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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.
Expand All @@ -186,9 +155,21 @@ def test_in(value, seq):
'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,
}
36 changes: 28 additions & 8 deletions tests/test_tests.py
Expand Up @@ -78,17 +78,37 @@ def test_upper(self, env):
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 }}')
Expand Down

0 comments on commit ca1abd4

Please sign in to comment.