gh-102780: Fix uncancel() call in asyncio timeouts (#102815)

Also use `raise TimeOut from <CancelledError instance>` so that the CancelledError is set
in the `__cause__` field rather than in the `__context__` field.

Co-authored-by: Guido van Rossum <gvanrossum@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Kristján Valur Jónsson 2023-03-22 17:52:10 +00:00 committed by GitHub
parent 1ca315538f
commit 04adf2df39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 6 deletions

View file

@ -84,6 +84,7 @@ class Timeout:
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 @@ class Timeout:
if self._state is _State.EXPIRING:
self._state = _State.EXPIRED
if self._task.uncancel() == 0 and exc_type is exceptions.CancelledError:
# Since there are no outstanding cancel requests, we're
if self._task.uncancel() <= self._cancelling and exc_type is exceptions.CancelledError:
# Since there are no new cancel requests, we're
# handling this.
raise TimeoutError
raise TimeoutError from exc_val
elif self._state is _State.ENTERED:
self._state = _State.EXITED