Make built-in methods picklable through the reduce protocol.

This commit is contained in:
Alexandre Vassalotti 2013-11-24 02:41:05 -08:00
parent d606ba7f55
commit 4c05d3bc56
3 changed files with 22 additions and 41 deletions

View File

@ -23,7 +23,7 @@ Misc variables:
"""
from types import FunctionType, BuiltinFunctionType, ModuleType
from types import FunctionType, ModuleType
from copyreg import dispatch_table
from copyreg import _extension_registry, _inverted_registry, _extension_cache
from itertools import islice
@ -962,14 +962,7 @@ class _Pickler:
self.memoize(obj)
def save_method(self, obj):
if obj.__self__ is None or type(obj.__self__) is ModuleType:
self.save_global(obj)
else:
self.save_reduce(getattr, (obj.__self__, obj.__name__), obj=obj)
dispatch[FunctionType] = save_global
dispatch[BuiltinFunctionType] = save_method
dispatch[type] = save_global

View File

@ -3513,34 +3513,6 @@ save_reduce(PicklerObject *self, PyObject *args, PyObject *obj)
return 0;
}
static int
save_method(PicklerObject *self, PyObject *obj)
{
PyObject *method_self = PyCFunction_GET_SELF(obj);
if (method_self == NULL || PyModule_Check(method_self)) {
return save_global(self, obj, NULL);
}
else {
PyObject *builtins;
PyObject *getattr;
PyObject *reduce_value;
int status = -1;
_Py_IDENTIFIER(getattr);
builtins = PyEval_GetBuiltins();
getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
reduce_value = \
Py_BuildValue("O(Os)", getattr, method_self,
((PyCFunctionObject *)obj)->m_ml->ml_name);
if (reduce_value != NULL) {
status = save_reduce(self, reduce_value, obj);
Py_DECREF(reduce_value);
}
return status;
}
}
static int
save(PicklerObject *self, PyObject *obj, int pers_save)
{
@ -3652,10 +3624,6 @@ save(PicklerObject *self, PyObject *obj, int pers_save)
goto done;
}
}
else if (type == &PyCFunction_Type) {
status = save_method(self, obj);
goto done;
}
/* XXX: This part needs some unit tests. */

View File

@ -159,6 +159,26 @@ meth_dealloc(PyCFunctionObject *m)
}
}
static PyObject *
meth_reduce(PyCFunctionObject *m)
{
PyObject *builtins;
PyObject *getattr;
_Py_IDENTIFIER(getattr);
if (m->m_self == NULL || PyModule_Check(m->m_self))
return PyUnicode_FromString(m->m_ml->ml_name);
builtins = PyEval_GetBuiltins();
getattr = _PyDict_GetItemId(builtins, &PyId_getattr);
return Py_BuildValue("O(Os)", getattr, m->m_self, m->m_ml->ml_name);
}
static PyMethodDef meth_methods[] = {
{"__reduce__", (PyCFunction)meth_reduce, METH_NOARGS, NULL},
{NULL, NULL}
};
/*
* finds the docstring's introspection signature.
* if present, returns a pointer pointing to the first '('.
@ -394,7 +414,7 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
meth_methods, /* tp_methods */
meth_members, /* tp_members */
meth_getsets, /* tp_getset */
0, /* tp_base */