◐ Shell
clean mode source ↗

Message 166477 - Python tracker

I see that the originally proposed patch is more or less what I suggested above.  Since this has been a critical issue for 5 years, I think such a minimal patch should be committed even though it is not a complete solution.

It seems to me that the more complicated patch exception_pickling_26.diff has a significant overlap with _common_reduce() in typeobject.c.

The patch actually attempts to be *more* general than _common_reduce() since it collects data from tp_getset and tp_members, whereas _common_reduce() only collects data from __slots__.  The patch does not seem to take account of read-only members/getsetters, which I think would cause exceptions when unpickling.

An alternative implementation piggy-backing on _common_reduce() (and using __reduce__ rather than __getstate__) would be

def __reduce__(self):
    slots = None
    func, args, state = object.__reduce__(self, 2)[:3]
    if type(state) is tuple:
        state, slots = state
    newstate = {'args': self.args}
    if state:
        newstate.update(state)
    if slots:
        newstate.update(slots)
    return func, args, newstate

This deals correctly with slots and works with all protocols.  However, the pickles produced can only be unpickled on versions where exceptions are new-style classes, ie Python 2.5 and later.

This would have the side effect that __init__() would no longer be called while unpickling.