Skip to content

Commit

Permalink
fail-on-template-vars: improve compatibility with Django behavior
Browse files Browse the repository at this point in the history
With `OneToOneField`, Django raises `Model.DoesNotExist` which is
converted by its template engine to `string_if_invalid`:
https://github.com/django/django/blob/5.0.7/django/template/base.py#L932-L933

It is usually falsy, hence the need for `InvalidVarException.__bool__`
to return `bool(self.origin_value)` to be consistent with Django's
default behavior.

However to trigger `InvalidVarException` behavior and its dreaded
`InvalidVarException.__mod__`, it needs to go through this check:
https://github.com/django/django/blob/5.0.7/django/template/base.py#L716
and thus also needs to be truthy hence the stack inspecting `__bool__`
method to know what to return.
  • Loading branch information
xavfernandez committed Jul 10, 2024
1 parent 3c46471 commit 2413623
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pytest_django/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,13 @@ def _get_origin() -> str | None:
return name
return None

def __bool__(self) -> bool:
for frame_info in inspect.stack():
if frame_info.function == "resolve" and frame_info.filename.endswith("base.py"):
# To go through this guard: https://github.com/django/django/blob/5.0.7/django/template/base.py#L716
return True
return bool(self.origin_value)

def __mod__(self, var: str) -> str:
origin = self._get_origin()
if origin:
Expand Down
44 changes: 44 additions & 0 deletions tests/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,50 @@ def test_for_invalid_template(client):
)


@pytest.mark.django_project(
extra_settings="""
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
"""
)
def test_invalid_template_variable_object_does_not_exists_behaves_like_an_empty_string(
django_pytester: DjangoPytester
) -> None:
django_pytester.create_app_file(
"<div>{% if object_exists %}This should not appear{% endif %}</div>",
"templates/invalid_template_base.html",
)
django_pytester.create_app_file(
"{% include 'invalid_template_base.html' %}", "templates/invalid_template.html"
)
django_pytester.create_test_module(
"""
from django.core.exceptions import ObjectDoesNotExist
from django.template.loader import render_to_string
import pytest
def fake_one_to_one_relation_missing():
raise ObjectDoesNotExist()
def test_ignore(client):
assert render_to_string(
'invalid_template.html',
{"object_exists": fake_one_to_one_relation_missing},
) == "<div></div>"
"""
)
result = django_pytester.runpytest_subprocess("-s", "--fail-on-template-vars")

result.stdout.fnmatch_lines_random(
[
"tpkg/test_the_test.py .",
]
)


@pytest.mark.django_project(
extra_settings="""
TEMPLATE_LOADERS = (
Expand Down

0 comments on commit 2413623

Please sign in to comment.