summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2017-07-12 15:18:49 +0500
committerTim Graham <timograham@gmail.com>2017-07-12 09:11:48 -0400
commit30f334cc58e939c7d9bd8455c80bd066fbde9f2b (patch)
tree8905fc2e141a4bd8085102226d25e31afcf05049
parentfe7b4568255ae1f77c180404631d81ba6b2d996d (diff)
[1.11.x] Fixed #28389 -- Fixed pickling of LazyObject on Python 2 when wrapped object doesn't have __reduce__().
Partial revert of 35355a4ffedb2aeed52d5fe3034380ffc6a438db.
-rw-r--r--django/utils/functional.py13
-rw-r--r--docs/releases/1.11.4.txt3
-rw-r--r--tests/utils_tests/test_lazyobject.py2
3 files changed, 12 insertions, 6 deletions
diff --git a/django/utils/functional.py b/django/utils/functional.py
index 7d5b7feea5..4ea5fe5745 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -300,13 +300,14 @@ class LazyObject(object):
self._setup()
return (unpickle_lazyobject, (self._wrapped,))
+ # Overriding __class__ stops __reduce__ from being called on Python 2.
+ # So, define __getstate__ in a way that cooperates with the way that
+ # pickle interprets this class. This fails when the wrapped class is a
+ # builtin, but it's better than nothing.
def __getstate__(self):
- """
- Prevent older versions of pickle from trying to pickle the __dict__
- (which in the case of a SimpleLazyObject may contain a lambda). The
- value will be ignored by __reduce__() and the custom unpickler.
- """
- return {}
+ if self._wrapped is empty:
+ self._setup()
+ return self._wrapped.__dict__
def __copy__(self):
if self._wrapped is empty:
diff --git a/docs/releases/1.11.4.txt b/docs/releases/1.11.4.txt
index 2383ad6a17..2cd093335e 100644
--- a/docs/releases/1.11.4.txt
+++ b/docs/releases/1.11.4.txt
@@ -15,3 +15,6 @@ Bugfixes
* Fixed ``QuerySet.union()`` and ``difference()`` when combining with
a queryset raising ``EmptyResultSet`` (:ticket:`28378`).
+
+* Fixed a regression in pickling of ``LazyObject`` on Python 2 when the wrapped
+ object doesn't have ``__reduce__()`` (:ticket:`28389`).
diff --git a/tests/utils_tests/test_lazyobject.py b/tests/utils_tests/test_lazyobject.py
index 9dc225b55f..c2a9855abf 100644
--- a/tests/utils_tests/test_lazyobject.py
+++ b/tests/utils_tests/test_lazyobject.py
@@ -187,11 +187,13 @@ class LazyObjectTestCase(TestCase):
def test_pickle(self):
# See ticket #16563
obj = self.lazy_wrap(Foo())
+ obj.bar = 'baz'
pickled = pickle.dumps(obj)
unpickled = pickle.loads(pickled)
self.assertIsInstance(unpickled, Foo)
self.assertEqual(unpickled, obj)
self.assertEqual(unpickled.foo, obj.foo)
+ self.assertEqual(unpickled.bar, obj.bar)
# Test copying lazy objects wrapping both builtin types and user-defined
# classes since a lot of the relevant code does __dict__ manipulation and