Skip to content

Commit c48b03a

Browse files
committed
Do not fail invalid template variables with default filter
1 parent 45087ec commit c48b03a

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

docs/usage.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ You can switch it on in `pytest.ini`::
3333

3434
[pytest]
3535
FAIL_INVALID_TEMPLATE_VARS = True
36-
36+
37+
Invalid template variables will not fail the test if the variable uses the Django
38+
`default` filter, like `{{ does_not_exist:default:"ok" }}`.
39+
3740
Additional pytest.ini settings
3841
------------------------------
3942

pytest_django/plugin.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,17 @@ def __contains__(self, key):
551551
def _get_origin():
552552
stack = inspect.stack()
553553

554+
# Don't flag non-existent variables with default filter applied
555+
from django.template.defaultfilters import default as default_filter
556+
try:
557+
has_default_filter = any(
558+
filter[0] is default_filter
559+
for filter in stack[2][0].f_locals["self"].filters)
560+
except (AttributeError, IndexError, KeyError):
561+
has_default_filter = False
562+
if has_default_filter:
563+
return True, None
564+
554565
# Try to use topmost `self.origin` first (Django 1.9+, and with
555566
# TEMPLATE_DEBUG)..
556567
for f in stack[2:]:
@@ -562,7 +573,7 @@ def _get_origin():
562573
except (AttributeError, KeyError):
563574
continue
564575
if origin is not None:
565-
return origin
576+
return False, origin
566577

567578
from django.template import Template
568579

@@ -579,10 +590,14 @@ def _get_origin():
579590
# ``django.template.base.Template``
580591
template = f_locals["self"]
581592
if isinstance(template, Template):
582-
return template.name
593+
return False, template.name
594+
595+
return False, None
583596

584597
def __mod__(self, var):
585-
origin = self._get_origin()
598+
has_default_filter, origin = self._get_origin()
599+
if has_default_filter:
600+
return ""
586601
if origin:
587602
msg = "Undefined template variable '{}' in '{}'".format(var, origin)
588603
else:

tests/test_environment.py

+34-1
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,44 @@ def test_ignore(client):
112112
ROOT_URLCONF = 'tpkg.app.urls'
113113
"""
114114
)
115-
def test_invalid_template_with_default_if_none(django_testdir):
115+
def test_invalid_template_with_default(django_testdir):
116116
django_testdir.create_app_file(
117117
"""
118118
<div>{{ data.empty|default:'d' }}</div>
119119
<div>{{ data.none|default:'d' }}</div>
120+
<div>{{ data.missing|default:'d' }}</div>
121+
""",
122+
"templates/the_template.html",
123+
)
124+
django_testdir.create_test_module(
125+
"""
126+
def test_for_invalid_template():
127+
from django.shortcuts import render
128+
129+
130+
render(
131+
request=None,
132+
template_name='the_template.html',
133+
context={'data': {'empty': '', 'none': None}},
134+
)
135+
"""
136+
)
137+
result = django_testdir.runpytest_subprocess("--fail-on-template-vars")
138+
result.stdout.fnmatch_lines_random(["tpkg/test_the_test.py ."])
139+
140+
141+
@pytest.mark.django_project(
142+
extra_settings="""
143+
TEMPLATE_LOADERS = (
144+
'django.template.loaders.filesystem.Loader',
145+
'django.template.loaders.app_directories.Loader',
146+
)
147+
ROOT_URLCONF = 'tpkg.app.urls'
148+
"""
149+
)
150+
def test_invalid_template_with_default_if_none(django_testdir):
151+
django_testdir.create_app_file(
152+
"""
120153
<div>{{ data.empty|default_if_none:'d' }}</div>
121154
<div>{{ data.none|default_if_none:'d' }}</div>
122155
<div>{{ data.missing|default_if_none:'d' }}</div>

0 commit comments

Comments
 (0)