[Patches] [ python-Patches-1692335 ] Move initial args assignment to BaseException.__new__

SourceForge.net noreply at sourceforge.net
Sun Aug 12 14:34:47 CEST 2007


Patches item #1692335, was opened at 2007-04-01 15:46
Message generated for change (Comment added) made by zseil
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1692335&group_id=5470

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: Core (C code)
Group: Python 2.5
Status: Open
Resolution: None
Priority: 5
Private: No
Submitted By: Ziga Seilnacht (zseil)
Assigned to: Nobody/Anonymous (nobody)
Summary: Move initial args assignment to BaseException.__new__

Initial Comment:
Pickling exceptions fails when an Exception class
requires an argument in the constructor, but doesn't
call its base class' constructor.  See this mail
for details:

http://mail.python.org/pipermail/python-dev/2007-April/072416.html

This patch simply moves initial args assignment to
BaseException.__new__. This should fix most of the
problems, because it is very unlikely that an
exception overwrites the __new__ method; exceptions
used to be old style classes, which don't support
the __new__ special method.

The args attribute is still overwritten in all the
__init__ methods, so there shouldn't be any backward
compatibility problems.



----------------------------------------------------------------------

>Comment By: Ziga Seilnacht (zseil)
Date: 2007-08-12 14:34

Message:
Logged In: YES 
user_id=1326842
Originator: YES

It's not just the message attribute; the problem is
that the current code expects that the exception
won't be modified between creation and unpickling.

For example:

>>> import pickle
>>> e = EnvironmentError()
>>> e.filename = "x"
>>> new = pickle.dumps(pickle.loads(e))
>>> print new.filename
None
>>> e = SyntaxError()
>>> e.lineno = 10
>>> new = pickle.loads(pickle.dumps(e))
>>> print new.lineno
None


----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2007-08-12 14:13

Message:
Logged In: YES 
user_id=849994
Originator: NO

I wouldn't care too much about .message; it was new in 2.5 and is already
deprecated in 2.6.

----------------------------------------------------------------------

Comment By: Ziga Seilnacht (zseil)
Date: 2007-08-12 13:24

Message:
Logged In: YES 
user_id=1326842
Originator: YES

File Added: exception_pickling_26.diff

----------------------------------------------------------------------

Comment By: Ziga Seilnacht (zseil)
Date: 2007-08-12 13:23

Message:
Logged In: YES 
user_id=1326842
Originator: YES

There is also the problem that Jim Fulton mentioned
in bug #1742889; if the user modifies the 'message'
attribute of an exception (or any other attribute
that is not stored in the __dict__), it won't get
serialized on pickling.

Attaching a new patch that fixes this by using the
__getstate__() pickling hook.  It uses tp_members
and tp_getset members of the type object to find
all the attributes that need to be serialized.

The 2.5 patch also contains a fix for migrating
old exception pickles to Python 2.5.  For that
I had to change cPickle and pickle.  It would
be nice if Jim could comment if this change is
needed, since ZODB is probably the biggest user
of these modules.

The downside is that this patch is fairly big.

File Added: exception_pickling_25.diff

----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2007-08-12 10:01

Message:
Logged In: YES 
user_id=849994
Originator: NO

The only question left is what to do if something reassigns
exceptioninstance.args.

----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2007-08-12 10:00

Message:
Logged In: YES 
user_id=849994
Originator: NO

The only question left is what to do if something reassigns
exceptioninstance.args.

----------------------------------------------------------------------

Comment By: Eric Huss (ehuss)
Date: 2007-08-12 03:33

Message:
Logged In: YES 
user_id=393416
Originator: NO

Georg's new patch looks good to me, it seems to pass all the scenarios
that I know of.  You can close out my patch if you check this in.  Thanks
for looking into this!


----------------------------------------------------------------------

Comment By: Neal Norwitz (nnorwitz)
Date: 2007-08-11 20:27

Message:
Logged In: YES 
user_id=33168
Originator: NO

self->args needs to be initialized to NULL because if the alloc of args
failed, self->args would be uninitialized and deallocated.  (I realize the
alloc of an empty tuple will realistically never fail currently.)

I'm not sure if this could cause any new problems because of the behavior
change, but the code itself looked fine to me.  Hopefully someone with more
knowledge of exceptions could take a look at the idea.

----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2007-08-11 11:06

Message:
Logged In: YES 
user_id=849994
Originator: NO

Attaching a new patch that fixes the 

class D(Exception):
    def __init__(self, foo):
        self.foo = foo
        Exception.__init__(self)

scenario by keeping the original args to __new__ as an exception
attribute.
File Added: exception-pickling.diff

----------------------------------------------------------------------

Comment By: Georg Brandl (gbrandl)
Date: 2007-08-11 11:06

Message:
Logged In: YES 
user_id=849994
Originator: NO

Attaching a new patch that fixes the 

class D(Exception):
    def __init__(self, foo):
        self.foo = foo
        Exception.__init__(self)

scenario by keeping the original args to __new__ as an exception
attribute.
File Added: exception-pickling.diff

----------------------------------------------------------------------

Comment By: Eric Huss (ehuss)
Date: 2007-06-27 20:45

Message:
Logged In: YES 
user_id=393416
Originator: NO

Added patch #1744398 as an alternate solution.


----------------------------------------------------------------------

Comment By: Eric Huss (ehuss)
Date: 2007-06-15 02:34

Message:
Logged In: YES 
user_id=393416
Originator: NO

I have stumbled across another scenario where unpickling fails.  If your
exception takes arguments, but you call Exception.__init__ with a different
number of arguments, it will fail.  As in:

class D(Exception):
    def __init__(self, foo):
        self.foo = foo
        Exception.__init__(self)


----------------------------------------------------------------------

Comment By: Ziga Seilnacht (zseil)
Date: 2007-04-01 23:50

Message:
Logged In: YES 
user_id=1326842
Originator: YES

I'm attaching a test that Eric Huss sent in private
mail.

The test fails, because old exception pickles don't
have args for the reconstructor, but their __init__()
gets called anyway because they are new style classes
now.

The problem is in cPickle.InstanceNew() and
pickle.Unpickler._instantiate().  Those methods behave
differently depending on the type of the object
instantiated; they avoid the __init__() call when type
is an old style class.

There is nothing that can be done in the exception
classes to fix this issue; the fix would need to be
in the pickle and cPickle module.
File Added: test_exception_pickle.py

----------------------------------------------------------------------

Comment By: Ziga Seilnacht (zseil)
Date: 2007-04-01 15:47

Message:
Logged In: YES 
user_id=1326842
Originator: YES

File Added: exc_args_25.diff

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1692335&group_id=5470


More information about the Patches mailing list