Skip to content

Commit

Permalink
Do not fail invalid template variables with default filter
Browse files Browse the repository at this point in the history
  • Loading branch information
jcushman committed Apr 21, 2021
1 parent 45087ec commit 826be76
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
5 changes: 4 additions & 1 deletion docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ You can switch it on in `pytest.ini`::

[pytest]
FAIL_INVALID_TEMPLATE_VARS = True

Invalid template variables will not fail the test if the variable uses the Django
`default` filter, like `{{ does_not_exist:default:"ok" }}`.

Additional pytest.ini settings
------------------------------

Expand Down
21 changes: 18 additions & 3 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,17 @@ def __contains__(self, key):
def _get_origin():
stack = inspect.stack()

# Don't flag non-existent variables with default filter applied.
from django.template.defaultfilters import default as default_filter
try:
has_default_filter = any(
filter[0] is default_filter
for filter in stack[2][0].f_locals["self"].filters)
except (AttributeError, IndexError, KeyError):
has_default_filter = False
if has_default_filter:
return True, None

# Try to use topmost `self.origin` first (Django 1.9+, and with
# TEMPLATE_DEBUG)..
for f in stack[2:]:
Expand All @@ -562,7 +573,7 @@ def _get_origin():
except (AttributeError, KeyError):
continue
if origin is not None:
return origin
return False, origin

from django.template import Template

Expand All @@ -579,10 +590,14 @@ def _get_origin():
# ``django.template.base.Template``
template = f_locals["self"]
if isinstance(template, Template):
return template.name
return False, template.name

return False, None

def __mod__(self, var):
origin = self._get_origin()
has_default_filter, origin = self._get_origin()
if has_default_filter:
return ""
if origin:
msg = "Undefined template variable '{}' in '{}'".format(var, origin)
else:
Expand Down
35 changes: 34 additions & 1 deletion tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,44 @@ def test_ignore(client):
ROOT_URLCONF = 'tpkg.app.urls'
"""
)
def test_invalid_template_with_default_if_none(django_testdir):
def test_invalid_template_with_default(django_testdir):
django_testdir.create_app_file(
"""
<div>{{ data.empty|default:'d' }}</div>
<div>{{ data.none|default:'d' }}</div>
<div>{{ data.missing|default:'d' }}</div>
""",
"templates/the_template.html",
)
django_testdir.create_test_module(
"""
def test_for_invalid_template():
from django.shortcuts import render
render(
request=None,
template_name='the_template.html',
context={'data': {'empty': '', 'none': None}},
)
"""
)
result = django_testdir.runpytest_subprocess("--fail-on-template-vars")
result.stdout.fnmatch_lines_random(["tpkg/test_the_test.py ."])


@pytest.mark.django_project(
extra_settings="""
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
ROOT_URLCONF = 'tpkg.app.urls'
"""
)
def test_invalid_template_with_default_if_none(django_testdir):
django_testdir.create_app_file(
"""
<div>{{ data.empty|default_if_none:'d' }}</div>
<div>{{ data.none|default_if_none:'d' }}</div>
<div>{{ data.missing|default_if_none:'d' }}</div>
Expand Down

0 comments on commit 826be76

Please sign in to comment.