diff options
author | Alexandre Vassalotti <alexandre@peadrop.com> | 2013-12-01 00:52:03 (GMT) |
---|---|---|
committer | Alexandre Vassalotti <alexandre@peadrop.com> | 2013-12-01 00:52:03 (GMT) |
commit | a2934280e56dfca6ec74a6ce8392b5496592ab93 (patch) | |
tree | 72d18564704db9a850faf544169d5891c46ed77a | |
parent | 34ca066d1c3cc5071713bad353688d18a54cc22b (diff) | |
download | cpython-a2934280e56dfca6ec74a6ce8392b5496592ab93.zip cpython-a2934280e56dfca6ec74a6ce8392b5496592ab93.tar.gz cpython-a2934280e56dfca6ec74a6ce8392b5496592ab93.tar.bz2 |
Issue #6477: Added pickling support for singletons and their types.
-rw-r--r-- | Include/object.h | 3 | ||||
-rw-r--r-- | Lib/pickle.py | 21 | ||||
-rw-r--r-- | Lib/test/pickletester.py | 9 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/cPickle.c | 64 | ||||
-rw-r--r-- | Objects/object.c | 4 |
6 files changed, 100 insertions, 4 deletions
diff --git a/Include/object.h b/Include/object.h index afbc68d..05d8d39 100644 --- a/Include/object.h +++ b/Include/object.h @@ -829,6 +829,9 @@ they can have object code that is not dependent on Python compilation flags. PyAPI_FUNC(void) Py_IncRef(PyObject *); PyAPI_FUNC(void) Py_DecRef(PyObject *); +PyAPI_DATA(PyTypeObject) PyNone_Type; +PyAPI_DATA(PyTypeObject) PyNotImplemented_Type; + /* _Py_NoneStruct is an object of undefined type which can be used in contexts where NULL (nil) is not suitable (since NULL often means 'error'). diff --git a/Lib/pickle.py b/Lib/pickle.py index 299de16..5d0aba7 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -427,6 +427,14 @@ class Pickler: self.write(NONE) dispatch[NoneType] = save_none + def save_ellipsis(self, obj): + self.save_global(Ellipsis, 'Ellipsis') + dispatch[type(Ellipsis)] = save_ellipsis + + def save_notimplemented(self, obj): + self.save_global(NotImplemented, 'NotImplemented') + dispatch[type(NotImplemented)] = save_notimplemented + def save_bool(self, obj): if self.proto >= 2: self.write(obj and NEWTRUE or NEWFALSE) @@ -770,7 +778,18 @@ class Pickler: dispatch[ClassType] = save_global dispatch[FunctionType] = save_global dispatch[BuiltinFunctionType] = save_global - dispatch[TypeType] = save_global + + def save_type(self, obj): + if obj is type(None): + return self.save_reduce(type, (None,), obj=obj) + elif obj is type(NotImplemented): + return self.save_reduce(type, (NotImplemented,), obj=obj) + elif obj is type(Ellipsis): + return self.save_reduce(type, (Ellipsis,), obj=obj) + return self.save_global(obj) + + dispatch[TypeType] = save_type + # Pickling helpers diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index 1599893..d7b68db 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -661,6 +661,15 @@ class AbstractPickleTests(unittest.TestCase): u = self.loads(s) self.assertEqual(t, u) + def test_singleton_types(self): + # Issue #6477: Test that types of built-in singletons can be pickled. + singletons = [None, Ellipsis, NotImplemented] + for singleton in singletons: + for proto in protocols: + s = self.dumps(type(singleton), proto) + u = self.loads(s) + self.assertIs(type(singleton), u) + # Tests for protocol 2 def test_proto(self): @@ -15,6 +15,9 @@ Core and Builtins Library ------- +- Issue #6477: Added pickling support for built-in singletons (i.e., None, + Ellipsis and NotImplemented) and their respective types. + - Issue #16231: Fixed pickle.Pickler to only fallback to its default pickling behaviour when Pickler.persistent_id returns None, but not for any other false values. This allows false values other than None to be used as diff --git a/Modules/cPickle.c b/Modules/cPickle.c index 8145bbf..c84a757 100644 --- a/Modules/cPickle.c +++ b/Modules/cPickle.c @@ -2559,6 +2559,60 @@ save_reduce(Picklerobject *self, PyObject *args, PyObject *fn, PyObject *ob) } static int +save_ellipsis(Picklerobject *self, PyObject *obj) +{ + PyObject *str = PyString_FromString("Ellipsis"); + int res; + if (str == NULL) + return -1; + res = save_global(self, Py_Ellipsis, str); + Py_DECREF(str); + return res; +} + +static int +save_notimplemented(Picklerobject *self, PyObject *obj) +{ + PyObject *str = PyString_FromString("NotImplemented"); + int res; + if (str == NULL) + return -1; + res = save_global(self, Py_NotImplemented, str); + Py_DECREF(str); + return res; +} + +static int +save_singleton_type(Picklerobject *self, PyObject *obj, PyObject *singleton) +{ + PyObject *reduce_value; + int status; + + reduce_value = Py_BuildValue("O(O)", &PyType_Type, singleton); + if (reduce_value == NULL) { + return -1; + } + status = save_reduce(self, reduce_value, (PyObject *)self, obj); + Py_DECREF(reduce_value); + return status; +} + +static int +save_type(Picklerobject *self, PyObject *obj) +{ + if (obj == (PyObject *)&PyNone_Type) { + return save_singleton_type(self, obj, Py_None); + } + else if (obj == (PyObject *)&PyEllipsis_Type) { + return save_singleton_type(self, obj, Py_Ellipsis); + } + else if (obj == (PyObject *)&PyNotImplemented_Type) { + return save_singleton_type(self, obj, Py_NotImplemented); + } + return save_global(self, obj, NULL); +} + +static int save(Picklerobject *self, PyObject *args, int pers_save) { PyTypeObject *type; @@ -2580,6 +2634,14 @@ save(Picklerobject *self, PyObject *args, int pers_save) res = save_none(self, args); goto finally; } + else if (args == Py_Ellipsis) { + res = save_ellipsis(self, args); + goto finally; + } + else if (args == Py_NotImplemented) { + res = save_notimplemented(self, args); + goto finally; + } type = Py_TYPE(args); @@ -2671,7 +2733,7 @@ save(Picklerobject *self, PyObject *args, int pers_save) goto finally; } if (type == &PyType_Type) { - res = save_global(self, args, NULL); + res = save_type(self, args); goto finally; } break; diff --git a/Objects/object.c b/Objects/object.c index 14f4e9f..26a5a2a 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2012,7 +2012,7 @@ none_dealloc(PyObject* ignore) } -static PyTypeObject PyNone_Type = { +PyTypeObject PyNone_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "NoneType", 0, @@ -2043,7 +2043,7 @@ NotImplemented_repr(PyObject *op) return PyString_FromString("NotImplemented"); } -static PyTypeObject PyNotImplemented_Type = { +PyTypeObject PyNotImplemented_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "NotImplementedType", 0, |