Pickling/Unpickling python Exceptions

Sergey Lukin lukin.s.v at gmail.com
Thu Jan 27 10:49:45 EST 2011


Hi all,

I'm migrating code from python 2.4 to python 2.6 and I've got into troubles
with pickling/unpickling  python Exceptions.
The following code works fine in 2.4 but not in 2.6.
See Exception1 example

I have found on python mail list similar problem
http://mail.python.org/pipermail/python-list/2009-December/1228773.html
They recommend to use __reduce__. But this does not help as I'm getting
different Exception class after pickle
See Exception_with_reduce example

I also have found possible solution to this problem here
http://bugs.python.org/issue1692335
As a workaround they propose to pass Exception arguments into base class
See Exception2 example
But there is another problem. Constructor is called 2 times which is not
acceptable to me.

Could you please advice on the solution?

------------------------------------------
test program
------------------------------------------
import cPickle

class Exception1(Exception):
    def __init__(self,arg1):
        print "constructor called"
        Exception.__init__(self)

class Exception2(Exception):
    def __init__(self,arg1):
        print "constructor called"
        Exception.__init__(self,arg1)

class Exception_with_reduce(Exception):
    def __reduce__(self):
        try:
            getnewargs = self.__getnewargs__
        except AttributeError:
            newargs = (self.__class__,)
        else:
            newargs = (self.__class__,) + getnewargs()

        try:
            getstate = self.__getstate__
        except AttributeError:
            state = self.__dict__
        else:
            state = getstate()
        return (Exception, newargs, state)

    def __init__(self,arg1):
        print "constructor called"
        Exception.__init__(self,arg1)

def test(E,args):
    try:
        print ">>",E.__name__
        e = E(*args)
        print "- pickling"
        s = cPickle.dumps(e)
        print "- unpickling"
        e = cPickle.loads(s)

        if E != e.__class__:
            print "! failed: expected %s, got
%s"%(E.__name__,e.__class__.__name__)
    except Exception, e:
        print "! failed:",e

    print "\ finished"
    print


import os
if os.path.isfile("/home/ast1/blabla"):
    try:
        s = open("/home/ast1/blabla","r").read()
        e = cPickle.loads(s)
        print e.__class__
    except Exception, e:
        print "error:",e

test(Exception1,[1])
test(Exception2,[1])
test(Exception_with_reduce,[1])
------------------------------------------


------------------------------------------
run results on python 2.6:
------------------------------------------

constructor called
<class '__main__.Exception2'>
>> Exception1
constructor called
- pickling
- unpickling
! failed: ('__init__() takes exactly 2 arguments (1 given)', <class
'__main__.Exception1'>, ())
\ finished

>> Exception2
constructor called
- pickling
- unpickling
constructor called
\ finished

>> Exception_with_reduce
constructor called
- pickling
- unpickling
! failed: expected Exception_with_reduce, got Exception
\ finished

------------------------------------------
run results on python 2.4:
------------------------------------------

__main__.Exception2
>> Exception1
constructor called
- pickling
- unpickling
\ finished

>> Exception2
constructor called
- pickling
- unpickling
\ finished

>> Exception_with_reduce
constructor called
- pickling
- unpickling
\ finished
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20110127/a1318b05/attachment.html>


More information about the Python-list mailing list