test_context.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. from unittest import mock
  2. from django.http import HttpRequest
  3. from django.template import (
  4. Context,
  5. Engine,
  6. RequestContext,
  7. Template,
  8. Variable,
  9. VariableDoesNotExist,
  10. )
  11. from django.template.context import RenderContext
  12. from django.test import RequestFactory, SimpleTestCase, override_settings
  13. class ContextTests(SimpleTestCase):
  14. def test_context(self):
  15. c = Context({"a": 1, "b": "xyzzy"})
  16. self.assertEqual(c["a"], 1)
  17. self.assertEqual(c.push(), {})
  18. c["a"] = 2
  19. self.assertEqual(c["a"], 2)
  20. self.assertEqual(c.get("a"), 2)
  21. self.assertEqual(c.pop(), {"a": 2})
  22. self.assertEqual(c["a"], 1)
  23. self.assertEqual(c.get("foo", 42), 42)
  24. self.assertEqual(c, mock.ANY)
  25. def test_push_context_manager(self):
  26. c = Context({"a": 1})
  27. with c.push():
  28. c["a"] = 2
  29. self.assertEqual(c["a"], 2)
  30. self.assertEqual(c["a"], 1)
  31. with c.push(a=3):
  32. self.assertEqual(c["a"], 3)
  33. self.assertEqual(c["a"], 1)
  34. def test_update_context_manager(self):
  35. c = Context({"a": 1})
  36. with c.update({}):
  37. c["a"] = 2
  38. self.assertEqual(c["a"], 2)
  39. self.assertEqual(c["a"], 1)
  40. with c.update({"a": 3}):
  41. self.assertEqual(c["a"], 3)
  42. self.assertEqual(c["a"], 1)
  43. def test_push_context_manager_with_context_object(self):
  44. c = Context({"a": 1})
  45. with c.push(Context({"a": 3})):
  46. self.assertEqual(c["a"], 3)
  47. self.assertEqual(c["a"], 1)
  48. def test_update_context_manager_with_context_object(self):
  49. c = Context({"a": 1})
  50. with c.update(Context({"a": 3})):
  51. self.assertEqual(c["a"], 3)
  52. self.assertEqual(c["a"], 1)
  53. def test_push_proper_layering(self):
  54. c = Context({"a": 1})
  55. c.push(Context({"b": 2}))
  56. c.push(Context({"c": 3, "d": {"z": "26"}}))
  57. self.assertEqual(
  58. c.dicts,
  59. [
  60. {"False": False, "None": None, "True": True},
  61. {"a": 1},
  62. {"b": 2},
  63. {"c": 3, "d": {"z": "26"}},
  64. ],
  65. )
  66. def test_update_proper_layering(self):
  67. c = Context({"a": 1})
  68. c.update(Context({"b": 2}))
  69. c.update(Context({"c": 3, "d": {"z": "26"}}))
  70. self.assertEqual(
  71. c.dicts,
  72. [
  73. {"False": False, "None": None, "True": True},
  74. {"a": 1},
  75. {"b": 2},
  76. {"c": 3, "d": {"z": "26"}},
  77. ],
  78. )
  79. def test_setdefault(self):
  80. c = Context()
  81. x = c.setdefault("x", 42)
  82. self.assertEqual(x, 42)
  83. self.assertEqual(c["x"], 42)
  84. x = c.setdefault("x", 100)
  85. self.assertEqual(x, 42)
  86. self.assertEqual(c["x"], 42)
  87. def test_resolve_on_context_method(self):
  88. """
  89. #17778 -- Variable shouldn't resolve RequestContext methods
  90. """
  91. empty_context = Context()
  92. with self.assertRaises(VariableDoesNotExist):
  93. Variable("no_such_variable").resolve(empty_context)
  94. with self.assertRaises(VariableDoesNotExist):
  95. Variable("new").resolve(empty_context)
  96. self.assertEqual(
  97. Variable("new").resolve(Context({"new": "foo"})),
  98. "foo",
  99. )
  100. def test_render_context(self):
  101. test_context = RenderContext({"fruit": "papaya"})
  102. # push() limits access to the topmost dict
  103. test_context.push()
  104. test_context["vegetable"] = "artichoke"
  105. self.assertEqual(list(test_context), ["vegetable"])
  106. self.assertNotIn("fruit", test_context)
  107. with self.assertRaises(KeyError):
  108. test_context["fruit"]
  109. self.assertIsNone(test_context.get("fruit"))
  110. def test_flatten_context(self):
  111. a = Context()
  112. a.update({"a": 2})
  113. a.update({"b": 4})
  114. a.update({"c": 8})
  115. self.assertEqual(
  116. a.flatten(),
  117. {"False": False, "None": None, "True": True, "a": 2, "b": 4, "c": 8},
  118. )
  119. def test_flatten_context_with_context(self):
  120. """
  121. Context.push() with a Context argument should work.
  122. """
  123. a = Context({"a": 2})
  124. a.push(Context({"z": "8"}))
  125. self.assertEqual(
  126. a.flatten(),
  127. {
  128. "False": False,
  129. "None": None,
  130. "True": True,
  131. "a": 2,
  132. "z": "8",
  133. },
  134. )
  135. def test_flatten_context_with_context_copy(self):
  136. ctx1 = Context({"a": 2})
  137. ctx2 = ctx1.new(Context({"b": 4}))
  138. self.assertEqual(
  139. ctx2.dicts, [{"True": True, "False": False, "None": None}, {"b": 4}]
  140. )
  141. self.assertEqual(
  142. ctx2.flatten(),
  143. {"False": False, "None": None, "True": True, "b": 4},
  144. )
  145. def test_context_comparable(self):
  146. """
  147. #21765 -- equality comparison should work
  148. """
  149. test_data = {"x": "y", "v": "z", "d": {"o": object, "a": "b"}}
  150. self.assertEqual(Context(test_data), Context(test_data))
  151. a = Context()
  152. b = Context()
  153. self.assertEqual(a, b)
  154. # update only a
  155. a.update({"a": 1})
  156. self.assertNotEqual(a, b)
  157. # update both to check regression
  158. a.update({"c": 3})
  159. b.update({"c": 3})
  160. self.assertNotEqual(a, b)
  161. # make contexts equals again
  162. b.update({"a": 1})
  163. self.assertEqual(a, b)
  164. def test_copy_request_context_twice(self):
  165. """
  166. #24273 -- Copy twice shouldn't raise an exception
  167. """
  168. RequestContext(HttpRequest()).new().new()
  169. def test_set_upward(self):
  170. c = Context({"a": 1})
  171. c.set_upward("a", 2)
  172. self.assertEqual(c.get("a"), 2)
  173. def test_set_upward_empty_context(self):
  174. empty_context = Context()
  175. empty_context.set_upward("a", 1)
  176. self.assertEqual(empty_context.get("a"), 1)
  177. def test_set_upward_with_push(self):
  178. """
  179. The highest context which has the given key is used.
  180. """
  181. c = Context({"a": 1})
  182. c.push({"a": 2})
  183. c.set_upward("a", 3)
  184. self.assertEqual(c.get("a"), 3)
  185. c.pop()
  186. self.assertEqual(c.get("a"), 1)
  187. def test_set_upward_with_push_no_match(self):
  188. """
  189. The highest context is used if the given key isn't found.
  190. """
  191. c = Context({"b": 1})
  192. c.push({"b": 2})
  193. c.set_upward("a", 2)
  194. self.assertEqual(len(c.dicts), 3)
  195. self.assertEqual(c.dicts[-1]["a"], 2)
  196. def context_process_returning_none(request):
  197. return None
  198. class RequestContextTests(SimpleTestCase):
  199. request_factory = RequestFactory()
  200. def test_include_only(self):
  201. """
  202. #15721 -- ``{% include %}`` and ``RequestContext`` should work
  203. together.
  204. """
  205. engine = Engine(
  206. loaders=[
  207. (
  208. "django.template.loaders.locmem.Loader",
  209. {
  210. "child": '{{ var|default:"none" }}',
  211. },
  212. ),
  213. ]
  214. )
  215. request = self.request_factory.get("/")
  216. ctx = RequestContext(request, {"var": "parent"})
  217. self.assertEqual(
  218. engine.from_string('{% include "child" %}').render(ctx), "parent"
  219. )
  220. self.assertEqual(
  221. engine.from_string('{% include "child" only %}').render(ctx), "none"
  222. )
  223. def test_stack_size(self):
  224. """Optimized RequestContext construction (#7116)."""
  225. request = self.request_factory.get("/")
  226. ctx = RequestContext(request, {})
  227. # The stack contains 4 items:
  228. # [builtins, supplied context, context processor, empty dict]
  229. self.assertEqual(len(ctx.dicts), 4)
  230. def test_context_comparable(self):
  231. # Create an engine without any context processors.
  232. test_data = {"x": "y", "v": "z", "d": {"o": object, "a": "b"}}
  233. # test comparing RequestContext to prevent problems if somebody
  234. # adds __eq__ in the future
  235. request = self.request_factory.get("/")
  236. self.assertEqual(
  237. RequestContext(request, dict_=test_data),
  238. RequestContext(request, dict_=test_data),
  239. )
  240. def test_modify_context_and_render(self):
  241. template = Template("{{ foo }}")
  242. request = self.request_factory.get("/")
  243. context = RequestContext(request, {})
  244. context["foo"] = "foo"
  245. self.assertEqual(template.render(context), "foo")
  246. @override_settings(
  247. TEMPLATES=[
  248. {
  249. "BACKEND": "django.template.backends.django.DjangoTemplates",
  250. "OPTIONS": {
  251. "context_processors": [
  252. "django.template.context_processors.request",
  253. "template_tests.test_context.context_process_returning_none",
  254. ],
  255. },
  256. }
  257. ],
  258. )
  259. def test_template_context_processor_returning_none(self):
  260. request_context = RequestContext(HttpRequest())
  261. msg = (
  262. "Context processor context_process_returning_none didn't return a "
  263. "dictionary."
  264. )
  265. with self.assertRaisesMessage(TypeError, msg):
  266. with request_context.bind_template(Template("")):
  267. pass