Skip to content

Commit 8e2c999

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 19605d7 commit 8e2c999

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

pytest_django/plugin.py

+7
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,13 @@ 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: https://github.com/django/django/blob/5.0.7/django/template/base.py#L716
700+
return True
701+
return bool(self.origin_value)
702+
696703
def __mod__(self, var: str) -> str:
697704
origin = self._get_origin()
698705
if origin:

tests/test_environment.py

+44
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,50 @@ 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' %}", "templates/invalid_template.html"
208+
)
209+
django_pytester.create_test_module(
210+
"""
211+
from django.core.exceptions import ObjectDoesNotExist
212+
from django.template.loader import render_to_string
213+
214+
import pytest
215+
216+
def fake_one_to_one_relation_missing():
217+
raise ObjectDoesNotExist()
218+
219+
def test_ignore(client):
220+
assert render_to_string(
221+
'invalid_template.html',
222+
{"object_exists": fake_one_to_one_relation_missing},
223+
) == "<div></div>"
224+
"""
225+
)
226+
result = django_pytester.runpytest_subprocess("-s", "--fail-on-template-vars")
227+
228+
result.stdout.fnmatch_lines_random(
229+
[
230+
"tpkg/test_the_test.py .",
231+
]
232+
)
233+
234+
191235
@pytest.mark.django_project(
192236
extra_settings="""
193237
TEMPLATE_LOADERS = (

0 commit comments

Comments
 (0)