summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorKumar Aditya <59607654+kumaraditya303@users.noreply.github.com>2023-02-16 18:48:21 (GMT)
committerGitHub <noreply@github.com>2023-02-16 18:48:21 (GMT)
commita5024a261a75dafa4fb6613298dcb64a9603d9c7 (patch)
tree8d54f5f79f74a79822334357f21528e1c138158e /Lib/asyncio
parent226484e47599a93f5bf033ac47198e68ff401432 (diff)
downloadcpython-a5024a261a75dafa4fb6613298dcb64a9603d9c7.zip
cpython-a5024a261a75dafa4fb6613298dcb64a9603d9c7.tar.gz
cpython-a5024a261a75dafa4fb6613298dcb64a9603d9c7.tar.bz2
GH-96764: rewrite `asyncio.wait_for` to use `asyncio.timeout` (#98518)
Changes `asyncio.wait_for` to use `asyncio.timeout` as its underlying implementation.
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/tasks.py77
1 files changed, 29 insertions, 48 deletions
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index e78719d..a2e06d5 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -24,6 +24,7 @@ from . import coroutines
from . import events
from . import exceptions
from . import futures
+from . import timeouts
from .coroutines import _is_coroutine
# Helper to generate new task names
@@ -437,65 +438,44 @@ async def wait_for(fut, timeout):
If the wait is cancelled, the task is also cancelled.
+ If the task supresses the cancellation and returns a value instead,
+ that value is returned.
+
This function is a coroutine.
"""
- loop = events.get_running_loop()
+ # The special case for timeout <= 0 is for the following case:
+ #
+ # async def test_waitfor():
+ # func_started = False
+ #
+ # async def func():
+ # nonlocal func_started
+ # func_started = True
+ #
+ # try:
+ # await asyncio.wait_for(func(), 0)
+ # except asyncio.TimeoutError:
+ # assert not func_started
+ # else:
+ # assert False
+ #
+ # asyncio.run(test_waitfor())
- if timeout is None:
- return await fut
- if timeout <= 0:
- fut = ensure_future(fut, loop=loop)
+ if timeout is not None and timeout <= 0:
+ fut = ensure_future(fut)
if fut.done():
return fut.result()
- await _cancel_and_wait(fut, loop=loop)
+ await _cancel_and_wait(fut)
try:
return fut.result()
except exceptions.CancelledError as exc:
- raise exceptions.TimeoutError() from exc
-
- waiter = loop.create_future()
- timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
- cb = functools.partial(_release_waiter, waiter)
-
- fut = ensure_future(fut, loop=loop)
- fut.add_done_callback(cb)
-
- try:
- # wait until the future completes or the timeout
- try:
- await waiter
- except exceptions.CancelledError:
- if fut.done():
- return fut.result()
- else:
- fut.remove_done_callback(cb)
- # We must ensure that the task is not running
- # after wait_for() returns.
- # See https://bugs.python.org/issue32751
- await _cancel_and_wait(fut, loop=loop)
- raise
-
- if fut.done():
- return fut.result()
- else:
- fut.remove_done_callback(cb)
- # We must ensure that the task is not running
- # after wait_for() returns.
- # See https://bugs.python.org/issue32751
- await _cancel_and_wait(fut, loop=loop)
- # In case task cancellation failed with some
- # exception, we should re-raise it
- # See https://bugs.python.org/issue40607
- try:
- return fut.result()
- except exceptions.CancelledError as exc:
- raise exceptions.TimeoutError() from exc
- finally:
- timeout_handle.cancel()
+ raise TimeoutError from exc
+ async with timeouts.timeout(timeout):
+ return await fut
async def _wait(fs, timeout, return_when, loop):
"""Internal helper for wait().
@@ -541,9 +521,10 @@ async def _wait(fs, timeout, return_when, loop):
return done, pending
-async def _cancel_and_wait(fut, loop):
+async def _cancel_and_wait(fut):
"""Cancel the *fut* future or task and wait until it completes."""
+ loop = events.get_running_loop()
waiter = loop.create_future()
cb = functools.partial(_release_waiter, waiter)
fut.add_done_callback(cb)