cpython: 760ac320fa3d (original) (raw)
Mercurial > cpython
changeset 72639:760ac320fa3d 3.2
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:23:04 +0200 |
parents | d05350c14e77 |
children | 46c026a5ccb9 bf39434dd506 |
files | Lib/pickle.py Lib/test/pickletester.py Misc/ACKS Misc/NEWS Modules/_pickle.c |
diffstat | 5 files changed, 40 insertions(+), 13 deletions(-)[+] [-] Lib/pickle.py 18 Lib/test/pickletester.py 21 Misc/ACKS 2 Misc/NEWS 4 Modules/_pickle.c 8 |
line wrap: on
line diff
--- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -299,20 +299,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, type)[](#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 copyreg.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, type)[](#l1.23)
except TypeError: # t is not a class (old Boost; see SF #502085)[](#l1.24)
issc = False[](#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 @@ -121,6 +121,19 @@ class metaclass(type): class use_metaclass(object, metaclass=metaclass): pass +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().
@@ -695,6 +708,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)
copyreg.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 @@ -164,6 +164,7 @@ Anders Chrigström Tom Christiansen Vadim Chugunov David Cinege +Craig Citro Mike Clarkson Andrew Clegg Brad Clements @@ -881,6 +882,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 @@ -36,6 +36,10 @@ Core and Builtins Library ------- +- Issue #7689: Allow pickling of dynamically created classes when their
- Issue #4147: minidom's toprettyxml no longer adds whitespace to text nodes.
- Issue #13034: When decoding some SSL certificates, the subjectAltName
--- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -3141,10 +3141,6 @@ save(PicklerObject *self, PyObject *obj, status = save_global(self, obj, NULL); goto done; }
- else if (PyType_IsSubtype(type, &PyType_Type)) {
status = save_global(self, obj, NULL);[](#l5.8)
goto done;[](#l5.9)
- }
/* XXX: This part needs some unit tests. */ @@ -3163,6 +3159,10 @@ save(PicklerObject *self, PyObject *obj, Py_INCREF(obj); reduce_value = _Pickler_FastCall(self, reduce_func, obj); }