Skip to content

Commit d7da5ac

Browse files
xavfernandezbluetech
authored andcommitted
fail-on-template-vars: improve compatibility with Django behavior
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.
1 parent 089843c commit d7da5ac

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

pytest_django/plugin.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,14 @@ def _get_origin() -> str | None:
693693
return name
694694
return None
695695

696+
def __bool__(self) -> bool:
697+
for frame_info in inspect.stack():
698+
if frame_info.function == "resolve" and frame_info.filename.endswith("base.py"):
699+
# To go through this guard:
700+
# https://github.com/django/django/blob/5.0.7/django/template/base.py#L716
701+
return True
702+
return bool(self.origin_value)
703+
696704
def __mod__(self, var: str) -> str:
697705
origin = self._get_origin()
698706
if origin:

tests/test_environment.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,48 @@ def test_for_invalid_template(client):
188188
)
189189

190190

191+
@pytest.mark.django_project(
192+
extra_settings="""
193+
TEMPLATE_LOADERS = (
194+
'django.template.loaders.filesystem.Loader',
195+
'django.template.loaders.app_directories.Loader',
196+
)
197+
"""
198+
)
199+
def test_invalid_template_variable_object_does_not_exists_behaves_like_an_empty_string(
200+
django_pytester: DjangoPytester,
201+
) -> None:
202+
django_pytester.create_app_file(
203+
"<div>{% if object_exists %}This should not appear{% endif %}</div>",
204+
"templates/invalid_template_base.html",
205+
)
206+
django_pytester.create_app_file(
207+
"{% include 'invalid_template_base.html' %}",
208+
"templates/invalid_template.html",
209+
)
210+
django_pytester.create_test_module(
211+
"""
212+
from django.core.exceptions import ObjectDoesNotExist
213+
from django.template.loader import render_to_string
214+
215+
import pytest
216+
217+
def fake_one_to_one_relation_missing():
218+
raise ObjectDoesNotExist()
219+
220+
def test_ignore():
221+
assert render_to_string(
222+
'invalid_template.html',
223+
{"object_exists": fake_one_to_one_relation_missing},
224+
) == "<div></div>"
225+
"""
226+
)
227+
228+
result = django_pytester.runpytest_subprocess("-s", "--fail-on-template-vars")
229+
230+
result.assert_outcomes(passed=1)
231+
232+
191233
@pytest.mark.django_project(
192234
extra_settings="""
193235
TEMPLATE_LOADERS = (

0 commit comments

Comments
 (0)