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

This commit is contained in:
Alexandre Vassalotti 2013-11-30 16:06:39 -08:00
parent f8ceb04fcf
commit 19b6fa6ebb
6 changed files with 58 additions and 4 deletions

View 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_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').

View file

@ -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

View file

@ -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):

View file

@ -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.

View file

@ -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)
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) {

View file

@ -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)
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,