summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_asyncio/test_taskgroups.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2023-10-21 19:18:34 (GMT)
committerGitHub <noreply@github.com>2023-10-21 19:18:34 (GMT)
commit6c23635f2b7067ef091a550954e09f8b7c329e3f (patch)
treeb420a114d1b1ff9ca39f85b69ac68311d580ffe5 /Lib/test/test_asyncio/test_taskgroups.py
parentfd60549c0ac6c81f05594a5141d24b4433ae39be (diff)
downloadcpython-6c23635f2b7067ef091a550954e09f8b7c329e3f.zip
cpython-6c23635f2b7067ef091a550954e09f8b7c329e3f.tar.gz
cpython-6c23635f2b7067ef091a550954e09f8b7c329e3f.tar.bz2
gh-111085: Fix invalid state handling in TaskGroup and Timeout (#111111)
asyncio.TaskGroup and asyncio.Timeout classes now raise proper RuntimeError if they are improperly used. * When they are used without entering the context manager. * When they are used after finishing. * When the context manager is entered more than once (simultaneously or sequentially). * If there is no current task when entering the context manager. They now remain in a consistent state after an exception is thrown, so subsequent operations can be performed correctly (if they are allowed). Co-authored-by: James Hilton-Balfe <gobot1234yt@gmail.com>
Diffstat (limited to 'Lib/test/test_asyncio/test_taskgroups.py')
-rw-r--r--Lib/test/test_asyncio/test_taskgroups.py45
1 files changed, 45 insertions, 0 deletions
diff --git a/Lib/test/test_asyncio/test_taskgroups.py b/Lib/test/test_asyncio/test_taskgroups.py
index 6a0231f..7a18362 100644
--- a/Lib/test/test_asyncio/test_taskgroups.py
+++ b/Lib/test/test_asyncio/test_taskgroups.py
@@ -8,6 +8,8 @@ import contextlib
from asyncio import taskgroups
import unittest
+from test.test_asyncio.utils import await_without_task
+
# To prevent a warning "test altered the execution environment"
def tearDownModule():
@@ -779,6 +781,49 @@ class TestTaskGroup(unittest.IsolatedAsyncioTestCase):
await asyncio.create_task(main())
+ async def test_taskgroup_already_entered(self):
+ tg = taskgroups.TaskGroup()
+ async with tg:
+ with self.assertRaisesRegex(RuntimeError, "has already been entered"):
+ async with tg:
+ pass
+
+ async def test_taskgroup_double_enter(self):
+ tg = taskgroups.TaskGroup()
+ async with tg:
+ pass
+ with self.assertRaisesRegex(RuntimeError, "has already been entered"):
+ async with tg:
+ pass
+
+ async def test_taskgroup_finished(self):
+ tg = taskgroups.TaskGroup()
+ async with tg:
+ pass
+ coro = asyncio.sleep(0)
+ with self.assertRaisesRegex(RuntimeError, "is finished"):
+ tg.create_task(coro)
+ # We still have to await coro to avoid a warning
+ await coro
+
+ async def test_taskgroup_not_entered(self):
+ tg = taskgroups.TaskGroup()
+ coro = asyncio.sleep(0)
+ with self.assertRaisesRegex(RuntimeError, "has not been entered"):
+ tg.create_task(coro)
+ # We still have to await coro to avoid a warning
+ await coro
+
+ async def test_taskgroup_without_parent_task(self):
+ tg = taskgroups.TaskGroup()
+ with self.assertRaisesRegex(RuntimeError, "parent task"):
+ await await_without_task(tg.__aenter__())
+ coro = asyncio.sleep(0)
+ with self.assertRaisesRegex(RuntimeError, "has not been entered"):
+ tg.create_task(coro)
+ # We still have to await coro to avoid a warning
+ await coro
+
if __name__ == "__main__":
unittest.main()