Fixed #23913 -- Deprecated the `=` comparison in `if` template tag.

This commit is contained in:
Ola Sitarska 2014-12-01 21:20:37 +00:00 committed by Tim Graham
parent 412066e71e
commit d563e3be68
6 changed files with 68 additions and 3 deletions

View File

@ -999,7 +999,7 @@ def do_if(parser, token):
``{% if 1>2 %}`` is not a valid if tag. ``{% if 1>2 %}`` is not a valid if tag.
All supported operators are: ``or``, ``and``, ``in``, ``not in`` All supported operators are: ``or``, ``and``, ``in``, ``not in``
``==`` (or ``=``), ``!=``, ``>``, ``>=``, ``<`` and ``<=``. ``==``, ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
Operator precedence follows Python. Operator precedence follows Python.
""" """

View File

@ -1,6 +1,9 @@
""" """
Parser and utilities for the smart 'if' tag Parser and utilities for the smart 'if' tag
""" """
import warnings
from django.utils.deprecation import RemovedInDjango20Warning
# Using a simple top down parser, as described here: # Using a simple top down parser, as described here:
@ -99,6 +102,7 @@ OPERATORS = {
'not': prefix(8, lambda context, x: not x.eval(context)), 'not': prefix(8, lambda context, x: not x.eval(context)),
'in': infix(9, lambda context, x, y: x.eval(context) in y.eval(context)), 'in': infix(9, lambda context, x, y: x.eval(context) in y.eval(context)),
'not in': infix(9, lambda context, x, y: x.eval(context) not in y.eval(context)), 'not in': infix(9, lambda context, x, y: x.eval(context) not in y.eval(context)),
# This should be removed in Django 2.0:
'=': infix(10, lambda context, x, y: x.eval(context) == y.eval(context)), '=': infix(10, lambda context, x, y: x.eval(context) == y.eval(context)),
'==': infix(10, lambda context, x, y: x.eval(context) == y.eval(context)), '==': infix(10, lambda context, x, y: x.eval(context) == y.eval(context)),
'!=': infix(10, lambda context, x, y: x.eval(context) != y.eval(context)), '!=': infix(10, lambda context, x, y: x.eval(context) != y.eval(context)),
@ -174,6 +178,11 @@ class IfParser(object):
except (KeyError, TypeError): except (KeyError, TypeError):
return self.create_var(token) return self.create_var(token)
else: else:
if token == '=':
warnings.warn(
"Operator '=' is deprecated and will be removed in Django 2.0. Use '==' instead.",
RemovedInDjango20Warning, stacklevel=2
)
return op() return op()
def next_token(self): def next_token(self):

View File

@ -140,6 +140,9 @@ details on these changes.
* The ``ssi`` template tag will be removed. * The ``ssi`` template tag will be removed.
* Support for the ``=`` comparison operator in the ``if`` template tag will be
removed.
.. _deprecation-removed-in-1.9: .. _deprecation-removed-in-1.9:
1.9 1.9

View File

@ -1492,6 +1492,12 @@ absolute path. This is of limited use in most deployment situations, and
the :ttag:`include` tag often makes more sense. This tag is now deprecated and the :ttag:`include` tag often makes more sense. This tag is now deprecated and
will be removed in Django 2.0. will be removed in Django 2.0.
``=`` as comparison operator in ``if`` template tag
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using a single equals sign with the ``{% if %}`` template tag for equality
testing was undocumented and untested. It's now deprecated in favor of ``==``.
.. removed-features-1.8: .. removed-features-1.8:
Features removed in 1.8 Features removed in 1.8

View File

@ -1,5 +1,8 @@
import warnings
from django.template import TemplateSyntaxError from django.template import TemplateSyntaxError
from django.test import SimpleTestCase from django.test import ignore_warnings, SimpleTestCase
from django.utils.deprecation import RemovedInDjango20Warning
from ..utils import setup, TestObj from ..utils import setup, TestObj
@ -521,3 +524,42 @@ class IfTagTests(SimpleTestCase):
def test_if_tag_badarg04(self): def test_if_tag_badarg04(self):
output = self.engine.render_to_string('if-tag-badarg04') output = self.engine.render_to_string('if-tag-badarg04')
self.assertEqual(output, 'no') self.assertEqual(output, 'no')
@setup({'if-tag-eq-deprecated': '{% if foo = bar %}yes{% else %}no{% endif %}'},
test_once=True)
def test_if_tag_eq_deprecated(self):
with warnings.catch_warnings(record=True) as warns:
warnings.simplefilter('always')
output = self.engine.render_to_string('if-tag-eq-deprecated')
self.assertEqual(output, 'yes')
self.assertEqual(len(warns), 1)
self.assertEqual(
str(warns[0].message),
"Operator '=' is deprecated and will be removed in Django 2.0. "
"Use '==' instead."
)
@ignore_warnings(category=RemovedInDjango20Warning)
class TestEqualitySingleEqualsSign(SimpleTestCase):
# The following tests should be changed to template.TemplateSyntaxError
# (or simply removed) when the deprecation path ends in Django 2.0.
@setup({'if-tag-eq01': '{% if foo = bar %}yes{% else %}no{% endif %}'})
def test_if_tag_eq01(self):
output = self.engine.render_to_string('if-tag-eq01', {'foo': 1})
self.assertEqual(output, 'no')
@setup({'if-tag-eq02': '{% if foo = bar %}yes{% else %}no{% endif %}'})
def test_if_tag_eq02(self):
output = self.engine.render_to_string('if-tag-eq02', {'foo': 1, 'bar': 1})
self.assertEqual(output, 'yes')
@setup({'if-tag-eq03': '{% if foo = bar %}yes{% else %}no{% endif %}'})
def test_if_tag_eq03(self):
output = self.engine.render_to_string('if-tag-eq03', {'foo': 1, 'bar': 2})
self.assertEqual(output, 'no')
@setup({'if-tag-eq04': '{% if foo == \'\' %}yes{% else %}no{% endif %}'})
def test_if_tag_eq04(self):
output = self.engine.render_to_string('if-tag-eq04')
self.assertEqual(output, 'no')

View File

@ -18,7 +18,7 @@ from django.utils.safestring import mark_safe
ROOT = os.path.dirname(os.path.abspath(upath(__file__))) ROOT = os.path.dirname(os.path.abspath(upath(__file__)))
def setup(templates, *args): def setup(templates, *args, **kwargs):
""" """
Runs test method multiple times in the following order: Runs test method multiple times in the following order:
@ -31,6 +31,9 @@ def setup(templates, *args):
True False True False
True True True True
""" """
# when testing deprecation warnings, it's useful to run just one test since
# the message won't be displayed multiple times
test_once = kwargs.get('test_once', False)
for arg in args: for arg in args:
templates.update(arg) templates.update(arg)
@ -57,6 +60,8 @@ def setup(templates, *args):
loaders=loaders, loaders=loaders,
) )
func(self) func(self)
if test_once:
return
func(self) func(self)
self.engine = Engine( self.engine = Engine(