Index: Lib/test/pickletester.py =================================================================== --- Lib/test/pickletester.py (revision 77421) +++ Lib/test/pickletester.py (working copy) @@ -124,6 +124,21 @@ class use_metaclass(object): __metaclass__ = metaclass +class pickling_metaclass(type): + def __cmp__(self, other): + r = cmp(type(self), type(other)) + if r: + return r + return cmp(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 +624,14 @@ b = self.loads(s) self.assertEqual(a.__class__, b.__class__) + def test_dynamicclass(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 Index: Lib/pickle.py =================================================================== --- Lib/pickle.py (revision 77421) +++ Lib/pickle.py (working copy) @@ -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: Index: Modules/cPickle.c =================================================================== --- Modules/cPickle.c (revision 77421) +++ Modules/cPickle.c (working copy) @@ -2701,11 +2701,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. @@ -2721,6 +2716,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) {