Hi all,<br><br>I'm migrating code from python 2.4 to python 2.6 and I've got into troubles with pickling/unpickling python Exceptions.<br>The following code works fine in 2.4 but not in 2.6.<br>See Exception1 example<br>
<br>I have found on python mail list similar problem <br><a href="http://mail.python.org/pipermail/python-list/2009-December/1228773.html" target="_blank">http://mail.python.org/pipermail/python-list/2009-December/1228773.html</a><br>
They recommend to use __reduce__. But this does not help as I'm getting different Exception class after pickle<br>See Exception_with_reduce example<br><br>I also have found possible solution to this problem here<br><a href="http://bugs.python.org/issue1692335">http://bugs.python.org/issue1692335</a><br>
As a workaround they propose to pass Exception arguments into base class<br>See Exception2 example<br>But there is another problem. Constructor is called 2 times which is not acceptable to me.<br><br>Could you please advice on the solution?<br>
<br>------------------------------------------<br>test program<br>------------------------------------------<br>import cPickle<br><br>class Exception1(Exception):<br> def __init__(self,arg1):<br> print "constructor called"<br>
Exception.__init__(self)<br> <br>class Exception2(Exception):<br> def __init__(self,arg1):<br> print "constructor called"<br> Exception.__init__(self,arg1)<br><br>class Exception_with_reduce(Exception):<br>
def __reduce__(self):<br> try:<br> getnewargs = self.__getnewargs__<br> except AttributeError:<br> newargs = (self.__class__,)<br> else:<br> newargs = (self.__class__,) + getnewargs()<br>
<br> try:<br> getstate = self.__getstate__<br> except AttributeError:<br> state = self.__dict__<br> else:<br> state = getstate()<br> return (Exception, newargs, state)<br>
<br> def __init__(self,arg1):<br> print "constructor called"<br> Exception.__init__(self,arg1)<br><br>def test(E,args):<br> try:<br> print ">>",E.__name__<br> e = E(*args)<br>
print "- pickling"<br> s = cPickle.dumps(e)<br> print "- unpickling"<br> e = cPickle.loads(s)<br> <br> if E != e.__class__:<br> print "! failed: expected %s, got %s"%(E.__name__,e.__class__.__name__)<br>
except Exception, e:<br> print "! failed:",e<br> <br> print "\ finished"<br> print <br> <br> <br>import os<br>if os.path.isfile("/home/ast1/blabla"):<br> try:<br>
s = open("/home/ast1/blabla","r").read()<br> e = cPickle.loads(s)<br> print e.__class__<br> except Exception, e:<br> print "error:",e<br> <br>test(Exception1,[1])<br>
test(Exception2,[1])<br>test(Exception_with_reduce,[1])<br>------------------------------------------<br><br><br>------------------------------------------<br>
run results on python 2.6:<br>
------------------------------------------<br>
<br>
constructor called<br><class '__main__.Exception2'><br>>> Exception1<br>constructor called<br>- pickling<br>- unpickling<br>! failed: ('__init__() takes exactly 2 arguments (1 given)', <class '__main__.Exception1'>, ())<br>
\ finished<br><br>>> Exception2<br>constructor called<br>- pickling<br>- unpickling<br>constructor called<br>\ finished<br><br>>> Exception_with_reduce<br>constructor called<br>- pickling<br>- unpickling<br>! failed: expected Exception_with_reduce, got Exception<br>
\ finished<br><br>------------------------------------------<br>
run results on python 2.4:<br>
------------------------------------------<br>
<br>__main__.Exception2<br>>> Exception1<br>constructor called<br>- pickling<br>- unpickling<br>\ finished<br><br>>> Exception2<br>constructor called<br>- pickling<br>- unpickling<br>\ finished<br><br>>> Exception_with_reduce<br>
constructor called<br>- pickling<br>- unpickling<br>\ finished<br><br><br><br><br>