cpython: 64053bd79590 (original) (raw)
Mercurial > cpython
changeset 72641:64053bd79590 2.7
Issue #7689: Allow pickling of dynamically created classes when their metaclass is registered with copyreg. Patch by Nicolas M. Thiéry and Craig Citro. [#7689]
Antoine Pitrou solipsis@pitrou.net | |
---|---|
date | Tue, 04 Oct 2011 09:34:48 +0200 |
parents | aa3ebc2dfc15 |
children | 05c58e0873f0 |
files | Lib/pickle.py Lib/test/pickletester.py Misc/ACKS Misc/NEWS Modules/cPickle.c |
diffstat | 5 files changed, 41 insertions(+), 14 deletions(-)[+] [-] Lib/pickle.py 18 Lib/test/pickletester.py 21 Misc/ACKS 2 Misc/NEWS 4 Modules/cPickle.c 10 |
line wrap: on
line diff
--- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -286,20 +286,20 @@ class Pickler: f(self, obj) # Call unbound method with explicit self return
# Check for a class with a custom metaclass; treat as regular class[](#l1.7)
try:[](#l1.8)
issc = issubclass(t, TypeType)[](#l1.9)
except TypeError: # t is not a class (old Boost; see SF #502085)[](#l1.10)
issc = 0[](#l1.11)
if issc:[](#l1.12)
self.save_global(obj)[](#l1.13)
return[](#l1.14)
- # 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[](#l1.21)
try:[](#l1.22)
issc = issubclass(t, TypeType)[](#l1.23)
except TypeError: # t is not a class (old Boost; see SF #502085)[](#l1.24)
issc = 0[](#l1.25)
if issc:[](#l1.26)
self.save_global(obj)[](#l1.27)
return[](#l1.28)
+ # Check for a reduce_ex method, fall back to reduce reduce = getattr(obj, "reduce_ex", None) if reduce:
--- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -124,6 +124,19 @@ class metaclass(type): class use_metaclass(object): metaclass = metaclass +class pickling_metaclass(type):
- def eq(self, other):
return (type(self) == type(other) and[](#l2.9)
self.reduce_args == other.reduce_args)[](#l2.10)
+ +def create_dynamic_class(name, bases):
DATA0 .. DATA2 are the pickles we expect under the various protocols, for
the object returned by create_data().
@@ -609,6 +622,14 @@ class AbstractPickleTests(unittest.TestC b = self.loads(s) self.assertEqual(a.class, b.class)
- def test_dynamic_class(self):
a = create_dynamic_class("my_dynamic_class", (object,))[](#l2.28)
copy_reg.pickle(pickling_metaclass, pickling_metaclass.__reduce__)[](#l2.29)
for proto in protocols:[](#l2.30)
s = self.dumps(a, proto)[](#l2.31)
b = self.loads(s)[](#l2.32)
self.assertEqual(a, b)[](#l2.33)
+ def test_structseq(self): import time import os
--- a/Misc/ACKS +++ b/Misc/ACKS @@ -147,6 +147,7 @@ Anders Chrigström Tom Christiansen Vadim Chugunov David Cinege +Craig Citro Mike Clarkson Andrew Clegg Brad Clements @@ -817,6 +818,7 @@ Anatoly Techtonik Mikhail Terekhov Richard M. Tew Tobias Thelen +Nicolas M. Thiéry James Thomas Robin Thomas Stephen Thorne
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,10 @@ Core and Builtins Library ------- +- Issue #7689: Allow pickling of dynamically created classes when their
--- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -2697,11 +2697,6 @@ save(Picklerobject *self, PyObject *args } }
- if (PyType_IsSubtype(type, &PyType_Type)) {
res = save_global(self, args, NULL);[](#l5.8)
goto finally;[](#l5.9)
- }
- /* 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 @@ save(Picklerobject *self, PyObject *args } } else {
if (PyType_IsSubtype(type, &PyType_Type)) {[](#l5.19)
res = save_global(self, args, NULL);[](#l5.20)
goto finally;[](#l5.21)
}[](#l5.22)
+ /* Check for a reduce_ex method. */ reduce = PyObject_GetAttr(args, __reduce_ex___str); if (reduce != NULL) {