diff options
author | Chris Jerdonek <chris.jerdonek@gmail.com> | 2020-05-18 05:47:31 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-18 05:47:31 (GMT) |
commit | da742ba826721da84140abc785856d4ccc2d787f (patch) | |
tree | 1a6f9db52fe93edf9946620d0e2312e97c6f16a0 /Lib/asyncio/tasks.py | |
parent | d17f3d8315a3a775ab0807fc80acf92b1bd682f8 (diff) | |
download | cpython-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.py | 26 |
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) |