diff options
| author | Daniel Lindsley <daniel@toastdriven.com> | 2013-05-20 22:17:56 -0700 |
|---|---|---|
| committer | Daniel Lindsley <daniel@toastdriven.com> | 2013-05-21 10:17:27 -0700 |
| commit | cb9aaac91fb41b29b3d0d94f3cd208123c02a2ca (patch) | |
| tree | c757677c93a6d3d6bb2bb32f2bcf28cced6799cf /django | |
| parent | bac187c0d8e829fb3ca2ca82965eabbcbcb6ddd5 (diff) | |
[1.5.x] Fixed #20212 - __reduce__ should only be defined for Py3+.
Diffstat (limited to 'django')
| -rw-r--r-- | django/utils/functional.py | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/django/utils/functional.py b/django/utils/functional.py index 1dcbd55664..839dd4ef85 100644 --- a/django/utils/functional.py +++ b/django/utils/functional.py @@ -5,6 +5,12 @@ import sys from django.utils import six +try: + import copyreg +except ImportError: + import copy_reg as copyreg + + # You can't trivially replace this `functools.partial` because this binds to # classes and returns bound instances, whereas functools.partial (on CPython) # is a type and its instances don't bind. @@ -294,15 +300,23 @@ class SimpleLazyObject(LazyObject): self._setup() return self._wrapped.__dict__ - # Python 3.3 will call __reduce__ when pickling; these methods are needed - # to serialize and deserialize correctly. They are not called in earlier - # versions of Python. + # Python 3.3 will call __reduce__ when pickling; this method is needed + # to serialize and deserialize correctly. @classmethod def __newobj__(cls, *args): return cls.__new__(cls, *args) - def __reduce__(self): - return (self.__newobj__, (self.__class__,), self.__getstate__()) + def __reduce_ex__(self, proto): + if proto >= 2: + # On Py3, since the default protocol is 3, pickle uses the + # ``__newobj__`` method (& more efficient opcodes) for writing. + return (self.__newobj__, (self.__class__,), self.__getstate__()) + else: + # On Py2, the default protocol is 0 (for back-compat) & the above + # code fails miserably (see regression test). Instead, we return + # exactly what's returned if there's no ``__reduce__`` method at + # all. + return (copyreg._reconstructor, (self.__class__, object, None), self.__getstate__()) # Need to pretend to be the wrapped class, for the sake of objects that care # about this (especially in equality tests) |
