1
0
mirror of https://github.com/django/django.git synced 2025-09-09 18:49:11 +00:00

Refs #36559 -- Ran template partial source tests in debug mode only.

Added a warning for accessing PartialTemplate.source when debugging is disabled.
Thanks Sarah Boyce for the idea.
This commit is contained in:
farhan 2025-09-02 14:59:30 -04:00 committed by Jacob Walls
parent f0c05a40d2
commit 3485599ef0
3 changed files with 153 additions and 65 deletions

View File

@ -53,6 +53,7 @@ times with multiple contexts)
import inspect
import logging
import re
import warnings
from enum import Enum
from django.template.context import BaseContext
@ -329,6 +330,13 @@ class PartialTemplate:
@property
def source(self):
template = self.origin.loader.get_template(self.origin.template_name)
if not template.engine.debug:
warnings.warn(
"PartialTemplate.source is only available when template "
"debugging is enabled.",
RuntimeWarning,
stacklevel=2,
)
return self.find_partial_source(template.source, self.name)
def _render(self, context):

View File

@ -4,7 +4,9 @@ from unittest import mock
from django.http import HttpResponse
from django.template import (
Context,
NodeList,
Origin,
PartialTemplate,
Template,
TemplateDoesNotExist,
TemplateSyntaxError,
@ -15,6 +17,8 @@ from django.template.loader import render_to_string
from django.test import TestCase, override_settings
from django.urls import path, reverse
from .utils import setup
engine = engines["django"]
@ -30,18 +34,30 @@ class PartialTagsTests(TestCase):
def test_template_source_is_correct(self):
partial = engine.get_template("partial_examples.html#test-partial")
self.assertEqual(
partial.template.source,
"{% partialdef test-partial %}\nTEST-PARTIAL-CONTENT\n{% endpartialdef %}",
msg = (
"PartialTemplate.source is only available when "
"template debugging is enabled."
)
with self.assertRaisesMessage(RuntimeWarning, msg):
self.assertEqual(
partial.template.source,
"{% partialdef test-partial %}\n"
"TEST-PARTIAL-CONTENT\n"
"{% endpartialdef %}",
)
def test_template_source_inline_is_correct(self):
partial = engine.get_template("partial_examples.html#inline-partial")
self.assertEqual(
partial.template.source,
"{% partialdef inline-partial inline %}\nINLINE-CONTENT\n"
"{% endpartialdef %}",
msg = (
"PartialTemplate.source is only available when "
"template debugging is enabled."
)
with self.assertRaisesMessage(RuntimeWarning, msg):
self.assertEqual(
partial.template.source,
"{% partialdef inline-partial inline %}\nINLINE-CONTENT\n"
"{% endpartialdef %}",
)
def test_full_template_from_loader(self):
template = engine.get_template("partial_examples.html")
@ -149,6 +165,20 @@ class PartialTagsTests(TestCase):
rendered_content = template_with_partial.render({})
self.assertEqual("TEST-PARTIAL-CONTENT", rendered_content.strip())
def test_template_source_warning(self):
partial = engine.get_template("partial_examples.html#test-partial")
with self.assertWarnsMessage(
RuntimeWarning,
"PartialTemplate.source is only available when template "
"debugging is enabled.",
):
self.assertEqual(
partial.template.source,
"{% partialdef test-partial %}\n"
"TEST-PARTIAL-CONTENT\n"
"{% endpartialdef %}",
)
class RobustPartialHandlingTests(TestCase):
@ -219,8 +249,18 @@ class RobustPartialHandlingTests(TestCase):
class FindPartialSourceTests(TestCase):
@setup(
{
"partial_source_success_template": (
"{% partialdef test-partial %}\n"
"TEST-PARTIAL-CONTENT\n"
"{% endpartialdef %}\n"
),
},
debug_only=True,
)
def test_find_partial_source_success(self):
template = engine.get_template("partial_examples.html").template
template = self.engine.get_template("partial_source_success_template")
partial_proxy = template.extra_data["partials"]["test-partial"]
expected = """{% partialdef test-partial %}
@ -228,8 +268,18 @@ TEST-PARTIAL-CONTENT
{% endpartialdef %}"""
self.assertEqual(partial_proxy.source.strip(), expected.strip())
@setup(
{
"partial_source_with_inline_template": (
"{% partialdef inline-partial inline %}\n"
"INLINE-CONTENT\n"
"{% endpartialdef %}\n"
),
},
debug_only=True,
)
def test_find_partial_source_with_inline(self):
template = engine.get_template("partial_examples.html").template
template = self.engine.get_template("partial_source_with_inline_template")
partial_proxy = template.extra_data["partials"]["inline-partial"]
expected = """{% partialdef inline-partial inline %}
@ -237,38 +287,38 @@ INLINE-CONTENT
{% endpartialdef %}"""
self.assertEqual(partial_proxy.source.strip(), expected.strip())
def test_find_partial_source_nonexistent_partial(self):
template = engine.get_template("partial_examples.html").template
partial_proxy = template.extra_data["partials"]["test-partial"]
result = partial_proxy.find_partial_source(
template.source, "nonexistent-partial"
)
self.assertEqual(result, "")
@setup(
{
"empty_partial_template": ("{% partialdef empty %}{% endpartialdef %}"),
},
debug_only=True,
)
def test_find_partial_source_empty_partial(self):
template_source = "{% partialdef empty %}{% endpartialdef %}"
template = Template(template_source)
template = self.engine.get_template("empty_partial_template")
partial_proxy = template.extra_data["partials"]["empty"]
result = partial_proxy.find_partial_source(template_source, "empty")
result = partial_proxy.find_partial_source(template.source, "empty")
self.assertEqual(result, "{% partialdef empty %}{% endpartialdef %}")
@setup(
{
"consecutive_partials_template": (
"{% partialdef empty %}{% endpartialdef %}"
"{% partialdef other %}...{% endpartialdef %}"
),
},
debug_only=True,
)
def test_find_partial_source_multiple_consecutive_partials(self):
template_source = (
"{% partialdef empty %}{% endpartialdef %}"
"{% partialdef other %}...{% endpartialdef %}"
)
template = Template(template_source)
template = self.engine.get_template("consecutive_partials_template")
empty_proxy = template.extra_data["partials"]["empty"]
other_proxy = template.extra_data["partials"]["other"]
empty_result = empty_proxy.find_partial_source(template_source, "empty")
empty_result = empty_proxy.find_partial_source(template.source, "empty")
self.assertEqual(empty_result, "{% partialdef empty %}{% endpartialdef %}")
other_result = other_proxy.find_partial_source(template_source, "other")
other_result = other_proxy.find_partial_source(template.source, "other")
self.assertEqual(other_result, "{% partialdef other %}...{% endpartialdef %}")
def test_partials_with_duplicate_names(self):
@ -306,28 +356,40 @@ INLINE-CONTENT
):
Template(template_source, origin=Origin(name="template.html"))
@setup(
{
"named_end_tag_template": (
"{% partialdef thing %}CONTENT{% endpartialdef thing %}"
),
},
debug_only=True,
)
def test_find_partial_source_supports_named_end_tag(self):
template_source = "{% partialdef thing %}CONTENT{% endpartialdef thing %}"
template = Template(template_source)
template = self.engine.get_template("named_end_tag_template")
partial_proxy = template.extra_data["partials"]["thing"]
result = partial_proxy.find_partial_source(template_source, "thing")
result = partial_proxy.find_partial_source(template.source, "thing")
self.assertEqual(
result, "{% partialdef thing %}CONTENT{% endpartialdef thing %}"
)
@setup(
{
"nested_partials_basic_template": (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef %}"
"{% endpartialdef %}"
),
},
debug_only=True,
)
def test_find_partial_source_supports_nested_partials(self):
template_source = (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef %}"
"{% endpartialdef %}"
)
template = Template(template_source)
template = self.engine.get_template("nested_partials_basic_template")
empty_proxy = template.extra_data["partials"]["outer"]
other_proxy = template.extra_data["partials"]["inner"]
outer_result = empty_proxy.find_partial_source(template_source, "outer")
outer_result = empty_proxy.find_partial_source(template.source, "outer")
self.assertEqual(
outer_result,
(
@ -336,21 +398,26 @@ INLINE-CONTENT
),
)
inner_result = other_proxy.find_partial_source(template_source, "inner")
inner_result = other_proxy.find_partial_source(template.source, "inner")
self.assertEqual(inner_result, "{% partialdef inner %}...{% endpartialdef %}")
@setup(
{
"nested_partials_named_end_template": (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef inner %}"
"{% endpartialdef outer %}"
),
},
debug_only=True,
)
def test_find_partial_source_supports_nested_partials_and_named_end_tags(self):
template_source = (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef inner %}"
"{% endpartialdef outer %}"
)
template = Template(template_source)
template = self.engine.get_template("nested_partials_named_end_template")
empty_proxy = template.extra_data["partials"]["outer"]
other_proxy = template.extra_data["partials"]["inner"]
outer_result = empty_proxy.find_partial_source(template_source, "outer")
outer_result = empty_proxy.find_partial_source(template.source, "outer")
self.assertEqual(
outer_result,
(
@ -359,23 +426,28 @@ INLINE-CONTENT
),
)
inner_result = other_proxy.find_partial_source(template_source, "inner")
inner_result = other_proxy.find_partial_source(template.source, "inner")
self.assertEqual(
inner_result, "{% partialdef inner %}...{% endpartialdef inner %}"
)
@setup(
{
"nested_partials_mixed_end_1_template": (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef %}"
"{% endpartialdef outer %}"
),
},
debug_only=True,
)
def test_find_partial_source_supports_nested_partials_and_mixed_end_tags_1(self):
template_source = (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef %}"
"{% endpartialdef outer %}"
)
template = Template(template_source)
template = self.engine.get_template("nested_partials_mixed_end_1_template")
empty_proxy = template.extra_data["partials"]["outer"]
other_proxy = template.extra_data["partials"]["inner"]
outer_result = empty_proxy.find_partial_source(template_source, "outer")
outer_result = empty_proxy.find_partial_source(template.source, "outer")
self.assertEqual(
outer_result,
(
@ -384,21 +456,26 @@ INLINE-CONTENT
),
)
inner_result = other_proxy.find_partial_source(template_source, "inner")
inner_result = other_proxy.find_partial_source(template.source, "inner")
self.assertEqual(inner_result, "{% partialdef inner %}...{% endpartialdef %}")
@setup(
{
"nested_partials_mixed_end_2_template": (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef inner %}"
"{% endpartialdef %}"
),
},
debug_only=True,
)
def test_find_partial_source_supports_nested_partials_and_mixed_end_tags_2(self):
template_source = (
"{% partialdef outer %}"
"{% partialdef inner %}...{% endpartialdef inner %}"
"{% endpartialdef %}"
)
template = Template(template_source)
template = self.engine.get_template("nested_partials_mixed_end_2_template")
empty_proxy = template.extra_data["partials"]["outer"]
other_proxy = template.extra_data["partials"]["inner"]
outer_result = empty_proxy.find_partial_source(template_source, "outer")
outer_result = empty_proxy.find_partial_source(template.source, "outer")
self.assertEqual(
outer_result,
(
@ -407,7 +484,7 @@ INLINE-CONTENT
),
)
inner_result = other_proxy.find_partial_source(template_source, "inner")
inner_result = other_proxy.find_partial_source(template.source, "inner")
self.assertEqual(
inner_result, "{% partialdef inner %}...{% endpartialdef inner %}"
)

View File

@ -9,7 +9,7 @@ ROOT = os.path.dirname(os.path.abspath(__file__))
TEMPLATE_DIR = os.path.join(ROOT, "templates")
def setup(templates, *args, test_once=False):
def setup(templates, *args, test_once=False, debug_only=False):
"""
Runs test method multiple times in the following order:
@ -54,11 +54,14 @@ def setup(templates, *args, test_once=False):
self.engine = Engine(
libraries=libraries,
loaders=loaders,
debug=debug_only,
)
func(self)
if test_once:
return
func(self)
if debug_only:
return
self.engine = Engine(
libraries=libraries,