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

Reply via email to