Skip to content

Commit c0e9dee

Browse files
gh-154791: Fix asyncio Future losing traceback on repeated result() calls
1 parent 1ec5607 commit c0e9dee

3 files changed

Lines changed: 24 additions & 1 deletion

File tree

Lib/test/test_asyncio/test_futures2.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ async def raise_exc():
2828
else:
2929
self.fail('TypeError was not raised')
3030

31+
async def test_future_traceback_preserved_after_suppress(self):
32+
async def raise_exc():
33+
raise TypeError(42)
34+
35+
future = self.cls(raise_exc())
36+
try:
37+
await future
38+
except TypeError:
39+
pass
40+
41+
try:
42+
await future
43+
except TypeError as e:
44+
tb = ''.join(traceback.format_tb(e.__traceback__))
45+
self.assertIn('raise_exc', tb,
46+
'Original raise site lost after first result() call')
47+
else:
48+
self.fail('TypeError was not raised')
49+
50+
3151
async def test_task_exc_handler_correct_context(self):
3252
# see https://github.com/python/cpython/issues/96704
3353
name = contextvars.ContextVar('name', default='foo')
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fix `asyncio._CFuture` losing the initial exception traceback frames when
2+
`Future.result()` is called more than once. Previously, the C implementation
3+
cleared the stored traceback after the first call, causing subsequent raises
4+
to omit the original raise site. The Python implementation was unaffected.

Modules/_asynciomodule.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,6 @@ future_get_result(asyncio_state *state, FutureObj *fut, PyObject **result)
769769
return -1;
770770
}
771771
*result = Py_NewRef(fut->fut_exception);
772-
Py_CLEAR(fut->fut_exception_tb);
773772
return 1;
774773
}
775774

0 commit comments

Comments
 (0)