diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-08-04 14:50:54 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-04 14:50:54 (GMT) |
commit | 2d84fe59c0a8bba689d79cefa7110970dd781d46 (patch) | |
tree | 1b7d617b72b1c83e7e7b30c5fedacab07588c775 | |
parent | f2926358d1cd70625222eaf4b541584d2f2a1272 (diff) | |
download | cpython-2d84fe59c0a8bba689d79cefa7110970dd781d46.zip cpython-2d84fe59c0a8bba689d79cefa7110970dd781d46.tar.gz cpython-2d84fe59c0a8bba689d79cefa7110970dd781d46.tar.bz2 |
GH-95289: Always call uncancel() when parent cancellation is requested (GH-95602)
Co-authored-by: Guido van Rossum <guido@python.org>
(cherry picked from commit 2fef27589e44c91042c2598b5cad6c6ad0516d93)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
-rw-r--r-- | Lib/asyncio/taskgroups.py | 17 | ||||
-rw-r--r-- | Lib/test/test_asyncio/test_taskgroups.py | 33 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst | 1 |
3 files changed, 42 insertions, 9 deletions
diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py index 3ca6506..097b486 100644 --- a/Lib/asyncio/taskgroups.py +++ b/Lib/asyncio/taskgroups.py @@ -54,21 +54,22 @@ class TaskGroup: async def __aexit__(self, et, exc, tb): self._exiting = True - propagate_cancellation_error = None if (exc is not None and self._is_base_error(exc) and self._base_error is None): self._base_error = exc - if et is not None: - if et is exceptions.CancelledError: - if self._parent_cancel_requested and not self._parent_task.uncancel(): - # Do nothing, i.e. swallow the error. - pass - else: - propagate_cancellation_error = exc + propagate_cancellation_error = \ + exc if et is exceptions.CancelledError else None + if self._parent_cancel_requested: + # If this flag is set we *must* call uncancel(). + if self._parent_task.uncancel() == 0: + # If there are no pending cancellations left, + # don't propagate CancelledError. + propagate_cancellation_error = None + if et is not None: if not self._aborting: # Our parent task is being cancelled: # diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py index 26fb5e4..99498e7 100644 --- a/Lib/test/test_asyncio/test_taskgroups.py +++ b/Lib/test/test_asyncio/test_taskgroups.py @@ -3,7 +3,7 @@ import asyncio import contextvars - +import contextlib from asyncio import taskgroups import unittest @@ -741,6 +741,37 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase): self.assertEqual(get_error_types(cm.exception), {ZeroDivisionError}) + async def test_taskgroup_context_manager_exit_raises(self): + # See https://github.com/python/cpython/issues/95289 + class CustomException(Exception): + pass + + async def raise_exc(): + raise CustomException + + @contextlib.asynccontextmanager + async def database(): + try: + yield + finally: + raise CustomException + + async def main(): + task = asyncio.current_task() + try: + async with taskgroups.TaskGroup() as tg: + async with database(): + tg.create_task(raise_exc()) + await asyncio.sleep(1) + except* CustomException as err: + self.assertEqual(task.cancelling(), 0) + self.assertEqual(len(err.exceptions), 2) + + else: + self.fail('CustomException not raised') + + await asyncio.create_task(main()) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst b/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst new file mode 100644 index 0000000..d802f55 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-08-03-16-52-32.gh-issue-95289.FMnHlV.rst @@ -0,0 +1 @@ +Fix :class:`asyncio.TaskGroup` to propagate exception when :exc:`asyncio.CancelledError` was replaced with another exception by a context manger. Patch by Kumar Aditya and Guido van Rossum. |