[Python-checkins] cpython (2.7): Issue #7689: Allow pickling of dynamically created classes when their

antoine.pitrou python-checkins at python.org
Tue Oct 4 09:39:13 CEST 2011


http://hg.python.org/cpython/rev/64053bd79590
changeset:   72641:64053bd79590
branch:      2.7
parent:      72636:aa3ebc2dfc15
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Tue Oct 04 09:34:48 2011 +0200
summary:
  Issue #7689: Allow pickling of dynamically created classes when their
metaclass is registered with copyreg.  Patch by Nicolas M. Thiéry and
Craig Citro.

files:
  Lib/pickle.py            |  18 +++++++++---------
  Lib/test/pickletester.py |  21 +++++++++++++++++++++
  Misc/ACKS                |   2 ++
  Misc/NEWS                |   4 ++++
  Modules/cPickle.c        |  10 +++++-----
  5 files changed, 41 insertions(+), 14 deletions(-)


diff --git a/Lib/pickle.py b/Lib/pickle.py
--- a/Lib/pickle.py
+++ b/Lib/pickle.py
@@ -286,20 +286,20 @@
             f(self, obj) # Call unbound method with explicit self
             return
 
-        # Check for a class with a custom metaclass; treat as regular class
-        try:
-            issc = issubclass(t, TypeType)
-        except TypeError: # t is not a class (old Boost; see SF #502085)
-            issc = 0
-        if issc:
-            self.save_global(obj)
-            return
-
         # Check copy_reg.dispatch_table
         reduce = dispatch_table.get(t)
         if reduce:
             rv = reduce(obj)
         else:
+            # Check for a class with a custom metaclass; treat as regular class
+            try:
+                issc = issubclass(t, TypeType)
+            except TypeError: # t is not a class (old Boost; see SF #502085)
+                issc = 0
+            if issc:
+                self.save_global(obj)
+                return
+
             # Check for a __reduce_ex__ method, fall back to __reduce__
             reduce = getattr(obj, "__reduce_ex__", None)
             if reduce:
diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py
--- a/Lib/test/pickletester.py
+++ b/Lib/test/pickletester.py
@@ -124,6 +124,19 @@
 class use_metaclass(object):
     __metaclass__ = metaclass
 
+class pickling_metaclass(type):
+    def __eq__(self, other):
+        return (type(self) == type(other) and
+                self.reduce_args == other.reduce_args)
+
+    def __reduce__(self):
+        return (create_dynamic_class, self.reduce_args)
+
+def create_dynamic_class(name, bases):
+    result = pickling_metaclass(name, bases, dict())
+    result.reduce_args = (name, bases)
+    return result
+
 # DATA0 .. DATA2 are the pickles we expect under the various protocols, for
 # the object returned by create_data().
 
@@ -609,6 +622,14 @@
             b = self.loads(s)
             self.assertEqual(a.__class__, b.__class__)
 
+    def test_dynamic_class(self):
+        a = create_dynamic_class("my_dynamic_class", (object,))
+        copy_reg.pickle(pickling_metaclass, pickling_metaclass.__reduce__)
+        for proto in protocols:
+            s = self.dumps(a, proto)
+            b = self.loads(s)
+            self.assertEqual(a, b)
+
     def test_structseq(self):
         import time
         import os
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -147,6 +147,7 @@
 Tom Christiansen
 Vadim Chugunov
 David Cinege
+Craig Citro
 Mike Clarkson
 Andrew Clegg
 Brad Clements
@@ -817,6 +818,7 @@
 Mikhail Terekhov
 Richard M. Tew
 Tobias Thelen
+Nicolas M. Thiéry
 James Thomas
 Robin Thomas
 Stephen Thorne
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -50,6 +50,10 @@
 Library
 -------
 
+- Issue #7689: Allow pickling of dynamically created classes when their
+  metaclass is registered with copy_reg.  Patch by Nicolas M. Thiéry and
+  Craig Citro.
+
 - Issue #13058: ossaudiodev: fix a file descriptor leak on error. Patch by
   Thomas Jarosch.
 
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -2697,11 +2697,6 @@
         }
     }
 
-    if (PyType_IsSubtype(type, &PyType_Type)) {
-        res = save_global(self, args, NULL);
-        goto finally;
-    }
-
     /* Get a reduction callable, and call it.  This may come from
      * copy_reg.dispatch_table, the object's __reduce_ex__ method,
      * or the object's __reduce__ method.
@@ -2717,6 +2712,11 @@
         }
     }
     else {
+        if (PyType_IsSubtype(type, &PyType_Type)) {
+            res = save_global(self, args, NULL);
+            goto finally;
+        }
+
         /* Check for a __reduce_ex__ method. */
         __reduce__ = PyObject_GetAttr(args, __reduce_ex___str);
         if (__reduce__ != NULL) {

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list