]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #6477: Added support for pickling the types of built-in singletons.
authorAlexandre Vassalotti <alexandre@peadrop.com>
Sun, 1 Dec 2013 00:06:39 +0000 (16:06 -0800)
committerAlexandre Vassalotti <alexandre@peadrop.com>
Sun, 1 Dec 2013 00:06:39 +0000 (16:06 -0800)
Include/object.h
Lib/pickle.py
Lib/test/pickletester.py
Misc/NEWS
Modules/_pickle.c
Objects/object.c

index 20c4780e0c9faca34ab89707ce9ec66e216e3c05..5c89ca3a81289336ebf03317c012e3c22e8f1603 100644 (file)
@@ -831,6 +831,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').
index d62f014a6785b9a26f354e8cff9d1792a3f256be..386ffba7e2444791c83ab78eb8c112a3df7e386a 100644 (file)
@@ -728,9 +728,18 @@ class _Pickler:
 
         self.memoize(obj)
 
+    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(...):
+            return self.save_reduce(type, (...,), obj=obj)
+        return self.save_global(obj)
+
     dispatch[FunctionType] = save_global
     dispatch[BuiltinFunctionType] = save_global
-    dispatch[type] = save_global
+    dispatch[type] = save_type
 
 # Pickling helpers
 
index 86869e18e1600cf45b6a95df832e5bb003edf555..86d668ef6f012de02c053d0a9cdb98b2fd8e78ae 100644 (file)
@@ -768,6 +768,15 @@ class AbstractPickleTests(unittest.TestCase):
             u = self.loads(s)
             self.assertEqual(NotImplemented, u)
 
+    def test_singleton_types(self):
+        # Issue #6477: Test that types of built-in singletons can be pickled.
+        singletons = [None, ..., 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):
index 6e55d6636b59936a249e4c29c1a3bb816f3c4a7e..0acbafd600b02072359f89a4b7b0685532961ddf 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -24,6 +24,9 @@ Library
 - Fixed _pickle.Unpickler to not fail when loading empty strings as
   persistent IDs.
 
+- Issue #6477: Added support for pickling the types of built-in singletons
+  (i.e., Ellipsis, NotImplemented, None).
+
 - Issue #11508: Fixed uuid.getnode() and uuid.uuid1() on environment with
   virtual interface.  Original patch by Kent Frazier.
 
index d862ae876cdb41654c2f0027a7cb87fe106c0105..ba192fb78d43c192f62314c18b19ea2732770ba5 100644 (file)
@@ -2835,6 +2835,36 @@ save_notimplemented(PicklerObject *self, PyObject *obj)
     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, 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_pers(PicklerObject *self, PyObject *obj, PyObject *func)
 {
@@ -3189,7 +3219,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
         goto done;
     }
     else if (type == &PyType_Type) {
-        status = save_global(self, obj, NULL);
+        status = save_type(self, obj);
         goto done;
     }
     else if (type == &PyFunction_Type) {
index 949e7dc7f39d482f7308c424c149515cae4e415c..83da6a4ff070fcf181b639857a736d2b190cd76c 100644 (file)
@@ -1459,7 +1459,7 @@ static PyNumberMethods none_as_number = {
     0,                          /* nb_index */
 };
 
-static PyTypeObject PyNone_Type = {
+PyTypeObject PyNone_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     "NoneType",
     0,
@@ -1524,7 +1524,7 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     Py_RETURN_NOTIMPLEMENTED;
 }
 
-static PyTypeObject PyNotImplemented_Type = {
+PyTypeObject PyNotImplemented_Type = {
     PyVarObject_HEAD_INIT(&PyType_Type, 0)
     "NotImplementedType",
     0,