summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
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/asyncio
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/asyncio')
-rw-r--r--Lib/asyncio/taskgroups.py6
-rw-r--r--Lib/asyncio/timeouts.py12
2 files changed, 10 insertions, 8 deletions
diff --git a/Lib/asyncio/taskgroups.py b/Lib/asyncio/taskgroups.py
index 24238c4..91be0de 100644
--- a/Lib/asyncio/taskgroups.py
+++ b/Lib/asyncio/taskgroups.py
@@ -54,16 +54,14 @@ class TaskGroup:
async def __aenter__(self):
if self._entered:
raise RuntimeError(
- f"TaskGroup {self!r} has been already entered")
- self._entered = True
-
+ f"TaskGroup {self!r} has already been entered")
if self._loop is None:
self._loop = events.get_running_loop()
-
self._parent_task = tasks.current_task(self._loop)
if self._parent_task is None:
raise RuntimeError(
f'TaskGroup {self!r} cannot determine the parent task')
+ self._entered = True
return self
diff --git a/Lib/asyncio/timeouts.py b/Lib/asyncio/timeouts.py
index 029c468..30042ab 100644
--- a/Lib/asyncio/timeouts.py
+++ b/Lib/asyncio/timeouts.py
@@ -49,8 +49,9 @@ class Timeout:
def reschedule(self, when: Optional[float]) -> None:
"""Reschedule the timeout."""
- assert self._state is not _State.CREATED
if self._state is not _State.ENTERED:
+ if self._state is _State.CREATED:
+ raise RuntimeError("Timeout has not been entered")
raise RuntimeError(
f"Cannot change state of {self._state.value} Timeout",
)
@@ -82,11 +83,14 @@ class Timeout:
return f"<Timeout [{self._state.value}]{info_str}>"
async def __aenter__(self) -> "Timeout":
+ if self._state is not _State.CREATED:
+ raise RuntimeError("Timeout has already been entered")
+ task = tasks.current_task()
+ if task is None:
+ raise RuntimeError("Timeout should be used inside a task")
self._state = _State.ENTERED
- self._task = tasks.current_task()
+ self._task = task
self._cancelling = self._task.cancelling()
- if self._task is None:
- raise RuntimeError("Timeout should be used inside a task")
self.reschedule(self._when)
return self