bpo-29590: fix stack trace for gen.throw() with yield from (#19896)

* Add failing test.

* bpo-29590: fix stack trace for gen.throw() with yield from (GH-NNNN)

When gen.throw() is called on a generator after a "yield from", the
intermediate stack trace entries are lost.  This commit fixes that.
This commit is contained in:
Chris Jerdonek 2020-07-09 06:27:23 -07:00 committed by GitHub
parent 96a6a6d42b
commit 8b33961e4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 0 deletions

View file

@ -415,6 +415,55 @@ class GeneratorThrowTest(unittest.TestCase):
gen.throw(ValueError)
class GeneratorStackTraceTest(unittest.TestCase):
def check_stack_names(self, frame, expected):
names = []
while frame:
name = frame.f_code.co_name
# Stop checking frames when we get to our test helper.
if name.startswith('check_') or name.startswith('call_'):
break
names.append(name)
frame = frame.f_back
self.assertEqual(names, expected)
def check_yield_from_example(self, call_method):
def f():
self.check_stack_names(sys._getframe(), ['f', 'g'])
try:
yield
except Exception:
pass
self.check_stack_names(sys._getframe(), ['f', 'g'])
def g():
self.check_stack_names(sys._getframe(), ['g'])
yield from f()
self.check_stack_names(sys._getframe(), ['g'])
gen = g()
gen.send(None)
try:
call_method(gen)
except StopIteration:
pass
def test_send_with_yield_from(self):
def call_send(gen):
gen.send(None)
self.check_yield_from_example(call_send)
def test_throw_with_yield_from(self):
def call_throw(gen):
gen.throw(RuntimeError)
self.check_yield_from_example(call_throw)
class YieldFromTests(unittest.TestCase):
def test_generator_gi_yieldfrom(self):
def a():