test_callables.py 4.0 KB

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