summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexandre Vassalotti <alexandre@peadrop.com>2013-12-01 00:52:03 (GMT)
committerAlexandre Vassalotti <alexandre@peadrop.com>2013-12-01 00:52:03 (GMT)
commita2934280e56dfca6ec74a6ce8392b5496592ab93 (patch)
tree72d18564704db9a850faf544169d5891c46ed77a
parent34ca066d1c3cc5071713bad353688d18a54cc22b (diff)
downloadcpython-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.h3
-rw-r--r--Lib/pickle.py21
-rw-r--r--Lib/test/pickletester.py9
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/cPickle.c64
-rw-r--r--Objects/object.c4
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):
diff --git a/Misc/NEWS b/Misc/NEWS
index 55cdd7e..3a7f8e1 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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,