2011/4/20 Stefan Behnel <stefan...@behnel.de>:
> Vitja Makarov, 20.04.2011 10:26:
>>
>> 2011/4/18 Stefan Behnel:
>>>
>>> Vitja Makarov, 18.04.2011 06:38:
>>>>
>>>> 2011/4/18 Stefan Behnel:
>>>>>
>>>>> 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.
>>>
>>> Not surprising. The implementation is completely different in Py2 and
>>> Py3,
>>> both in CPython and in Cython. It's actually much simpler in Cython under
>>> Py3, due to better semantics and C-API support. That also implies that
>>> there's much less Cython can do wrong in that environment. ;-)
>>>
>>>
>>>> Btw exception info temps are already saved and restored between yields.
>>>
>>> Right, but the exc_info itself is not reset and recovered around the
>>> yield.
>>> As I said above, generators have their own lifetime frame in CPython, and
>>> exceptions don't leak from that. So, whenever it's the generator (or code
>>> called by it) that raises an exception, that must be kept local to the
>>> generator.
>>
>> Please review:
>>
>> https://github.com/vitek/cython/commit/73014aaed10b82a3f632d7f86212f86280c55858
>>
>> I've added __Pyx_Generator_SwapExceptions() method and call it right
>> before resume switch and before return from yield. It swaps generator
>> exception state with thread local.
>
> Looks good to me. I assume this fixes the problem? Then please push it into
> mainline.
>

old pull request is still there ;)

https://github.com/cython/cython/pull/25

Does __Pyx_ExceptionReset() steal references to args, so they should
not be decrefed later?


-- 
vitja.
_______________________________________________
cython-devel mailing list
cython-devel@python.org
http://mail.python.org/mailman/listinfo/cython-devel

Reply via email to