• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2"""
3    jinja2.tests
4    ~~~~~~~~~~~~
5
6    Jinja test functions. Used with the "is" operator.
7
8    :copyright: (c) 2017 by the Jinja Team.
9    :license: BSD, see LICENSE for more details.
10"""
11import operator
12import re
13try:
14  from collections.abc import Mapping
15except ImportError:
16  from collections import Mapping
17from jinja2.runtime import Undefined
18from jinja2._compat import text_type, string_types, integer_types
19import decimal
20
21number_re = re.compile(r'^-?\d+(\.\d+)?$')
22regex_type = type(number_re)
23
24
25test_callable = callable
26
27
28def test_odd(value):
29    """Return true if the variable is odd."""
30    return value % 2 == 1
31
32
33def test_even(value):
34    """Return true if the variable is even."""
35    return value % 2 == 0
36
37
38def test_divisibleby(value, num):
39    """Check if a variable is divisible by a number."""
40    return value % num == 0
41
42
43def test_defined(value):
44    """Return true if the variable is defined:
45
46    .. sourcecode:: jinja
47
48        {% if variable is defined %}
49            value of variable: {{ variable }}
50        {% else %}
51            variable is not defined
52        {% endif %}
53
54    See the :func:`default` filter for a simple way to set undefined
55    variables.
56    """
57    return not isinstance(value, Undefined)
58
59
60def test_undefined(value):
61    """Like :func:`defined` but the other way round."""
62    return isinstance(value, Undefined)
63
64
65def test_none(value):
66    """Return true if the variable is none."""
67    return value is None
68
69
70def test_lower(value):
71    """Return true if the variable is lowercased."""
72    return text_type(value).islower()
73
74
75def test_upper(value):
76    """Return true if the variable is uppercased."""
77    return text_type(value).isupper()
78
79
80def test_string(value):
81    """Return true if the object is a string."""
82    return isinstance(value, string_types)
83
84
85def test_mapping(value):
86    """Return true if the object is a mapping (dict etc.).
87
88    .. versionadded:: 2.6
89    """
90    return isinstance(value, Mapping)
91
92
93def test_number(value):
94    """Return true if the variable is a number."""
95    return isinstance(value, integer_types + (float, complex, decimal.Decimal))
96
97
98def test_sequence(value):
99    """Return true if the variable is a sequence. Sequences are variables
100    that are iterable.
101    """
102    try:
103        len(value)
104        value.__getitem__
105    except:
106        return False
107    return True
108
109
110def test_sameas(value, other):
111    """Check if an object points to the same memory address than another
112    object:
113
114    .. sourcecode:: jinja
115
116        {% if foo.attribute is sameas false %}
117            the foo attribute really is the `False` singleton
118        {% endif %}
119    """
120    return value is other
121
122
123def test_iterable(value):
124    """Check if it's possible to iterate over an object."""
125    try:
126        iter(value)
127    except TypeError:
128        return False
129    return True
130
131
132def test_escaped(value):
133    """Check if the value is escaped."""
134    return hasattr(value, '__html__')
135
136
137def test_in(value, seq):
138    """Check if value is in seq.
139
140    .. versionadded:: 2.10
141    """
142    return value in seq
143
144
145TESTS = {
146    'odd':              test_odd,
147    'even':             test_even,
148    'divisibleby':      test_divisibleby,
149    'defined':          test_defined,
150    'undefined':        test_undefined,
151    'none':             test_none,
152    'lower':            test_lower,
153    'upper':            test_upper,
154    'string':           test_string,
155    'mapping':          test_mapping,
156    'number':           test_number,
157    'sequence':         test_sequence,
158    'iterable':         test_iterable,
159    'callable':         test_callable,
160    'sameas':           test_sameas,
161    'escaped':          test_escaped,
162    'in':               test_in,
163    '==':               operator.eq,
164    'eq':               operator.eq,
165    'equalto':          operator.eq,
166    '!=':               operator.ne,
167    'ne':               operator.ne,
168    '>':                operator.gt,
169    'gt':               operator.gt,
170    'greaterthan':      operator.gt,
171    'ge':               operator.ge,
172    '>=':               operator.ge,
173    '<':                operator.lt,
174    'lt':               operator.lt,
175    'lessthan':         operator.lt,
176    '<=':               operator.le,
177    'le':               operator.le,
178}
179