-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
gh-111085: Fix invalid state handling in TaskGroup and Timeout #111111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
gh-111085: Fix invalid state handling in TaskGroup and Timeout #111111
Conversation
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 are now left in consistent state after raising an exception, so following operations can be correctly performed (if they are allowed). Co-authored-by: James Hilton-Balfe <[email protected]>
Misc/NEWS.d/next/Library/2023-10-20-15-29-10.gh-issue-110910.u2oPwX.rst
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this! The original code was adapted from various sources...
Lib/asyncio/timeouts.py
Outdated
@@ -82,11 +81,14 @@ def __repr__(self) -> str: | |||
return f"<Timeout [{self._state.value}]{info_str}>" | |||
|
|||
async def __aenter__(self) -> "Timeout": | |||
if self._state is not _State.CREATED: | |||
raise RuntimeError(f"Timeout has been already {self._state.value}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the list of states, this produces crooked grammar in several cases (active, expiring). Maybe "Timeout cannot be entered in state X"? Or look at the error in reschedule() for inspiration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I did not know that "already active" and "already expiring" are not valid. In TaskGroup it is simply "has been already entered" but I decided to enhance it. Technically, "already entered" should be enough.
reschedule()
also produces weird message ("Cannot change state of created Timeout"). How can you change state of not created Timeout?
Lib/test/test_asyncio/utils.py
Outdated
try: | ||
for _ in coro.__await__(): | ||
pass | ||
except: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe except BaseException as err: nonlocal exc; exc = err
?
…timeouts-states' into asyncio-taskgroups-timeouts-states
Lib/asyncio/timeouts.py
Outdated
@@ -82,7 +82,7 @@ def __repr__(self) -> str: | |||
|
|||
async def __aenter__(self) -> "Timeout": | |||
if self._state is not _State.CREATED: | |||
raise RuntimeError(f"Timeout has been already {self._state.value}") | |||
raise RuntimeError("Timeout has been already entered") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, English grammar is hard. It should be "has already been entered".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bingo!
Thank you for your review Guido. |
Thanks @serhiy-storchaka for the PR 🌮🎉.. I'm working now to backport this PR to: 3.11, 3.12. |
…ythonGH-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). (cherry picked from commit 6c23635) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: James Hilton-Balfe <[email protected]>
…ythonGH-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). (cherry picked from commit 6c23635) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: James Hilton-Balfe <[email protected]>
GH-111171 is a backport of this pull request to the 3.12 branch. |
GH-111172 is a backport of this pull request to the 3.11 branch. |
…GH-111111) (GH-111172) 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). (cherry picked from commit 6c23635) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: James Hilton-Balfe <[email protected]>
…GH-111111) (GH-111171) 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). (cherry picked from commit 6c23635) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: James Hilton-Balfe <[email protected]>
…ython#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 <[email protected]>
…ython#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 <[email protected]>
asyncio.TaskGroup and asyncio.Timeout classes now raise proper RuntimeError if they are improperly used.
They are now left in consistent state after raising an exception, so following operations can be correctly performed (if they are allowed).