Index: Modules/_pickle.c =================================================================== --- Modules/_pickle.c (revision 65456) +++ Modules/_pickle.c (working copy) @@ -316,6 +316,8 @@ objects. */ int fast_nesting; PyObject *fast_memo; + PyObject *dispatch; /* Dispatch dictionary, used to extend or + modify Pickler. */ } PicklerObject; typedef struct UnpicklerObject { @@ -2089,6 +2091,30 @@ type = Py_TYPE(obj); + /* Mimic the dispatch dictionary in the Python implementation of Pickler. + This check should be done first to allows the pickling process of + built-in types to be overridden (like in pickle.py). */ + reduce_func = PyDict_GetItemWithError(self->dispatch, (PyObject *)type); + if (reduce_func != NULL) { + /* Here, the reference count of reduce_func is increased to + allow the blind DECREF at the end of the save() routine. */ + Py_INCREF(reduce_func); + /* reduce_value is unused and should be Py_None. + XXX: Perhaps a warning should be issued if reduce_value + is not Py_None? */ + reduce_value = PyObject_CallFunctionObjArgs(reduce_func, + (PyObject *)self, + obj, + NULL); + if (reduce_value == NULL) + goto error; + else + goto done; + } + else if (PyErr_Occurred()) { + goto error; + } + /* XXX: The old cPickle had an optimization that used switch-case statement dispatching on the first letter of the type name. It was probably not a bad idea after all. If benchmarks shows that particular @@ -2349,6 +2375,7 @@ Py_XDECREF(self->pers_func); Py_XDECREF(self->arg); Py_XDECREF(self->fast_memo); + Py_XDECREF(self->dispatch); PyMem_Free(self->write_buf); @@ -2363,6 +2390,7 @@ Py_VISIT(self->pers_func); Py_VISIT(self->arg); Py_VISIT(self->fast_memo); + Py_VISIT(self->dispatch); return 0; } @@ -2374,6 +2402,7 @@ Py_CLEAR(self->pers_func); Py_CLEAR(self->arg); Py_CLEAR(self->fast_memo); + Py_CLEAR(self->dispatch); PyMem_Free(self->write_buf); self->write_buf = NULL; @@ -2461,6 +2490,9 @@ self->memo = PyDict_New(); if (self->memo == NULL) return -1; + self->dispatch = PyDict_New(); + if (self->dispatch == NULL) + return -1; return 0; } @@ -2499,6 +2531,16 @@ } static PyObject * +Pickler_get_dispatch(PicklerObject *self) +{ + if (self->dispatch == NULL) + PyErr_SetString(PyExc_AttributeError, "dispatch"); + else + Py_INCREF(self->dispatch); + return self->dispatch; +} + +static PyObject * Pickler_get_persid(PicklerObject *self) { if (self->pers_func == NULL) @@ -2539,10 +2581,12 @@ }; static PyGetSetDef Pickler_getsets[] = { + {"dispatch", (getter)Pickler_get_dispatch, NULL}, {"memo", (getter)Pickler_get_memo, (setter)Pickler_set_memo}, {"persistent_id", (getter)Pickler_get_persid, (setter)Pickler_set_persid}, + {NULL} };