STINNER Victor added the comment: Attached gen_exc_value.patch changes how generators handle the currently handled exception (tstate->exc_value). The patch probably lacks tests to test the exact behaviour of sys.exc_info(). The 3 examples below can be used to write such tests. But before investing time on an implemenation, I would like to ensure that I correctly understood the bug and discuss how it should be fixed.
Currently, a generator inherits the currently handled exception from the "caller" (function calling next(), gen.send() or gen.throw()). With the patch, the generator and its caller don't share the exception anymore. The generator still remembers the current exception when it is interrupted by yield. It's still possible to pass the exception from the caller to the generator using the throw() method of the generator. My patch doesn't change the behaviour of throw(): see the example 3 below. The patch also fixes the initial issue: "./python -m test test_asyncio test_functools" doesn't fail anymore. Python 2.7 is also affected by the bug. I don't know yet if it's safe to change the behaviour of currently handled exception in Python 2 generators. It may break backward compatibility. We should probably check applications which heavily depends on generators. For example, the Trollius and Twisted projects use generators for coroutines in asynchronous programming. The backward compatibility also matters in Python 3.4, so same question: should we change the behaviour of Python 3.4? Can it break applications? In Python 3, the currently handled exception is more important than in Python 2, because it is used to automatically fill the __context__ attribute of raised exceptions. I didn't test the behaviour of yield-from yet, I don't know how my patch changes its behaviour. Example 1: --- import sys def gen(): print(sys.exc_info()) yield g = gen() try: raise ValueError except Exception: next(g) --- Original output: --- (<class 'ValueError'>, ValueError(), <traceback object at 0x7f22a1ab52c8>) --- With the patch: --- (None, None, None) --- Example 2: --- import sys def gen(): try: yield raise TypeError() except: print(sys.exc_info()) print(sys.exc_info()) yield g = gen() next(g) try: raise ValueError except Exception: next(g) --- Original output: --- (<class 'TypeError'>, TypeError(), <traceback object at 0x7fad239a22c8>) (<class 'ValueError'>, ValueError(), <traceback object at 0x7fad239a2288>) --- With the patch: --- (<class 'TypeError'>, TypeError(), <traceback object at 0x7f278b174988>) (None, None, None) --- Example 3: --- import sys def gen(): try: try: yield except: print(sys.exc_info()) raise TypeError() except Exception as exc: print("TypeError context:", repr(exc.__context__)) yield g = gen() next(g) try: raise ValueError except Exception as exc: g.throw(exc) --- Original output: --- (<class 'ValueError'>, ValueError(), <traceback object at 0x7f233f05e388>) TypeError context: ValueError() (<class 'ValueError'>, ValueError(), <traceback object at 0x7f233f05e348>) --- With the patch (unchanged): --- (<class 'ValueError'>, ValueError(), <traceback object at 0x7fdf356fead8>) TypeError context: ValueError() (None, None, None) --- ---------- keywords: +patch versions: +Python 2.7 Added file: http://bugs.python.org/file37931/gen_exc_value.patch _______________________________________ Python tracker <rep...@bugs.python.org> <http://bugs.python.org/issue23353> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com