classification
Title: __exit__ silences the active exception
Type: behavior Stage:
Components: Interpreter Core Versions: Python 3.0
process
Status: closed Resolution: fixed
Dependencies: Superseder: Lexical exception handlers
View: 3021
Assigned To: Nosy List: Rhamphoryncus, amaury.forgeotdarc, benjamin.peterson, ddvoinikov, georg.brandl, pitrou
Priority: release blocker Keywords:

Created on 2008-05-12 07:06 by ddvoinikov, last changed 2008-06-11 16:04 by benjamin.peterson. This issue is now closed.

Messages (10)
msg66713 - (view) Author: Dmitry Dvoinikov (ddvoinikov) Date: 2008-05-12 07:06
If a context manager is used within exception handling block, the active
exception is silenced after the context block completes and __exit__ exits.

try:
    raise Exception("foo")
except:
    with SomeContextManager():
        pass
    raise # in Py2.5 throws 'foo', in Py3.0 fails with RuntimeError
msg66724 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-05-12 14:20
This problem was introduced by r62847.
msg66775 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-05-13 09:10
Note that the problem is not related to "with", but with nested
exception handlers:

try:
    raise Exception("foo")
except:
    try: pass
    except: pass
    raise # in Py2.5 throws 'foo', in Py3.0 fails with RuntimeError


OTOH, python has always had poor support for nested exceptions; tried
with python24 and python25::

   try:
        raise Exception("foo")
   except:
      try: raise KeyError("caught")
      except KeyError: pass
      raise # reraise the KeyError...

This does not happen if the two lines with KeyError are moved in another
function.
msg66791 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-05-13 18:36
I've just discovered that the patch in r62847 doesn't clean up the
exception state if the except clause does not mention a local variable,
e.g. "except MyException" instead of "except MyException as e".
msg66794 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2008-05-13 19:22
Raising priority.
msg66811 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-05-14 09:21
As Amaury said, lexically nested exception handlers make re-raising
behaviour buggy. In Py3k, a workaround is to instead write:

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

With the slight inconvenience that the "raise e" line will be appended
to the original traceback.

If we want bare "raise" statements to work as expected after a nested
exception handler, we'll need to add proper exception stacking, for
example by adding the exception value as a member of PyTryBlock. The
effect on performance should also be measured.
msg66812 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-05-14 09:22
Small typo in the snippet above, this should obviously read:

   try:
      raise Exception("foo")
   except Exception as e:
      try: raise KeyError("caught")
      except KeyError: pass
      raise e
msg67302 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-05-24 14:13
Just found another funny example. This one fails also before r62847.

def except_yield():
    try:
        raise Exception("foo")
    except:
        yield 1
        raise
list(except_yield())

In Py3k (with or without r62487), we get "RuntimeError: No active
exception to reraise".
In Python 2.5, we get "TypeError: exceptions must be classes, instances,
or strings (deprecated), not NoneType".
msg67600 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-06-01 20:05
A clean solution to both #2507 and #2833 is now proposed in #3021.
msg67991 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-06-11 16:04
Fixed in r64121.
History
Date User Action Args
2008-06-11 16:04:44benjamin.petersonsetstatus: open -> closed
nosy: + benjamin.peterson
resolution: fixed
messages: + msg67991
2008-06-01 21:33:14benjamin.petersonsetsuperseder: Lexical exception handlers
2008-06-01 20:05:26pitrousetmessages: + msg67600
2008-05-30 20:33:37Rhamphoryncussetnosy: + Rhamphoryncus
2008-05-24 14:13:52pitrousetmessages: + msg67302
2008-05-14 09:22:26pitrousetmessages: + msg66812
2008-05-14 09:21:36pitrousetmessages: + msg66811
2008-05-13 19:22:12georg.brandlsetpriority: release blocker
nosy: + georg.brandl
messages: + msg66794
2008-05-13 18:36:21pitrousetmessages: + msg66791
2008-05-13 09:10:24amaury.forgeotdarcsetmessages: + msg66775
2008-05-13 08:37:23pitrousetnosy: + pitrou
2008-05-12 14:20:54amaury.forgeotdarcsetnosy: + amaury.forgeotdarc
messages: + msg66724
2008-05-12 07:06:53ddvoinikovcreate