[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