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)

msg31860 - (view)

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.

msg57002 - (view)

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.

msg57045 - (view)

Author: Alyssa Coghlan (ncoghlan) * (Python committer)

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()

msg57046 - (view)

Author: Alyssa Coghlan (ncoghlan) * (Python committer)

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.

msg57193 - (view)

Author: Neal Norwitz (nnorwitz) * (Python committer)

Date: 2007-11-07 07:21

Nick, can you backport this and add a NEWS entry? Thanks.

msg57197 - (view)

Author: Alyssa Coghlan (ncoghlan) * (Python committer)

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