Issue 1705170: contextmanager eats StopIteration (original) (raw)
Created on 2007-04-22 06:56 by Rhamphoryncus, last changed 2022-04-11 14:56 by admin. This issue is now closed.
Messages (6)
Author: Adam Olsen (Rhamphoryncus)
Date: 2007-04-22 06:56
This is the same bug recently reported by Bob Sidebotham on python-dev (http://mail.python.org/pipermail/python-dev/2007-April/072484.html), but my test-case doesn't involve an overly broad try/except block.
It also seems similar to Bug 1462485, which has been closed and marked fixed, but I can reproduce with my test-case using both python 2.5 and python-trunk (revision 54759).
The irony is that catching the exception to add debugging forces it to be instantiated, thereby avoiding the bug.
Author: Mike Klaas (klaas)
Date: 2007-10-31 20:26
Verified on 2.5.0. The problem stems from contextmanager.exit:
def exit(self, type, value, traceback): if type is None: try: self.gen.next() except StopIteration: return else: raise RuntimeError("generator didn't stop") else: try: self.gen.throw(type, value, traceback) raise RuntimeError("generator didn't stop after throw ()") except StopIteration, exc: # Suppress the exception unless it's the same exception that # was passed to throw(). This prevents a StopIteration # raised inside the "with" statement from being suppressed return exc is not value except: # only re-raise if it's not the exception that was # passed to throw(), because exit() must not raise # an exception unless exit() itself failed. But throw() # has to raise the exception to signal propagation, so this # fixes the impedance mismatch between the throw() protocol # and the exit() protocol. # if sys.exc_info()[1] is not value: raise
Conjecture: internal StopIteration exceptions are always the same instance (PyExc_StopIteration) when propagated to python, invalidating the return exc is not value check.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2007-11-02 09:45
Close, but not quite. The problem is that the 'value' argument may be None if instantiation of the exception hasn't been forced before exit gets called.
class TestWith(object): ... def enter(self): ... pass ... def exit(self, exc_type, exc_value, exc_tb): ... print exc_type, exc_value, exc_tb ... from future import with_statement with TestWith(): iter([]).next() ... <type 'exceptions.StopIteration'> None <traceback object at 0xb76bed4c> Traceback (most recent call last): File "", line 1, in StopIteration
That 'None' in the middle there is the problem - contextmanager.exit needs to be detecting that and instantiating the passed in exception if it isn't already instantiated. Something like the following at the start of the else clause should do the trick:
if value is None: value = type()
Author: Alyssa Coghlan (ncoghlan) *
Date: 2007-11-02 10:13
Fixed for 2.6 in rev 58766. I'm not sure if it will be possible to get this into 2.5.2.
Leaving open against 2.5 until it is checked in on the maintenance branch.
Author: Neal Norwitz (nnorwitz) *
Date: 2007-11-07 07:21
Nick, can you backport this and add a NEWS entry? Thanks.
Author: Alyssa Coghlan (ncoghlan) *
Date: 2007-11-07 12:27
Done in rev 58901
History
Date
User
Action
Args
2022-04-11 14:56:23
admin
set
github: 44880
2007-11-07 12:27:18
ncoghlan
set
status: open -> closed
resolution: accepted -> fixed
messages: +
2007-11-07 07:21:41
nnorwitz
set
nosy: + nnorwitz
messages: +
2007-11-02 10:14:05
ncoghlan
set
assignee: ncoghlan
2007-11-02 10:13:39
ncoghlan
set
resolution: accepted
messages: +
components: + Library (Lib), - None
versions: + Python 2.5
2007-11-02 09:45:18
ncoghlan
set
nosy: + ncoghlan
messages: +
2007-10-31 20:26:22
klaas
set
nosy: + klaas
messages: +
2007-04-22 06:56:50
Rhamphoryncus
create