[Python-3000] Exception re-raising woes

Robert Brewer fumanchu at aminus.org
Mon May 26 18:29:26 CEST 2008


Antoine Pitrou wrote:
> Trying to fix #2507 (Exception state lives too long in 3.0) has
> uncovered new issues with the bare "raise" statement when in used
> in exception block nesting situations (see #2833: __exit__
> silences the active exception). I say "uncovered" rather than
> "created" since, as Amaury points out in the latter bug entry,
> re-raising behaviour has always been a bit limited or non-obvious.
> 
> Witness the following code:
> 
>    try:
>       raise Exception("foo")
>    except Exception:
>       try: raise KeyError("caught")
>       except KeyError: pass
>       raise
> 
> With python 2.x and py3k pre-r62847, it would re-raise 
> KeyError("caught") (whereas the intuitive behaviour would
> be to re-raise Exception("foo")). With py3k post-r62847,
> it now raises a "RuntimeError: No active exception to
> reraise".
> 
> Note that in py3k at least, we can get the "correct" behaviour by
> writing instead:
> 
>    try:
>       raise Exception("foo")
>    except Exception as e:
>       try: raise KeyError("caught")
>       except KeyError: pass
>       raise e
> 
> The only slight annoyance being that the re-raising statement
> ("raise e") is added at the end of the original traceback.

I wouldn't call that either "incorrect" or "non-obvious".
It certainly hasn't been a burden in Python 2.x.

> There are other funny situations. Just try (with any Python version):
> 
> def except_yield():
>     try:
>         raise Exception("foo")
>     except:
>         yield 1
>         raise
> list(except_yield())
> 
> The problem with properly fixing the bare "raise" statement is that
> right now, the saved exception state is a member of the frame object.
> That is, there is no proper stacking of exception states when some
> lexically nested exception handlers are involved in the same frame.
> 
> Now perhaps it is time to think about fixing that problem, without
> losing the expected properties of exceptions in py3k. I propose
> the following changes:
> 
> - an "except" block now also becomes a block in ceval.c terms,
> that is, a specific PyTryBlock is pushed at its beginning (please
> note that right now SETUP_EXCEPT, despite its name, encloses the
> "try" block rather than any "except" statement)
> [snip lots more changes]

That seems like an awful lot of work and change just to trade the above
problem for a new one:

    try:
       raise Exception("foo")
    except Exception as e:
       try: raise KeyError("caught")
       except KeyError as x: pass
       raise x

In either case, it's easy enough to bind the exception to a name--easier
in 2.6/3k with the abolition of string exceptions (since "except
BaseException" now catches everything).


Robert Brewer
fumanchu at aminus.org



More information about the Python-3000 mailing list