3

Closed

calling close on generator does not raise GeneratorExit

description

<Thanks>egonw_</Thanks>
<Test>Attached</Test>
 
IronPython2.0 RC2.
 
The output of IronPython2.0 RC2. of the attached file test2_close.py is the:
 
import test2_close
test2_close.test()
outer_goal: got ans == 1
test got: 1
outer_goal: after for
outer_iterable: close: begin, inner_it is <chain_context object at 0x00000000000
0002B>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x000000000000002
C>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: outer_it is <generator object at 0x000000000000002D>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x000000000000002E>
outer_iterable: close: outer_it hasattr close branch
outer_goal: after with
outer_goal: got ans == 3
test got: 3
outer_goal: after for
outer_iterable: close: begin, inner_it is <chain_context object at 0x00000000000
0002F>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x000000000000003
0>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: outer_it is <generator object at 0x0000000000000031>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x0000000000000032>
outer_iterable: close: outer_it hasattr close branch
outer_goal: after with
outer_goal: finally
outer_goal: done
outer_iterable: close: begin, inner_it is <chain_context object at 0x00000000000
00033>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x000000000000003
4>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: outer_it is <generator object at 0x0000000000000035>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x0000000000000036>
outer_iterable: close: outer_it hasattr close branch
test: done
 
In contrast the output of CPython 2.5 is:
 
import TestIronPython
import test2_close
test2_close.test()
outer_goal: got ans == 1
test got: 1
outer_goal: after for
outer_iterable: close: begin, inner_it is <test2_close.chain_context object at 0
x00B5EFD0>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x00B67878>
inner_goal: caught GeneratorExit()
inner_goal: finally
outer_iterable: close: inner_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B67170>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B67620>
outer_iterable: close: outer_it hasattr close branch
outer_goal: after with
outer_goal: got ans == 3
test got: 3
outer_goal: after for
outer_iterable: close: begin, inner_it is <test2_close.chain_context object at 0
x00B5EF50>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x00B67850>
inner_goal: caught GeneratorExit()
inner_goal: finally
outer_iterable: close: inner_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B67148>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B678C8>
outer_iterable: close: outer_it hasattr close branch
outer_goal: after with
outer_goal: finally
outer_goal: done
outer_iterable: close: begin, inner_it is <test2_close.chain_context object at 0
x00B5EDD0>
outer_iterable: close: inner_it hasattr exit branch
outer_iterable: close: begin, inner_it is <generator object at 0x00B64DF0>
outer_iterable: close: inner_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B64A80>
outer_iterable: close: outer_it hasattr close branch
outer_iterable: close: outer_it is <generator object at 0x00B22E90>
outer_iterable: close: outer_it hasattr close branch

test: done

 
It seems that the calling close of the inner_goal generator used within the with block of outer_goal does not cause any GeneratorExit exception within inner_goal. Thus, the execution thread does not pass the finally clause of inner_goal.
 
So, is this a bug of IronPython 2.0 or a delibarate decision to deviate from CPython 2.5. Actually, using generators and calling close on them does provoke a GeneratorExit exception for simpler usages than test2_close.py
 
Thanks
Egon

file attachments

Closed Feb 11, 2010 at 9:08 PM by dfugate
Verified the behavior of IPy 2.6.1 matches CPy 2.6.2 using the attached repro. Repro's a bit too big to add back into our suite of regression tests.

comments

egonw_ wrote Dec 15, 2008 at 6:22 AM

I tried test2_close.py on IronPython 2.0 as well. And it shows the same output.

Thanks
Egon

dangyogi wrote Dec 30, 2008 at 6:46 PM

I just wanted to point out the absence of the following two lines generated by CPY that the IronPython output lacks:

inner_goal: caught GeneratorExit()
inner_goal: finally

These two lines not being printed by IronPython is the what the problem is. All of the other lines are just to follow the strange program flow.

BTW, This test program is a gutted version of a much larger program that uses generators extensively. This larger program works on CPY 2.5 and the 2.5 compatible Jython but not on IronPython due to this strange bug. The strange thing is that calls to generator.close work fine in IronPython for simpler cases. This made the bug difficult to reproduce in a single .py file for submission here. After failing to reproduce the bug in simple situations, we finally reproduced a gutted copy of the whole program structure in a single .py file. This reproduces the bug in a single .py file that we have submitted here as test2_close.py.

So this test2_close.py file is not simply a crazy man taking pot shots at your implementation of the new generator close method, but is actually needed for the Pyke project to run on IronPython. (See pyke.sourceforge.net).

dfugate wrote Nov 17, 2009 at 5:36 PM

Under CPython 2.6, only "inner_goal: finally" is emitted (twice). There is no "inner_goal: caught GeneratorExit()".