Loading django/utils/functional.py +22 −1 Original line number Diff line number Diff line Loading @@ -316,14 +316,35 @@ class SimpleLazyObject(LazyObject): if self._wrapped is None: self._setup() return str(self._wrapped) def __unicode__(self): if self._wrapped is None: self._setup() return unicode(self._wrapped) def __deepcopy__(self, memo): if self._wrapped is None: result = self.__class__(self._setupfunc) # We have to use SimpleLazyObject, not self.__class__, because the # latter is proxied. result = SimpleLazyObject(self._setupfunc) memo[id(self)] = result return result else: import copy return copy.deepcopy(self._wrapped, memo) # Need to pretend to be the wrapped class, for the sake of objects that care # about this (especially in equality tests) def __get_class(self): if self._wrapped is None: self._setup() return self._wrapped.__class__ __class__ = property(__get_class) def __eq__(self, other): if self._wrapped is None: self._setup() return self._wrapped == other def __hash__(self): if self._wrapped is None: self._setup() return hash(self._wrapped) def _setup(self): self._wrapped = self._setupfunc() tests/regressiontests/context_processors/tests.py +12 −2 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ Tests for Django's bundled context processors. """ from django.conf import settings from django.contrib.auth.models import Group from django.contrib.auth import authenticate from django.db.models import Q from django.test import TestCase from django.template import Template Loading Loading @@ -74,9 +74,13 @@ class AuthContextProcessorTests(TestCase): def test_user_attrs(self): """ Test that ContextLazyObject wraps objects properly Test that the lazy objects returned behave just like the wrapped objects. """ # These are 'functional' level tests for common use cases. Direct # testing of the implementation (SimpleLazyObject) is in the 'utils' # tests. self.client.login(username='super', password='secret') user = authenticate(username='super', password='secret') response = self.client.get('/auth_processor_user/') self.assertContains(response, "unicode: super") self.assertContains(response, "id: 100") Loading @@ -100,3 +104,9 @@ class AuthContextProcessorTests(TestCase): # calling a Python object' in <type 'exceptions.AttributeError'> # ignored" query = Q(user=response.context['user']) & Q(someflag=True) # Tests for user equality. This is hard because User defines # equality in a non-duck-typing way # See bug #12060 self.assertEqual(response.context['user'], user) self.assertEqual(user, response.context['user']) tests/regressiontests/utils/tests.py +75 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ Tests for django.utils. from unittest import TestCase from django.utils import html, checksums from django.utils.functional import SimpleLazyObject import timesince import datastructures Loading Loading @@ -161,6 +162,80 @@ class TestUtilsChecksums(TestCase): for value, output in items: self.check_output(f, value, output) 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) def __str__(self): return "I am _ComplexObject(%r)" % self.name def __unicode__(self): return unicode(self.name) def __repr__(self): return "_ComplexObject(%r)" % self.name complex_object = lambda: _ComplexObject("joe") class TestUtilsSimpleLazyObject(TestCase): """ 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): # For debugging, it will really confuse things if there is no clue that # SimpleLazyObject is actually a proxy object. So we don't # proxy __repr__ self.assert_("SimpleLazyObject" in repr(SimpleLazyObject(complex_object))) def test_str(self): self.assertEqual("I am _ComplexObject('joe')", str(SimpleLazyObject(complex_object))) def test_unicode(self): self.assertEqual(u"joe", unicode(SimpleLazyObject(complex_object))) 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): import copy # Check that we *can* do deep copy, and that it returns the right # objects. # First, for an unevaluated SimpleLazyObject s = SimpleLazyObject(complex_object) assert s._wrapped is None s2 = copy.deepcopy(s) assert s._wrapped is None # something has gone wrong is s is evaluated self.assertEqual(s2, complex_object()) # Second, for an evaluated SimpleLazyObject name = s.name # evaluate assert s._wrapped is not None s3 = copy.deepcopy(s) self.assertEqual(s3, complex_object()) if __name__ == "__main__": import doctest doctest.testmod() Loading
django/utils/functional.py +22 −1 Original line number Diff line number Diff line Loading @@ -316,14 +316,35 @@ class SimpleLazyObject(LazyObject): if self._wrapped is None: self._setup() return str(self._wrapped) def __unicode__(self): if self._wrapped is None: self._setup() return unicode(self._wrapped) def __deepcopy__(self, memo): if self._wrapped is None: result = self.__class__(self._setupfunc) # We have to use SimpleLazyObject, not self.__class__, because the # latter is proxied. result = SimpleLazyObject(self._setupfunc) memo[id(self)] = result return result else: import copy return copy.deepcopy(self._wrapped, memo) # Need to pretend to be the wrapped class, for the sake of objects that care # about this (especially in equality tests) def __get_class(self): if self._wrapped is None: self._setup() return self._wrapped.__class__ __class__ = property(__get_class) def __eq__(self, other): if self._wrapped is None: self._setup() return self._wrapped == other def __hash__(self): if self._wrapped is None: self._setup() return hash(self._wrapped) def _setup(self): self._wrapped = self._setupfunc()
tests/regressiontests/context_processors/tests.py +12 −2 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ Tests for Django's bundled context processors. """ from django.conf import settings from django.contrib.auth.models import Group from django.contrib.auth import authenticate from django.db.models import Q from django.test import TestCase from django.template import Template Loading Loading @@ -74,9 +74,13 @@ class AuthContextProcessorTests(TestCase): def test_user_attrs(self): """ Test that ContextLazyObject wraps objects properly Test that the lazy objects returned behave just like the wrapped objects. """ # These are 'functional' level tests for common use cases. Direct # testing of the implementation (SimpleLazyObject) is in the 'utils' # tests. self.client.login(username='super', password='secret') user = authenticate(username='super', password='secret') response = self.client.get('/auth_processor_user/') self.assertContains(response, "unicode: super") self.assertContains(response, "id: 100") Loading @@ -100,3 +104,9 @@ class AuthContextProcessorTests(TestCase): # calling a Python object' in <type 'exceptions.AttributeError'> # ignored" query = Q(user=response.context['user']) & Q(someflag=True) # Tests for user equality. This is hard because User defines # equality in a non-duck-typing way # See bug #12060 self.assertEqual(response.context['user'], user) self.assertEqual(user, response.context['user'])
tests/regressiontests/utils/tests.py +75 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ Tests for django.utils. from unittest import TestCase from django.utils import html, checksums from django.utils.functional import SimpleLazyObject import timesince import datastructures Loading Loading @@ -161,6 +162,80 @@ class TestUtilsChecksums(TestCase): for value, output in items: self.check_output(f, value, output) 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) def __str__(self): return "I am _ComplexObject(%r)" % self.name def __unicode__(self): return unicode(self.name) def __repr__(self): return "_ComplexObject(%r)" % self.name complex_object = lambda: _ComplexObject("joe") class TestUtilsSimpleLazyObject(TestCase): """ 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): # For debugging, it will really confuse things if there is no clue that # SimpleLazyObject is actually a proxy object. So we don't # proxy __repr__ self.assert_("SimpleLazyObject" in repr(SimpleLazyObject(complex_object))) def test_str(self): self.assertEqual("I am _ComplexObject('joe')", str(SimpleLazyObject(complex_object))) def test_unicode(self): self.assertEqual(u"joe", unicode(SimpleLazyObject(complex_object))) 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): import copy # Check that we *can* do deep copy, and that it returns the right # objects. # First, for an unevaluated SimpleLazyObject s = SimpleLazyObject(complex_object) assert s._wrapped is None s2 = copy.deepcopy(s) assert s._wrapped is None # something has gone wrong is s is evaluated self.assertEqual(s2, complex_object()) # Second, for an evaluated SimpleLazyObject name = s.name # evaluate assert s._wrapped is not None s3 = copy.deepcopy(s) self.assertEqual(s3, complex_object()) if __name__ == "__main__": import doctest doctest.testmod()