test_lazyobject.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. from __future__ import unicode_literals
  2. import copy
  3. import pickle
  4. import sys
  5. from unittest import TestCase
  6. from django.utils import six
  7. from django.utils.functional import LazyObject, SimpleLazyObject, empty
  8. class Foo(object):
  9. """
  10. A simple class with just one attribute.
  11. """
  12. foo = 'bar'
  13. def __eq__(self, other):
  14. return self.foo == other.foo
  15. class LazyObjectTestCase(TestCase):
  16. def lazy_wrap(self, wrapped_object):
  17. """
  18. Wrap the given object into a LazyObject
  19. """
  20. class AdHocLazyObject(LazyObject):
  21. def _setup(self):
  22. self._wrapped = wrapped_object
  23. return AdHocLazyObject()
  24. def test_getattr(self):
  25. obj = self.lazy_wrap(Foo())
  26. self.assertEqual(obj.foo, 'bar')
  27. def test_setattr(self):
  28. obj = self.lazy_wrap(Foo())
  29. obj.foo = 'BAR'
  30. obj.bar = 'baz'
  31. self.assertEqual(obj.foo, 'BAR')
  32. self.assertEqual(obj.bar, 'baz')
  33. def test_setattr2(self):
  34. # Same as test_setattr but in reversed order
  35. obj = self.lazy_wrap(Foo())
  36. obj.bar = 'baz'
  37. obj.foo = 'BAR'
  38. self.assertEqual(obj.foo, 'BAR')
  39. self.assertEqual(obj.bar, 'baz')
  40. def test_delattr(self):
  41. obj = self.lazy_wrap(Foo())
  42. obj.bar = 'baz'
  43. self.assertEqual(obj.bar, 'baz')
  44. del obj.bar
  45. with self.assertRaises(AttributeError):
  46. obj.bar
  47. def test_cmp(self):
  48. obj1 = self.lazy_wrap('foo')
  49. obj2 = self.lazy_wrap('bar')
  50. obj3 = self.lazy_wrap('foo')
  51. self.assertEqual(obj1, 'foo')
  52. self.assertEqual(obj1, obj3)
  53. self.assertNotEqual(obj1, obj2)
  54. self.assertNotEqual(obj1, 'bar')
  55. def test_bytes(self):
  56. obj = self.lazy_wrap(b'foo')
  57. self.assertEqual(bytes(obj), b'foo')
  58. def test_text(self):
  59. obj = self.lazy_wrap('foo')
  60. self.assertEqual(six.text_type(obj), 'foo')
  61. def test_bool(self):
  62. # Refs #21840
  63. for f in [False, 0, (), {}, [], None, set()]:
  64. self.assertFalse(self.lazy_wrap(f))
  65. for t in [True, 1, (1,), {1: 2}, [1], object(), {1}]:
  66. self.assertTrue(t)
  67. def test_dir(self):
  68. obj = self.lazy_wrap('foo')
  69. self.assertEqual(dir(obj), dir('foo'))
  70. def test_len(self):
  71. for seq in ['asd', [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}]:
  72. obj = self.lazy_wrap(seq)
  73. self.assertEqual(len(obj), 3)
  74. def test_class(self):
  75. self.assertIsInstance(self.lazy_wrap(42), int)
  76. class Bar(Foo):
  77. pass
  78. self.assertIsInstance(self.lazy_wrap(Bar()), Foo)
  79. def test_hash(self):
  80. obj = self.lazy_wrap('foo')
  81. d = {}
  82. d[obj] = 'bar'
  83. self.assertIn('foo', d)
  84. self.assertEqual(d['foo'], 'bar')
  85. def test_contains(self):
  86. test_data = [
  87. ('c', 'abcde'),
  88. (2, [1, 2, 3]),
  89. ('a', {'a': 1, 'b': 2, 'c': 3}),
  90. (2, {1, 2, 3}),
  91. ]
  92. for needle, haystack in test_data:
  93. self.assertIn(needle, self.lazy_wrap(haystack))
  94. # __contains__ doesn't work when the haystack is a string and the needle a LazyObject
  95. for needle_haystack in test_data[1:]:
  96. self.assertIn(self.lazy_wrap(needle), haystack)
  97. self.assertIn(self.lazy_wrap(needle), self.lazy_wrap(haystack))
  98. def test_getitem(self):
  99. obj_list = self.lazy_wrap([1, 2, 3])
  100. obj_dict = self.lazy_wrap({'a': 1, 'b': 2, 'c': 3})
  101. self.assertEqual(obj_list[0], 1)
  102. self.assertEqual(obj_list[-1], 3)
  103. self.assertEqual(obj_list[1:2], [2])
  104. self.assertEqual(obj_dict['b'], 2)
  105. with self.assertRaises(IndexError):
  106. obj_list[3]
  107. with self.assertRaises(KeyError):
  108. obj_dict['f']
  109. def test_setitem(self):
  110. obj_list = self.lazy_wrap([1, 2, 3])
  111. obj_dict = self.lazy_wrap({'a': 1, 'b': 2, 'c': 3})
  112. obj_list[0] = 100
  113. self.assertEqual(obj_list, [100, 2, 3])
  114. obj_list[1:2] = [200, 300, 400]
  115. self.assertEqual(obj_list, [100, 200, 300, 400, 3])
  116. obj_dict['a'] = 100
  117. obj_dict['d'] = 400
  118. self.assertEqual(obj_dict, {'a': 100, 'b': 2, 'c': 3, 'd': 400})
  119. def test_delitem(self):
  120. obj_list = self.lazy_wrap([1, 2, 3])
  121. obj_dict = self.lazy_wrap({'a': 1, 'b': 2, 'c': 3})
  122. del obj_list[-1]
  123. del obj_dict['c']
  124. self.assertEqual(obj_list, [1, 2])
  125. self.assertEqual(obj_dict, {'a': 1, 'b': 2})
  126. with self.assertRaises(IndexError):
  127. del obj_list[3]
  128. with self.assertRaises(KeyError):
  129. del obj_dict['f']
  130. def test_iter(self):
  131. # LazyObjects don't actually implements __iter__ but you can still
  132. # iterate over them because they implement __getitem__
  133. obj = self.lazy_wrap([1, 2, 3])
  134. for expected, actual in zip([1, 2, 3], obj):
  135. self.assertEqual(expected, actual)
  136. def test_pickle(self):
  137. # See ticket #16563
  138. obj = self.lazy_wrap(Foo())
  139. pickled = pickle.dumps(obj)
  140. unpickled = pickle.loads(pickled)
  141. self.assertIsInstance(unpickled, Foo)
  142. self.assertEqual(unpickled, obj)
  143. self.assertEqual(unpickled.foo, obj.foo)
  144. def test_deepcopy(self):
  145. # Check that we *can* do deep copy, and that it returns the right
  146. # objects.
  147. l = [1, 2, 3]
  148. obj = self.lazy_wrap(l)
  149. len(l) # forces evaluation
  150. obj2 = copy.deepcopy(obj)
  151. self.assertIsInstance(obj2, list)
  152. self.assertEqual(obj2, [1, 2, 3])
  153. def test_deepcopy_no_evaluation(self):
  154. # copying doesn't force evaluation
  155. l = [1, 2, 3]
  156. obj = self.lazy_wrap(l)
  157. obj2 = copy.deepcopy(obj)
  158. # Copying shouldn't force evaluation
  159. self.assertIs(obj._wrapped, empty)
  160. self.assertIs(obj2._wrapped, empty)
  161. class SimpleLazyObjectTestCase(LazyObjectTestCase):
  162. # By inheriting from LazyObjectTestCase and redefining the lazy_wrap()
  163. # method which all testcases use, we get to make sure all behaviors
  164. # tested in the parent testcase also apply to SimpleLazyObject.
  165. def lazy_wrap(self, wrapped_object):
  166. return SimpleLazyObject(lambda: wrapped_object)
  167. def test_repr(self):
  168. # First, for an unevaluated SimpleLazyObject
  169. obj = self.lazy_wrap(42)
  170. # __repr__ contains __repr__ of setup function and does not evaluate
  171. # the SimpleLazyObject
  172. six.assertRegex(self, repr(obj), '^<SimpleLazyObject:')
  173. self.assertIs(obj._wrapped, empty) # make sure evaluation hasn't been triggered
  174. self.assertEqual(obj, 42) # evaluate the lazy object
  175. self.assertIsInstance(obj._wrapped, int)
  176. self.assertEqual(repr(obj), '<SimpleLazyObject: 42>')
  177. def test_trace(self):
  178. # See ticket #19456
  179. old_trace_func = sys.gettrace()
  180. try:
  181. def trace_func(frame, event, arg):
  182. frame.f_locals['self'].__class__
  183. if old_trace_func is not None:
  184. old_trace_func(frame, event, arg)
  185. sys.settrace(trace_func)
  186. self.lazy_wrap(None)
  187. finally:
  188. sys.settrace(old_trace_func)
  189. def test_none(self):
  190. i = [0]
  191. def f():
  192. i[0] += 1
  193. return None
  194. x = SimpleLazyObject(f)
  195. self.assertEqual(str(x), "None")
  196. self.assertEqual(i, [1])
  197. self.assertEqual(str(x), "None")
  198. self.assertEqual(i, [1])
  199. def test_dict(self):
  200. # See ticket #18447
  201. lazydict = SimpleLazyObject(lambda: {'one': 1})
  202. self.assertEqual(lazydict['one'], 1)
  203. lazydict['one'] = -1
  204. self.assertEqual(lazydict['one'], -1)
  205. self.assertTrue('one' in lazydict)
  206. self.assertFalse('two' in lazydict)
  207. self.assertEqual(len(lazydict), 1)
  208. del lazydict['one']
  209. with self.assertRaises(KeyError):
  210. lazydict['one']
  211. def test_list_set(self):
  212. lazy_list = SimpleLazyObject(lambda: [1, 2, 3, 4, 5])
  213. lazy_set = SimpleLazyObject(lambda: {1, 2, 3, 4})
  214. self.assertTrue(1 in lazy_list)
  215. self.assertTrue(1 in lazy_set)
  216. self.assertFalse(6 in lazy_list)
  217. self.assertFalse(6 in lazy_set)
  218. self.assertEqual(len(lazy_list), 5)
  219. self.assertEqual(len(lazy_set), 4)