mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
8d7b1423f8
super objects are copyable on Python 3.14+:
5ca4e34bc1
and can no longer be used in BaseContext.__copy__().
325 lines
9.6 KiB
Python
325 lines
9.6 KiB
Python
from copy import copy
|
|
from unittest import mock
|
|
|
|
from django.http import HttpRequest
|
|
from django.template import (
|
|
Context,
|
|
Engine,
|
|
RequestContext,
|
|
Template,
|
|
Variable,
|
|
VariableDoesNotExist,
|
|
)
|
|
from django.template.context import RenderContext
|
|
from django.test import RequestFactory, SimpleTestCase, override_settings
|
|
|
|
|
|
class ContextTests(SimpleTestCase):
|
|
def test_context(self):
|
|
c = Context({"a": 1, "b": "xyzzy"})
|
|
self.assertEqual(c["a"], 1)
|
|
self.assertEqual(c.push(), {})
|
|
c["a"] = 2
|
|
self.assertEqual(c["a"], 2)
|
|
self.assertEqual(c.get("a"), 2)
|
|
self.assertEqual(c.pop(), {"a": 2})
|
|
self.assertEqual(c["a"], 1)
|
|
self.assertEqual(c.get("foo", 42), 42)
|
|
self.assertEqual(c, mock.ANY)
|
|
|
|
def test_push_context_manager(self):
|
|
c = Context({"a": 1})
|
|
with c.push():
|
|
c["a"] = 2
|
|
self.assertEqual(c["a"], 2)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
with c.push(a=3):
|
|
self.assertEqual(c["a"], 3)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
def test_update_context_manager(self):
|
|
c = Context({"a": 1})
|
|
with c.update({}):
|
|
c["a"] = 2
|
|
self.assertEqual(c["a"], 2)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
with c.update({"a": 3}):
|
|
self.assertEqual(c["a"], 3)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
def test_push_context_manager_with_context_object(self):
|
|
c = Context({"a": 1})
|
|
with c.push(Context({"a": 3})):
|
|
self.assertEqual(c["a"], 3)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
def test_update_context_manager_with_context_object(self):
|
|
c = Context({"a": 1})
|
|
with c.update(Context({"a": 3})):
|
|
self.assertEqual(c["a"], 3)
|
|
self.assertEqual(c["a"], 1)
|
|
|
|
def test_push_proper_layering(self):
|
|
c = Context({"a": 1})
|
|
c.push(Context({"b": 2}))
|
|
c.push(Context({"c": 3, "d": {"z": "26"}}))
|
|
self.assertEqual(
|
|
c.dicts,
|
|
[
|
|
{"False": False, "None": None, "True": True},
|
|
{"a": 1},
|
|
{"b": 2},
|
|
{"c": 3, "d": {"z": "26"}},
|
|
],
|
|
)
|
|
|
|
def test_update_proper_layering(self):
|
|
c = Context({"a": 1})
|
|
c.update(Context({"b": 2}))
|
|
c.update(Context({"c": 3, "d": {"z": "26"}}))
|
|
self.assertEqual(
|
|
c.dicts,
|
|
[
|
|
{"False": False, "None": None, "True": True},
|
|
{"a": 1},
|
|
{"b": 2},
|
|
{"c": 3, "d": {"z": "26"}},
|
|
],
|
|
)
|
|
|
|
def test_setdefault(self):
|
|
c = Context()
|
|
|
|
x = c.setdefault("x", 42)
|
|
self.assertEqual(x, 42)
|
|
self.assertEqual(c["x"], 42)
|
|
|
|
x = c.setdefault("x", 100)
|
|
self.assertEqual(x, 42)
|
|
self.assertEqual(c["x"], 42)
|
|
|
|
def test_resolve_on_context_method(self):
|
|
"""
|
|
#17778 -- Variable shouldn't resolve RequestContext methods
|
|
"""
|
|
empty_context = Context()
|
|
|
|
with self.assertRaises(VariableDoesNotExist):
|
|
Variable("no_such_variable").resolve(empty_context)
|
|
|
|
with self.assertRaises(VariableDoesNotExist):
|
|
Variable("new").resolve(empty_context)
|
|
|
|
self.assertEqual(
|
|
Variable("new").resolve(Context({"new": "foo"})),
|
|
"foo",
|
|
)
|
|
|
|
def test_render_context(self):
|
|
test_context = RenderContext({"fruit": "papaya"})
|
|
|
|
# push() limits access to the topmost dict
|
|
test_context.push()
|
|
|
|
test_context["vegetable"] = "artichoke"
|
|
self.assertEqual(list(test_context), ["vegetable"])
|
|
|
|
self.assertNotIn("fruit", test_context)
|
|
with self.assertRaises(KeyError):
|
|
test_context["fruit"]
|
|
self.assertIsNone(test_context.get("fruit"))
|
|
|
|
def test_flatten_context(self):
|
|
a = Context()
|
|
a.update({"a": 2})
|
|
a.update({"b": 4})
|
|
a.update({"c": 8})
|
|
|
|
self.assertEqual(
|
|
a.flatten(),
|
|
{"False": False, "None": None, "True": True, "a": 2, "b": 4, "c": 8},
|
|
)
|
|
|
|
def test_flatten_context_with_context(self):
|
|
"""
|
|
Context.push() with a Context argument should work.
|
|
"""
|
|
a = Context({"a": 2})
|
|
a.push(Context({"z": "8"}))
|
|
self.assertEqual(
|
|
a.flatten(),
|
|
{
|
|
"False": False,
|
|
"None": None,
|
|
"True": True,
|
|
"a": 2,
|
|
"z": "8",
|
|
},
|
|
)
|
|
|
|
def test_flatten_context_with_context_copy(self):
|
|
ctx1 = Context({"a": 2})
|
|
ctx2 = ctx1.new(Context({"b": 4}))
|
|
self.assertEqual(
|
|
ctx2.dicts, [{"True": True, "False": False, "None": None}, {"b": 4}]
|
|
)
|
|
self.assertEqual(
|
|
ctx2.flatten(),
|
|
{"False": False, "None": None, "True": True, "b": 4},
|
|
)
|
|
|
|
def test_context_comparable(self):
|
|
"""
|
|
#21765 -- equality comparison should work
|
|
"""
|
|
|
|
test_data = {"x": "y", "v": "z", "d": {"o": object, "a": "b"}}
|
|
|
|
self.assertEqual(Context(test_data), Context(test_data))
|
|
|
|
a = Context()
|
|
b = Context()
|
|
self.assertEqual(a, b)
|
|
|
|
# update only a
|
|
a.update({"a": 1})
|
|
self.assertNotEqual(a, b)
|
|
|
|
# update both to check regression
|
|
a.update({"c": 3})
|
|
b.update({"c": 3})
|
|
self.assertNotEqual(a, b)
|
|
|
|
# make contexts equals again
|
|
b.update({"a": 1})
|
|
self.assertEqual(a, b)
|
|
|
|
def test_copy_request_context_twice(self):
|
|
"""
|
|
#24273 -- Copy twice shouldn't raise an exception
|
|
"""
|
|
RequestContext(HttpRequest()).new().new()
|
|
|
|
def test_set_upward(self):
|
|
c = Context({"a": 1})
|
|
c.set_upward("a", 2)
|
|
self.assertEqual(c.get("a"), 2)
|
|
|
|
def test_set_upward_empty_context(self):
|
|
empty_context = Context()
|
|
empty_context.set_upward("a", 1)
|
|
self.assertEqual(empty_context.get("a"), 1)
|
|
|
|
def test_set_upward_with_push(self):
|
|
"""
|
|
The highest context which has the given key is used.
|
|
"""
|
|
c = Context({"a": 1})
|
|
c.push({"a": 2})
|
|
c.set_upward("a", 3)
|
|
self.assertEqual(c.get("a"), 3)
|
|
c.pop()
|
|
self.assertEqual(c.get("a"), 1)
|
|
|
|
def test_set_upward_with_push_no_match(self):
|
|
"""
|
|
The highest context is used if the given key isn't found.
|
|
"""
|
|
c = Context({"b": 1})
|
|
c.push({"b": 2})
|
|
c.set_upward("a", 2)
|
|
self.assertEqual(len(c.dicts), 3)
|
|
self.assertEqual(c.dicts[-1]["a"], 2)
|
|
|
|
|
|
def context_process_returning_none(request):
|
|
return None
|
|
|
|
|
|
class RequestContextTests(SimpleTestCase):
|
|
request_factory = RequestFactory()
|
|
|
|
def test_include_only(self):
|
|
"""
|
|
#15721 -- ``{% include %}`` and ``RequestContext`` should work
|
|
together.
|
|
"""
|
|
engine = Engine(
|
|
loaders=[
|
|
(
|
|
"django.template.loaders.locmem.Loader",
|
|
{
|
|
"child": '{{ var|default:"none" }}',
|
|
},
|
|
),
|
|
]
|
|
)
|
|
request = self.request_factory.get("/")
|
|
ctx = RequestContext(request, {"var": "parent"})
|
|
self.assertEqual(
|
|
engine.from_string('{% include "child" %}').render(ctx), "parent"
|
|
)
|
|
self.assertEqual(
|
|
engine.from_string('{% include "child" only %}').render(ctx), "none"
|
|
)
|
|
|
|
def test_stack_size(self):
|
|
"""Optimized RequestContext construction (#7116)."""
|
|
request = self.request_factory.get("/")
|
|
ctx = RequestContext(request, {})
|
|
# The stack contains 4 items:
|
|
# [builtins, supplied context, context processor, empty dict]
|
|
self.assertEqual(len(ctx.dicts), 4)
|
|
|
|
def test_context_comparable(self):
|
|
# Create an engine without any context processors.
|
|
test_data = {"x": "y", "v": "z", "d": {"o": object, "a": "b"}}
|
|
|
|
# test comparing RequestContext to prevent problems if somebody
|
|
# adds __eq__ in the future
|
|
request = self.request_factory.get("/")
|
|
|
|
self.assertEqual(
|
|
RequestContext(request, dict_=test_data),
|
|
RequestContext(request, dict_=test_data),
|
|
)
|
|
|
|
def test_modify_context_and_render(self):
|
|
template = Template("{{ foo }}")
|
|
request = self.request_factory.get("/")
|
|
context = RequestContext(request, {})
|
|
context["foo"] = "foo"
|
|
self.assertEqual(template.render(context), "foo")
|
|
|
|
@override_settings(
|
|
TEMPLATES=[
|
|
{
|
|
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
|
"OPTIONS": {
|
|
"context_processors": [
|
|
"django.template.context_processors.request",
|
|
"template_tests.test_context.context_process_returning_none",
|
|
],
|
|
},
|
|
}
|
|
],
|
|
)
|
|
def test_template_context_processor_returning_none(self):
|
|
request_context = RequestContext(HttpRequest())
|
|
msg = (
|
|
"Context processor context_process_returning_none didn't return a "
|
|
"dictionary."
|
|
)
|
|
with self.assertRaisesMessage(TypeError, msg):
|
|
with request_context.bind_template(Template("")):
|
|
pass
|
|
|
|
def test_context_copyable(self):
|
|
request_context = RequestContext(HttpRequest())
|
|
request_context_copy = copy(request_context)
|
|
self.assertIsInstance(request_context_copy, RequestContext)
|
|
self.assertEqual(request_context_copy.dicts, request_context.dicts)
|
|
self.assertIsNot(request_context_copy.dicts, request_context.dicts)
|