Skip to content

Commit 10bc05f

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

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-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

+16-3
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,15 @@ 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(filter[0] is default_filter for filter in stack[2][0].f_locals["self"].filters)
558+
except (AttributeError, IndexError, KeyError):
559+
has_default_filter = False
560+
if has_default_filter:
561+
return True, None
562+
554563
# Try to use topmost `self.origin` first (Django 1.9+, and with
555564
# TEMPLATE_DEBUG)..
556565
for f in stack[2:]:
@@ -562,7 +571,7 @@ def _get_origin():
562571
except (AttributeError, KeyError):
563572
continue
564573
if origin is not None:
565-
return origin
574+
return False, origin
566575

567576
from django.template import Template
568577

@@ -579,10 +588,14 @@ def _get_origin():
579588
# ``django.template.base.Template``
580589
template = f_locals["self"]
581590
if isinstance(template, Template):
582-
return template.name
591+
return False, template.name
592+
593+
return False, None
583594

584595
def __mod__(self, var):
585-
origin = self._get_origin()
596+
has_default_filter, origin = self._get_origin()
597+
if has_default_filter:
598+
return ""
586599
if origin:
587600
msg = "Undefined template variable '{}' in '{}'".format(var, origin)
588601
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)