From 655b29b5ba6200560e69bcdcfae5e2e892bddd9c Mon Sep 17 00:00:00 2001
From: Luke Plant <L.Plant.98@cantab.net>
Date: Thu, 15 Dec 2011 02:33:14 +0000
Subject: [PATCH] Fixed #16563 - Error pickling request.user

Thanks to zero.fuxor for the report

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17202 bcc190cf-cafb-0310-a4f2-bffc1f526a37
---
 django/utils/functional.py                      | 10 ++++++++++
 tests/regressiontests/utils/simplelazyobject.py | 10 ++++++++++
 2 files changed, 20 insertions(+)

diff --git a/django/utils/functional.py b/django/utils/functional.py
index 1bd2286728..183c24ced3 100644
--- a/django/utils/functional.py
+++ b/django/utils/functional.py
@@ -261,6 +261,16 @@ class SimpleLazyObject(LazyObject):
         else:
             return copy.deepcopy(self._wrapped, memo)
 
+    # Because we have messed with __class__ below, we confuse pickle as to what
+    # class we are pickling. It also appears to stop __reduce__ from being
+    # called. So, we 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 is better than nothing.
+    def __getstate__(self):
+        if self._wrapped is empty:
+            self._setup()
+        return self._wrapped.__dict__
+
     # Need to pretend to be the wrapped class, for the sake of objects that care
     # about this (especially in equality tests)
     __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
diff --git a/tests/regressiontests/utils/simplelazyobject.py b/tests/regressiontests/utils/simplelazyobject.py
index 8a02f52fb6..4ee822563e 100644
--- a/tests/regressiontests/utils/simplelazyobject.py
+++ b/tests/regressiontests/utils/simplelazyobject.py
@@ -1,4 +1,5 @@
 import copy
+import pickle
 
 from django.utils.unittest import TestCase
 from django.utils.functional import SimpleLazyObject, empty
@@ -96,3 +97,12 @@ class TestUtilsSimpleLazyObject(TestCase):
         self.assertTrue(x)
         x = SimpleLazyObject(lambda: 0)
         self.assertFalse(x)
+
+    def test_pickle_complex(self):
+        # See ticket #16563
+        x = SimpleLazyObject(complex_object)
+        pickled = pickle.dumps(x)
+        unpickled = pickle.loads(pickled)
+        self.assertEqual(unpickled, x)
+        self.assertEqual(unicode(unpickled), unicode(x))
+        self.assertEqual(unpickled.name, x.name)