summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio/tasks.py
diff options
context:
space:
mode:
authorChris Jerdonek <chris.jerdonek@gmail.com>2020-05-18 05:47:31 (GMT)
committerGitHub <noreply@github.com>2020-05-18 05:47:31 (GMT)
commitda742ba826721da84140abc785856d4ccc2d787f (patch)
tree1a6f9db52fe93edf9946620d0e2312e97c6f16a0 /Lib/asyncio/tasks.py
parentd17f3d8315a3a775ab0807fc80acf92b1bd682f8 (diff)
downloadcpython-da742ba826721da84140abc785856d4ccc2d787f.zip
cpython-da742ba826721da84140abc785856d4ccc2d787f.tar.gz
cpython-da742ba826721da84140abc785856d4ccc2d787f.tar.bz2
bpo-31033: Improve the traceback for cancelled asyncio tasks (GH-19951)
When an asyncio.Task is cancelled, the exception traceback now starts with where the task was first interrupted. Previously, the traceback only had "depth one."
Diffstat (limited to 'Lib/asyncio/tasks.py')
-rw-r--r--Lib/asyncio/tasks.py26
1 files changed, 12 insertions, 14 deletions
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index a3a0a33..21b98b6 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -270,8 +270,7 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
f'_step(): already done: {self!r}, {exc!r}')
if self._must_cancel:
if not isinstance(exc, exceptions.CancelledError):
- exc = exceptions.CancelledError(''
- if self._cancel_message is None else self._cancel_message)
+ exc = self._make_cancelled_error()
self._must_cancel = False
coro = self._coro
self._fut_waiter = None
@@ -293,11 +292,9 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
else:
super().set_result(exc.value)
except exceptions.CancelledError as exc:
- if exc.args:
- cancel_msg = exc.args[0]
- else:
- cancel_msg = None
- super().cancel(msg=cancel_msg) # I.e., Future.cancel(self).
+ # Save the original exception so we can chain it later.
+ self._cancelled_exc = exc
+ super().cancel() # I.e., Future.cancel(self).
except (KeyboardInterrupt, SystemExit) as exc:
super().set_exception(exc)
raise
@@ -787,8 +784,7 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
# Check if 'fut' is cancelled first, as
# 'fut.exception()' will *raise* a CancelledError
# instead of returning it.
- exc = exceptions.CancelledError(''
- if fut._cancel_message is None else fut._cancel_message)
+ exc = fut._make_cancelled_error()
outer.set_exception(exc)
return
else:
@@ -804,9 +800,12 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
for fut in children:
if fut.cancelled():
- # Check if 'fut' is cancelled first, as
- # 'fut.exception()' will *raise* a CancelledError
- # instead of returning it.
+ # Check if 'fut' is cancelled first, as 'fut.exception()'
+ # will *raise* a CancelledError instead of returning it.
+ # Also, since we're adding the exception return value
+ # to 'results' instead of raising it, don't bother
+ # setting __context__. This also lets us preserve
+ # calling '_make_cancelled_error()' at most once.
res = exceptions.CancelledError(
'' if fut._cancel_message is None else
fut._cancel_message)
@@ -820,8 +819,7 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
# If gather is being cancelled we must propagate the
# cancellation regardless of *return_exceptions* argument.
# See issue 32684.
- exc = exceptions.CancelledError(''
- if fut._cancel_message is None else fut._cancel_message)
+ exc = fut._make_cancelled_error()
outer.set_exception(exc)
else:
outer.set_result(results)