2012-06-07 18:08:47 +02:00
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
2011-03-28 04:11:19 +02:00
|
|
|
import copy
|
2011-12-15 03:33:14 +01:00
|
|
|
import pickle
|
2013-03-18 11:22:43 +01:00
|
|
|
import sys
|
2013-07-01 14:22:27 +02:00
|
|
|
from unittest import TestCase
|
2010-09-27 17:15:04 +02:00
|
|
|
|
2013-09-18 15:35:51 +02:00
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.test import TestCase as DjangoTestCase
|
2012-07-20 14:48:51 +02:00
|
|
|
from django.utils import six
|
2011-06-01 17:30:06 +02:00
|
|
|
from django.utils.functional import SimpleLazyObject, empty
|
|
|
|
|
2010-09-27 17:15:04 +02:00
|
|
|
|
|
|
|
class _ComplexObject(object):
|
|
|
|
def __init__(self, name):
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return self.name == other.name
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return hash(self.name)
|
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
if six.PY3:
|
|
|
|
def __bytes__(self):
|
|
|
|
return ("I am _ComplexObject(%r)" % self.name).encode("utf-8")
|
2010-09-27 17:15:04 +02:00
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
else:
|
|
|
|
def __str__(self):
|
|
|
|
return b"I am _ComplexObject(%r)" % str(self.name)
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return self.name
|
2010-09-27 17:15:04 +02:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return "_ComplexObject(%r)" % self.name
|
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
|
2010-09-27 17:15:04 +02:00
|
|
|
complex_object = lambda: _ComplexObject("joe")
|
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
|
2011-06-02 00:09:50 +02:00
|
|
|
class TestUtilsSimpleLazyObject(TestCase):
|
2010-09-27 17:15:04 +02:00
|
|
|
"""
|
|
|
|
Tests for SimpleLazyObject
|
|
|
|
"""
|
|
|
|
# Note that concrete use cases for SimpleLazyObject are also found in the
|
|
|
|
# auth context processor tests (unless the implementation of that function
|
|
|
|
# is changed).
|
|
|
|
|
|
|
|
def test_equality(self):
|
|
|
|
self.assertEqual(complex_object(), SimpleLazyObject(complex_object))
|
|
|
|
self.assertEqual(SimpleLazyObject(complex_object), complex_object())
|
|
|
|
|
|
|
|
def test_hash(self):
|
|
|
|
# hash() equality would not be true for many objects, but it should be
|
|
|
|
# for _ComplexObject
|
|
|
|
self.assertEqual(hash(complex_object()),
|
|
|
|
hash(SimpleLazyObject(complex_object)))
|
|
|
|
|
|
|
|
def test_repr(self):
|
2013-03-07 01:00:05 +01:00
|
|
|
# First, for an unevaluated SimpleLazyObject
|
|
|
|
x = SimpleLazyObject(complex_object)
|
|
|
|
# __repr__ contains __repr__ of setup function and does not evaluate
|
|
|
|
# the SimpleLazyObject
|
|
|
|
self.assertEqual("<SimpleLazyObject: %r>" % complex_object, repr(x))
|
|
|
|
self.assertEqual(empty, x._wrapped)
|
|
|
|
|
|
|
|
# Second, for an evaluated SimpleLazyObject
|
2013-10-19 14:31:38 +02:00
|
|
|
x.name # evaluate
|
2013-05-21 11:42:15 +02:00
|
|
|
self.assertIsInstance(x._wrapped, _ComplexObject)
|
2013-03-07 01:00:05 +01:00
|
|
|
# __repr__ contains __repr__ of wrapped object
|
|
|
|
self.assertEqual("<SimpleLazyObject: %r>" % x._wrapped, repr(x))
|
2010-09-27 17:15:04 +02:00
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
def test_bytes(self):
|
|
|
|
self.assertEqual(b"I am _ComplexObject('joe')",
|
|
|
|
bytes(SimpleLazyObject(complex_object)))
|
2010-09-27 17:15:04 +02:00
|
|
|
|
2012-08-04 15:55:53 +02:00
|
|
|
def test_text(self):
|
2012-07-20 14:48:51 +02:00
|
|
|
self.assertEqual("joe", six.text_type(SimpleLazyObject(complex_object)))
|
2010-09-27 17:15:04 +02:00
|
|
|
|
|
|
|
def test_class(self):
|
|
|
|
# This is important for classes that use __class__ in things like
|
|
|
|
# equality tests.
|
|
|
|
self.assertEqual(_ComplexObject, SimpleLazyObject(complex_object).__class__)
|
|
|
|
|
|
|
|
def test_deepcopy(self):
|
|
|
|
# Check that we *can* do deep copy, and that it returns the right
|
|
|
|
# objects.
|
|
|
|
|
|
|
|
# First, for an unevaluated SimpleLazyObject
|
|
|
|
s = SimpleLazyObject(complex_object)
|
2011-06-01 17:30:06 +02:00
|
|
|
self.assertIs(s._wrapped, empty)
|
2010-09-27 17:15:04 +02:00
|
|
|
s2 = copy.deepcopy(s)
|
2011-06-01 17:30:06 +02:00
|
|
|
# something has gone wrong is s is evaluated
|
|
|
|
self.assertIs(s._wrapped, empty)
|
2010-09-27 17:15:04 +02:00
|
|
|
self.assertEqual(s2, complex_object())
|
|
|
|
|
|
|
|
# Second, for an evaluated SimpleLazyObject
|
2013-10-19 14:31:38 +02:00
|
|
|
s.name # evaluate
|
2011-06-01 17:30:06 +02:00
|
|
|
self.assertIsNot(s._wrapped, empty)
|
2010-09-27 17:15:04 +02:00
|
|
|
s3 = copy.deepcopy(s)
|
|
|
|
self.assertEqual(s3, complex_object())
|
2011-06-01 17:30:06 +02:00
|
|
|
|
|
|
|
def test_none(self):
|
|
|
|
i = [0]
|
2013-03-07 01:09:36 +01:00
|
|
|
|
2011-06-01 17:30:06 +02:00
|
|
|
def f():
|
|
|
|
i[0] += 1
|
|
|
|
return None
|
|
|
|
|
|
|
|
x = SimpleLazyObject(f)
|
|
|
|
self.assertEqual(str(x), "None")
|
|
|
|
self.assertEqual(i, [1])
|
|
|
|
self.assertEqual(str(x), "None")
|
|
|
|
self.assertEqual(i, [1])
|
|
|
|
|
|
|
|
def test_bool(self):
|
|
|
|
x = SimpleLazyObject(lambda: 3)
|
|
|
|
self.assertTrue(x)
|
|
|
|
x = SimpleLazyObject(lambda: 0)
|
2011-06-02 00:09:50 +02:00
|
|
|
self.assertFalse(x)
|
2011-12-15 03:33:14 +01:00
|
|
|
|
|
|
|
def test_pickle_complex(self):
|
|
|
|
# See ticket #16563
|
|
|
|
x = SimpleLazyObject(complex_object)
|
|
|
|
pickled = pickle.dumps(x)
|
|
|
|
unpickled = pickle.loads(pickled)
|
|
|
|
self.assertEqual(unpickled, x)
|
2012-07-20 14:48:51 +02:00
|
|
|
self.assertEqual(six.text_type(unpickled), six.text_type(x))
|
2011-12-15 03:33:14 +01:00
|
|
|
self.assertEqual(unpickled.name, x.name)
|
2013-03-18 11:09:29 +01:00
|
|
|
|
|
|
|
def test_dict(self):
|
|
|
|
# See ticket #18447
|
|
|
|
lazydict = SimpleLazyObject(lambda: {'one': 1})
|
|
|
|
self.assertEqual(lazydict['one'], 1)
|
|
|
|
lazydict['one'] = -1
|
|
|
|
self.assertEqual(lazydict['one'], -1)
|
2013-08-15 20:59:58 +02:00
|
|
|
self.assertTrue('one' in lazydict)
|
|
|
|
self.assertFalse('two' in lazydict)
|
|
|
|
self.assertEqual(len(lazydict), 1)
|
2013-03-18 11:09:29 +01:00
|
|
|
del lazydict['one']
|
|
|
|
with self.assertRaises(KeyError):
|
|
|
|
lazydict['one']
|
2013-03-18 11:22:43 +01:00
|
|
|
|
|
|
|
def test_trace(self):
|
|
|
|
# See ticket #19456
|
|
|
|
old_trace_func = sys.gettrace()
|
|
|
|
try:
|
|
|
|
def trace_func(frame, event, arg):
|
|
|
|
frame.f_locals['self'].__class__
|
|
|
|
if old_trace_func is not None:
|
|
|
|
old_trace_func(frame, event, arg)
|
|
|
|
sys.settrace(trace_func)
|
|
|
|
SimpleLazyObject(None)
|
|
|
|
finally:
|
|
|
|
sys.settrace(old_trace_func)
|
2013-04-19 19:58:29 +02:00
|
|
|
|
|
|
|
def test_not_equal(self):
|
|
|
|
lazy1 = SimpleLazyObject(lambda: 2)
|
|
|
|
lazy2 = SimpleLazyObject(lambda: 2)
|
|
|
|
lazy3 = SimpleLazyObject(lambda: 3)
|
|
|
|
self.assertEqual(lazy1, lazy2)
|
|
|
|
self.assertNotEqual(lazy1, lazy3)
|
|
|
|
self.assertTrue(lazy1 != lazy3)
|
|
|
|
self.assertFalse(lazy1 != lazy2)
|
2013-05-21 07:17:56 +02:00
|
|
|
|
2013-09-18 15:35:51 +02:00
|
|
|
def test_list_set(self):
|
|
|
|
lazy_list = SimpleLazyObject(lambda: [1, 2, 3, 4, 5])
|
|
|
|
lazy_set = SimpleLazyObject(lambda: set([1, 2, 3, 4]))
|
|
|
|
self.assertTrue(1 in lazy_list)
|
|
|
|
self.assertTrue(1 in lazy_set)
|
|
|
|
self.assertFalse(6 in lazy_list)
|
|
|
|
self.assertFalse(6 in lazy_set)
|
|
|
|
self.assertEqual(len(lazy_list), 5)
|
|
|
|
self.assertEqual(len(lazy_set), 4)
|
|
|
|
|
2013-11-02 22:34:05 +01:00
|
|
|
|
2013-09-18 15:35:51 +02:00
|
|
|
class TestUtilsSimpleLazyObjectDjangoTestCase(DjangoTestCase):
|
2013-05-21 07:17:56 +02:00
|
|
|
|
2013-09-18 15:35:51 +02:00
|
|
|
def test_pickle_py2_regression(self):
|
2013-05-21 07:17:56 +02:00
|
|
|
# See ticket #20212
|
|
|
|
user = User.objects.create_user('johndoe', 'john@example.com', 'pass')
|
|
|
|
x = SimpleLazyObject(lambda: user)
|
|
|
|
|
|
|
|
# This would fail with "TypeError: can't pickle instancemethod objects",
|
|
|
|
# only on Python 2.X.
|
2013-10-19 14:31:38 +02:00
|
|
|
pickle.dumps(x)
|
2013-05-21 07:17:56 +02:00
|
|
|
|
|
|
|
# Try the variant protocol levels.
|
2013-10-19 14:31:38 +02:00
|
|
|
pickle.dumps(x, 0)
|
|
|
|
pickle.dumps(x, 1)
|
|
|
|
pickle.dumps(x, 2)
|
2013-05-21 07:17:56 +02:00
|
|
|
|
2013-09-02 12:06:32 +02:00
|
|
|
if six.PY2:
|
2013-05-21 07:17:56 +02:00
|
|
|
import cPickle
|
|
|
|
|
|
|
|
# This would fail with "TypeError: expected string or Unicode object, NoneType found".
|
2013-10-19 14:31:38 +02:00
|
|
|
cPickle.dumps(x)
|