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