mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
GH-95704: Don't suppress errors from tasks when TG is cancelled (GH-95761)
When a task catches CancelledError and raises some other error,
the other error should not silently be suppressed.
Any scenario where a task crashes in cleanup upon cancellation
will now result in an ExceptionGroup wrapping the crash(es)
instead of propagating CancelledError and ignoring the side errors.
NOTE: This represents a change in behavior (hence the need to
change several tests). But it is only an edge case.
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
(cherry picked from commit f51f54f39d
)
Co-authored-by: Guido van Rossum <guido@python.org>
This commit is contained in:
parent
2bb363cfcd
commit
36c114ab11
3 changed files with 35 additions and 28 deletions
|
@ -230,29 +230,29 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
|
||||
self.assertEqual(NUM, 15)
|
||||
|
||||
async def test_cancellation_in_body(self):
|
||||
async def test_taskgroup_08(self):
|
||||
|
||||
async def foo():
|
||||
await asyncio.sleep(0.1)
|
||||
1 / 0
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
finally:
|
||||
1 / 0
|
||||
|
||||
async def runner():
|
||||
async with taskgroups.TaskGroup() as g:
|
||||
for _ in range(5):
|
||||
g.create_task(foo())
|
||||
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
await asyncio.sleep(10)
|
||||
|
||||
r = asyncio.create_task(runner())
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
self.assertFalse(r.done())
|
||||
r.cancel()
|
||||
with self.assertRaises(asyncio.CancelledError) as cm:
|
||||
with self.assertRaises(ExceptionGroup) as cm:
|
||||
await r
|
||||
self.assertEqual(get_error_types(cm.exception), {ZeroDivisionError})
|
||||
|
||||
async def test_taskgroup_09(self):
|
||||
|
||||
|
@ -316,8 +316,10 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
async def test_taskgroup_11(self):
|
||||
|
||||
async def foo():
|
||||
await asyncio.sleep(0.1)
|
||||
1 / 0
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
finally:
|
||||
1 / 0
|
||||
|
||||
async def runner():
|
||||
async with taskgroups.TaskGroup():
|
||||
|
@ -325,24 +327,26 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
for _ in range(5):
|
||||
g2.create_task(foo())
|
||||
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
await asyncio.sleep(10)
|
||||
|
||||
r = asyncio.create_task(runner())
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
self.assertFalse(r.done())
|
||||
r.cancel()
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
with self.assertRaises(ExceptionGroup) as cm:
|
||||
await r
|
||||
|
||||
self.assertEqual(get_error_types(cm.exception), {ExceptionGroup})
|
||||
self.assertEqual(get_error_types(cm.exception.exceptions[0]), {ZeroDivisionError})
|
||||
|
||||
async def test_taskgroup_12(self):
|
||||
|
||||
async def foo():
|
||||
await asyncio.sleep(0.1)
|
||||
1 / 0
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
finally:
|
||||
1 / 0
|
||||
|
||||
async def runner():
|
||||
async with taskgroups.TaskGroup() as g1:
|
||||
|
@ -352,19 +356,19 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
for _ in range(5):
|
||||
g2.create_task(foo())
|
||||
|
||||
try:
|
||||
await asyncio.sleep(10)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
await asyncio.sleep(10)
|
||||
|
||||
r = asyncio.create_task(runner())
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
self.assertFalse(r.done())
|
||||
r.cancel()
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
with self.assertRaises(ExceptionGroup) as cm:
|
||||
await r
|
||||
|
||||
self.assertEqual(get_error_types(cm.exception), {ExceptionGroup})
|
||||
self.assertEqual(get_error_types(cm.exception.exceptions[0]), {ZeroDivisionError})
|
||||
|
||||
async def test_taskgroup_13(self):
|
||||
|
||||
async def crash_after(t):
|
||||
|
@ -424,8 +428,9 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
|
||||
self.assertFalse(r.done())
|
||||
r.cancel()
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
with self.assertRaises(ExceptionGroup) as cm:
|
||||
await r
|
||||
self.assertEqual(get_error_types(cm.exception), {ZeroDivisionError})
|
||||
|
||||
async def test_taskgroup_16(self):
|
||||
|
||||
|
@ -451,8 +456,9 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
|
|||
|
||||
self.assertFalse(r.done())
|
||||
r.cancel()
|
||||
with self.assertRaises(asyncio.CancelledError):
|
||||
with self.assertRaises(ExceptionGroup) as cm:
|
||||
await r
|
||||
self.assertEqual(get_error_types(cm.exception), {ZeroDivisionError})
|
||||
|
||||
async def test_taskgroup_17(self):
|
||||
NUM = 0
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue