Commit 19b6fa6e authored by Alexandre Vassalotti's avatar Alexandre Vassalotti

Issue #6477: Added support for pickling the types of built-in singletons.

parent f8ceb04f
...@@ -831,6 +831,9 @@ they can have object code that is not dependent on Python compilation flags. ...@@ -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_IncRef(PyObject *);
PyAPI_FUNC(void) Py_DecRef(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 _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'). where NULL (nil) is not suitable (since NULL often means 'error').
......
...@@ -728,9 +728,18 @@ class _Pickler: ...@@ -728,9 +728,18 @@ class _Pickler:
self.memoize(obj) 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[FunctionType] = save_global
dispatch[BuiltinFunctionType] = save_global dispatch[BuiltinFunctionType] = save_global
dispatch[type] = save_global dispatch[type] = save_type
# Pickling helpers # Pickling helpers
......
...@@ -768,6 +768,15 @@ class AbstractPickleTests(unittest.TestCase): ...@@ -768,6 +768,15 @@ class AbstractPickleTests(unittest.TestCase):
u = self.loads(s) u = self.loads(s)
self.assertEqual(NotImplemented, u) 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 # Tests for protocol 2
def test_proto(self): def test_proto(self):
......
...@@ -24,6 +24,9 @@ Library ...@@ -24,6 +24,9 @@ Library
- Fixed _pickle.Unpickler to not fail when loading empty strings as - Fixed _pickle.Unpickler to not fail when loading empty strings as
persistent IDs. 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 - Issue #11508: Fixed uuid.getnode() and uuid.uuid1() on environment with
virtual interface. Original patch by Kent Frazier. virtual interface. Original patch by Kent Frazier.
......
...@@ -2835,6 +2835,36 @@ save_notimplemented(PicklerObject *self, PyObject *obj) ...@@ -2835,6 +2835,36 @@ save_notimplemented(PicklerObject *self, PyObject *obj)
return res; 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 static int
save_pers(PicklerObject *self, PyObject *obj, PyObject *func) save_pers(PicklerObject *self, PyObject *obj, PyObject *func)
{ {
...@@ -3189,7 +3219,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save) ...@@ -3189,7 +3219,7 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
goto done; goto done;
} }
else if (type == &PyType_Type) { else if (type == &PyType_Type) {
status = save_global(self, obj, NULL); status = save_type(self, obj);
goto done; goto done;
} }
else if (type == &PyFunction_Type) { else if (type == &PyFunction_Type) {
......
...@@ -1459,7 +1459,7 @@ static PyNumberMethods none_as_number = { ...@@ -1459,7 +1459,7 @@ static PyNumberMethods none_as_number = {
0, /* nb_index */ 0, /* nb_index */
}; };
static PyTypeObject PyNone_Type = { PyTypeObject PyNone_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"NoneType", "NoneType",
0, 0,
...@@ -1524,7 +1524,7 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) ...@@ -1524,7 +1524,7 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
Py_RETURN_NOTIMPLEMENTED; Py_RETURN_NOTIMPLEMENTED;
} }
static PyTypeObject PyNotImplemented_Type = { PyTypeObject PyNotImplemented_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"NotImplementedType", "NotImplementedType",
0, 0,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment