test_callables.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from unittest import TestCase
  2. from django.template import Context, Engine
  3. class CallableVariablesTests(TestCase):
  4. @classmethod
  5. def setUpClass(cls):
  6. cls.engine = Engine()
  7. super(CallableVariablesTests, cls).setUpClass()
  8. def test_callable(self):
  9. class Doodad:
  10. def __init__(self, value):
  11. self.num_calls = 0
  12. self.value = value
  13. def __call__(self):
  14. self.num_calls += 1
  15. return {"the_value": self.value}
  16. my_doodad = Doodad(42)
  17. c = Context({"my_doodad": my_doodad})
  18. # We can't access ``my_doodad.value`` in the template, because
  19. # ``my_doodad.__call__`` will be invoked first, yielding a dictionary
  20. # without a key ``value``.
  21. t = self.engine.from_string('{{ my_doodad.value }}')
  22. self.assertEqual(t.render(c), '')
  23. # We can confirm that the doodad has been called
  24. self.assertEqual(my_doodad.num_calls, 1)
  25. # But we can access keys on the dict that's returned
  26. # by ``__call__``, instead.
  27. t = self.engine.from_string('{{ my_doodad.the_value }}')
  28. self.assertEqual(t.render(c), '42')
  29. self.assertEqual(my_doodad.num_calls, 2)
  30. def test_alters_data(self):
  31. class Doodad:
  32. alters_data = True
  33. def __init__(self, value):
  34. self.num_calls = 0
  35. self.value = value
  36. def __call__(self):
  37. self.num_calls += 1
  38. return {"the_value": self.value}
  39. my_doodad = Doodad(42)
  40. c = Context({"my_doodad": my_doodad})
  41. # Since ``my_doodad.alters_data`` is True, the template system will not
  42. # try to call our doodad but will use string_if_invalid
  43. t = self.engine.from_string('{{ my_doodad.value }}')
  44. self.assertEqual(t.render(c), '')
  45. t = self.engine.from_string('{{ my_doodad.the_value }}')
  46. self.assertEqual(t.render(c), '')
  47. # Double-check that the object was really never called during the
  48. # template rendering.
  49. self.assertEqual(my_doodad.num_calls, 0)
  50. def test_do_not_call(self):
  51. class Doodad:
  52. do_not_call_in_templates = True
  53. def __init__(self, value):
  54. self.num_calls = 0
  55. self.value = value
  56. def __call__(self):
  57. self.num_calls += 1
  58. return {"the_value": self.value}
  59. my_doodad = Doodad(42)
  60. c = Context({"my_doodad": my_doodad})
  61. # Since ``my_doodad.do_not_call_in_templates`` is True, the template
  62. # system will not try to call our doodad. We can access its attributes
  63. # as normal, and we don't have access to the dict that it returns when
  64. # called.
  65. t = self.engine.from_string('{{ my_doodad.value }}')
  66. self.assertEqual(t.render(c), '42')
  67. t = self.engine.from_string('{{ my_doodad.the_value }}')
  68. self.assertEqual(t.render(c), '')
  69. # Double-check that the object was really never called during the
  70. # template rendering.
  71. self.assertEqual(my_doodad.num_calls, 0)
  72. def test_do_not_call_and_alters_data(self):
  73. # If we combine ``alters_data`` and ``do_not_call_in_templates``, the
  74. # ``alters_data`` attribute will not make any difference in the
  75. # template system's behavior.
  76. class Doodad:
  77. do_not_call_in_templates = True
  78. alters_data = True
  79. def __init__(self, value):
  80. self.num_calls = 0
  81. self.value = value
  82. def __call__(self):
  83. self.num_calls += 1
  84. return {"the_value": self.value}
  85. my_doodad = Doodad(42)
  86. c = Context({"my_doodad": my_doodad})
  87. t = self.engine.from_string('{{ my_doodad.value }}')
  88. self.assertEqual(t.render(c), '42')
  89. t = self.engine.from_string('{{ my_doodad.the_value }}')
  90. self.assertEqual(t.render(c), '')
  91. # Double-check that the object was really never called during the
  92. # template rendering.
  93. self.assertEqual(my_doodad.num_calls, 0)