diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2023-10-21 19:18:34 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-21 19:18:34 (GMT) |
commit | 6c23635f2b7067ef091a550954e09f8b7c329e3f (patch) | |
tree | b420a114d1b1ff9ca39f85b69ac68311d580ffe5 /Lib/asyncio | |
parent | fd60549c0ac6c81f05594a5141d24b4433ae39be (diff) | |
download | cpython-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.py | 6 | ||||
-rw-r--r-- | Lib/asyncio/timeouts.py | 12 |
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 |