Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
gh-102780: Fix uncancel() call in asyncio timeouts#102815
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
9f96cea07517b71150db0d207fb1912f26dee574fcc91dae7902691e0f7bde507c40cc2a8914ea6f31146e299faFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -300,13 +300,17 @@ in the task at the next opportunity. | ||
| It is recommended that coroutines use ``try/finally`` blocks to robustly | ||
| perform clean-up logic. In case :exc:`asyncio.CancelledError` | ||
| is explicitly caught, it should generally be propagated when | ||
| clean-up is complete. :exc:`asyncio.CancelledError` directly subclasses | ||
| :exc:`BaseException` so most code will not need to be aware of it. | ||
| The asyncio components that enable structured concurrency, like | ||
| :class:`asyncio.TaskGroup` and :func:`asyncio.timeout`, | ||
gvanrossum marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| are implemented using cancellation internally and might misbehave if | ||
| a coroutine swallows :exc:`asyncio.CancelledError`. Similarly, user code | ||
| should not generally call :meth:`uncancel <asyncio.Task.uncancel>`. | ||
| However, in cases when suppressing :exc:`asyncio.CancelledError` is | ||
| truly desired, it is necessary to also call ``uncancel()`` to completely | ||
| remove the cancellation state. | ||
| .. _taskgroups: | ||
| @@ -1148,7 +1152,9 @@ Task Object | ||
| Therefore, unlike :meth:`Future.cancel`, :meth:`Task.cancel` does | ||
| not guarantee that the Task will be cancelled, although | ||
| suppressing cancellation completely is not common and is actively | ||
| discouraged. Should the coroutine nevertheless decide to suppress | ||
| the cancellation, it needs to call :meth:`Task.uncancel` in addition | ||
| to catching the exception. | ||
| .. versionchanged:: 3.9 | ||
| Added the *msg* parameter. | ||
| @@ -1238,6 +1244,10 @@ Task Object | ||
| with :meth:`uncancel`. :class:`TaskGroup` context managers use | ||
| :func:`uncancel` in a similar fashion. | ||
| If end-user code is, for some reason, suppresing cancellation by | ||
| catching :exc:`CancelledError`, it needs to call this method to remove | ||
| the cancellation state. | ||
| .. method:: cancelling() | ||
| Return the number of pending cancellation requests to this Task, i.e., | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -84,6 +84,7 @@ def __repr__(self) -> str: | ||
| async def __aenter__(self) -> "Timeout": | ||
| self._state = _State.ENTERED | ||
| self._task = tasks.current_task() | ||
| self._cancelling = self._task.cancelling() | ||
| if self._task is None: | ||
| raise RuntimeError("Timeout should be used inside a task") | ||
| self.reschedule(self._when) | ||
| @@ -104,10 +105,10 @@ async def __aexit__( | ||
| if self._state is _State.EXPIRING: | ||
| self._state = _State.EXPIRED | ||
| if self._task.uncancel()<= self._cancelling and exc_type is exceptions.CancelledError: | ||
| # Since there are nonew cancel requests, we're | ||
| # handling this. | ||
| raise TimeoutError from exc_val | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. This is a nice improvement that maybe ought to be called out in the commit message? (If you agree I can handle that when I merge it.) Contributor
| ||
| elif self._state is _State.ENTERED: | ||
| self._state = _State.EXITED | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| The :class:`asyncio.Timeout` context manager now works reliably even when performing cleanup due | ||
| to task cancellation. Previously it could raise a | ||
| :exc:`~asyncio.CancelledError` instead of an :exc:`~asyncio.TimeoutError` in such cases. |