[Cython] Recent bugs in generators

Vitja Makarov vitja.makarov at gmail.com
Mon Apr 18 06:38:20 CEST 2011


2011/4/18 Stefan Behnel <stefan_ml at behnel.de>:
> Vitja Makarov, 17.04.2011 17:57:
>>
>> 3. check_yield_in_exception()
>
> I added this because I found a failing pyregr test that uses it (testing the
> @contextmanager decorator).
>
>
>> Cython calls __Pyx_ExceptionReset when except block is done, so when
>> yield is there no exception reset is called.
>>
>> I'm not sure how to fix this.
>
> I'm not completely sure either.
>
>
>> import sys
>>
>> def foo():
>>     """
>>     >>>  list(foo())
>>     [<type 'exceptions.ValueError'>, None]
>>     """
>>     try:
>>         raise ValueError
>>     except ValueError:
>>         yield sys.exc_info()[0]
>>         yield sys.exc_info()[0] # exc_info is lost here
>
> I think (!), the difference here is that CPython actually keeps the
> exception in the generator frame. We don't have a frame, so we have to
> emulate it using the closure class. I guess we'll have to store away the
> exception into the closure when we yield while an exception is being
> handled, and restore it afterwards. Note: this is not the exception that is
> freshly *being* raised (the "_cur*" fields in the thread state), it's the
> exception that *was* raised and is now being handled, i.e. the thread state
> fields without the "_cur", that are reflected by sys.exc_info().
>

Interesting difference between py2 and py3:

def foo():
    try:
        raise ValueError
    except ValueError:
        yield
        raise
list(foo())

  File "xxx.py", line 7, in <module>
    list(foo())
  File "xxx.py", line 6, in foo
    raise
TypeError: exceptions must be old-style classes or derived from
BaseException, not NoneType

It seems that exception info is completely lost (tried 2.6, 2.7) and
seems to be fixed in python3.

Btw exception info temps are already saved and restored between yields.


-- 
vitja.


More information about the cython-devel mailing list