Skip to content

Commit dcf035b

Browse files
committed
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 3c46471 commit dcf035b

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

pytest_django/plugin.py

+10
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,16 @@ def _get_origin() -> str | None:
688688
return name
689689
return None
690690

691+
def __bool__(self) -> bool:
692+
for frame_info in inspect.stack():
693+
if (
694+
frame_info.function == "resolve"
695+
and frame_info.filename.endswith("base.py")
696+
):
697+
# To go through this guard: https://github.com/django/django/blob/5.0.7/django/template/base.py#L716
698+
return True
699+
return bool(self.origin_value)
700+
691701
def __mod__(self, var: str) -> str:
692702
origin = self._get_origin()
693703
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)