bpo-32258: Replace 'yield from' to 'await' in asyncio docs (#4779)

* Replace 'yield from' to 'await' in asyncio docs

* Fix docstrings
This commit is contained in:
Andrew Svetlov 2017-12-11 17:35:49 +02:00 committed by GitHub
parent abae67ebc2
commit 8874342cf3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 79 additions and 82 deletions

View file

@ -81,12 +81,11 @@ is called.
If you wait for a future, you should check early if the future was cancelled to
avoid useless operations. Example::
@coroutine
def slow_operation(fut):
async def slow_operation(fut):
if fut.cancelled():
return
# ... slow computation ...
yield from fut
await fut
# ...
The :func:`shield` function can also be used to ignore cancellation.
@ -99,7 +98,7 @@ Concurrency and multithreading
An event loop runs in a thread and executes all callbacks and tasks in the same
thread. While a task is running in the event loop, no other task is running in
the same thread. But when the task uses ``yield from``, the task is suspended
the same thread. But when the task uses ``await``, the task is suspended
and the event loop executes the next task.
To schedule a callback from a different thread, the
@ -192,8 +191,7 @@ Example with the bug::
import asyncio
@asyncio.coroutine
def test():
async def test():
print("never scheduled")
test()
@ -270,10 +268,9 @@ traceback where the task was created. Output in debug mode::
There are different options to fix this issue. The first option is to chain the
coroutine in another coroutine and use classic try/except::
@asyncio.coroutine
def handle_exception():
async def handle_exception():
try:
yield from bug()
await bug()
except Exception:
print("exception consumed")
@ -300,7 +297,7 @@ Chain coroutines correctly
--------------------------
When a coroutine function calls other coroutine functions and tasks, they
should be chained explicitly with ``yield from``. Otherwise, the execution is
should be chained explicitly with ``await``. Otherwise, the execution is
not guaranteed to be sequential.
Example with different bugs using :func:`asyncio.sleep` to simulate slow
@ -308,26 +305,22 @@ operations::
import asyncio
@asyncio.coroutine
def create():
yield from asyncio.sleep(3.0)
async def create():
await asyncio.sleep(3.0)
print("(1) create file")
@asyncio.coroutine
def write():
yield from asyncio.sleep(1.0)
async def write():
await asyncio.sleep(1.0)
print("(2) write into file")
@asyncio.coroutine
def close():
async def close():
print("(3) close file")
@asyncio.coroutine
def test():
async def test():
asyncio.ensure_future(create())
asyncio.ensure_future(write())
asyncio.ensure_future(close())
yield from asyncio.sleep(2.0)
await asyncio.sleep(2.0)
loop.stop()
loop = asyncio.get_event_loop()
@ -359,24 +352,22 @@ The loop stopped before the ``create()`` finished, ``close()`` has been called
before ``write()``, whereas coroutine functions were called in this order:
``create()``, ``write()``, ``close()``.
To fix the example, tasks must be marked with ``yield from``::
To fix the example, tasks must be marked with ``await``::
@asyncio.coroutine
def test():
yield from asyncio.ensure_future(create())
yield from asyncio.ensure_future(write())
yield from asyncio.ensure_future(close())
yield from asyncio.sleep(2.0)
async def test():
await asyncio.ensure_future(create())
await asyncio.ensure_future(write())
await asyncio.ensure_future(close())
await asyncio.sleep(2.0)
loop.stop()
Or without ``asyncio.ensure_future()``::
@asyncio.coroutine
def test():
yield from create()
yield from write()
yield from close()
yield from asyncio.sleep(2.0)
async def test():
await create()
await write()
await close()
await asyncio.sleep(2.0)
loop.stop()

View file

@ -488,8 +488,9 @@ Coroutines can be scheduled in a protocol method using :func:`ensure_future`,
but there is no guarantee made about the execution order. Protocols are not
aware of coroutines created in protocol methods and so will not wait for them.
To have a reliable execution order, use :ref:`stream objects <asyncio-streams>` in a
coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain`
To have a reliable execution order,
use :ref:`stream objects <asyncio-streams>` in a
coroutine with ``await``. For example, the :meth:`StreamWriter.drain`
coroutine can be used to wait until the write buffer is flushed.
@ -589,7 +590,7 @@ received data and close the connection::
:meth:`Transport.close` can be called immediately after
:meth:`WriteTransport.write` even if data are not sent yet on the socket: both
methods are asynchronous. ``yield from`` is not needed because these transport
methods are asynchronous. ``await`` is not needed because these transport
methods are not coroutines.
.. seealso::

View file

@ -24,7 +24,7 @@ Queue
A queue, useful for coordinating producer and consumer coroutines.
If *maxsize* is less than or equal to zero, the queue size is infinite. If
it is an integer greater than ``0``, then ``yield from put()`` will block
it is an integer greater than ``0``, then ``await put()`` will block
when the queue reaches *maxsize*, until an item is removed by :meth:`get`.
Unlike the standard library :mod:`queue`, you can reliably know this Queue's

View file

@ -208,7 +208,7 @@ StreamWriter
The intended use is to write::
w.write(data)
yield from w.drain()
await w.drain()
When the size of the transport buffer reaches the high-water limit (the
protocol is paused), block until the size of the buffer is drained down
@ -301,15 +301,14 @@ TCP echo client using the :func:`asyncio.open_connection` function::
import asyncio
@asyncio.coroutine
def tcp_echo_client(message, loop):
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,
loop=loop)
async def tcp_echo_client(message, loop):
reader, writer = await asyncio.open_connection('127.0.0.1', 8888,
loop=loop)
print('Send: %r' % message)
writer.write(message.encode())
data = yield from reader.read(100)
data = await reader.read(100)
print('Received: %r' % data.decode())
print('Close the socket')
@ -335,16 +334,15 @@ TCP echo server using the :func:`asyncio.start_server` function::
import asyncio
@asyncio.coroutine
def handle_echo(reader, writer):
data = yield from reader.read(100)
async def handle_echo(reader, writer):
data = await reader.read(100)
message = data.decode()
addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr))
print("Send: %r" % message)
writer.write(data)
yield from writer.drain()
await writer.drain()
print("Close the client socket")
writer.close()
@ -387,13 +385,13 @@ Simple example querying HTTP headers of the URL passed on the command line::
connect = asyncio.open_connection(url.hostname, 443, ssl=True)
else:
connect = asyncio.open_connection(url.hostname, 80)
reader, writer = yield from connect
reader, writer = await connect
query = ('HEAD {path} HTTP/1.0\r\n'
'Host: {hostname}\r\n'
'\r\n').format(path=url.path or '/', hostname=url.hostname)
writer.write(query.encode('latin-1'))
while True:
line = yield from reader.readline()
line = await reader.readline()
if not line:
break
line = line.decode('latin1').rstrip()
@ -428,19 +426,18 @@ Coroutine waiting until a socket receives data using the
import asyncio
from socket import socketpair
@asyncio.coroutine
def wait_for_data(loop):
async def wait_for_data(loop):
# Create a pair of connected sockets
rsock, wsock = socketpair()
# Register the open socket to wait for data
reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop)
reader, writer = await asyncio.open_connection(sock=rsock, loop=loop)
# Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode())
# Wait for data
data = yield from reader.read(100)
data = await reader.read(100)
# Got data, we are done: close the socket
print("Received:", data.decode())

View file

@ -347,21 +347,20 @@ wait for the subprocess exit. The subprocess is created by the
def process_exited(self):
self.exit_future.set_result(True)
@asyncio.coroutine
def get_date(loop):
async def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop)
# Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
transport, protocol = yield from create
transport, protocol = await loop.subprocess_exec(
lambda: DateProtocol(exit_future),
sys.executable, '-c', code,
stdin=None, stderr=None)
# Wait for the subprocess exit using the process_exited() method
# of the protocol
yield from exit_future
await exit_future
# Close the stdout pipe
transport.close()
@ -398,16 +397,16 @@ function::
code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
proc = yield from create
proc = await asyncio.create_subprocess_exec(
sys.executable, '-c', code,
stdout=asyncio.subprocess.PIPE)
# Read one line of output
data = yield from proc.stdout.readline()
data = await proc.stdout.readline()
line = data.decode('ascii').rstrip()
# Wait for the subprocess exit
yield from proc.wait()
await proc.wait()
return line
if sys.platform == "win32":

View file

@ -515,7 +515,7 @@ Task functions
Example::
for f in as_completed(fs):
result = yield from f # The 'yield from' may raise
result = await f # The 'await' may raise
# Use result
.. note::
@ -630,11 +630,11 @@ Task functions
The statement::
res = yield from shield(something())
res = await shield(something())
is exactly equivalent to the statement::
res = yield from something()
res = await something()
*except* that if the coroutine containing it is cancelled, the task running
in ``something()`` is not cancelled. From the point of view of
@ -647,7 +647,7 @@ Task functions
combine ``shield()`` with a try/except clause, as follows::
try:
res = yield from shield(something())
res = await shield(something())
except CancelledError:
res = None
@ -690,7 +690,7 @@ Task functions
Usage::
done, pending = yield from asyncio.wait(fs)
done, pending = await asyncio.wait(fs)
.. note::
@ -714,7 +714,7 @@ Task functions
This function is a :ref:`coroutine <coroutine>`, usage::
result = yield from asyncio.wait_for(fut, 60.0)
result = await asyncio.wait_for(fut, 60.0)
.. versionchanged:: 3.4.3
If the wait is cancelled, the future *fut* is now also cancelled.

View file

@ -19,8 +19,9 @@ def _is_debug_mode():
# If you set _DEBUG to true, @coroutine will wrap the resulting
# generator objects in a CoroWrapper instance (defined below). That
# instance will log a message when the generator is never iterated
# over, which may happen when you forget to use "yield from" with a
# coroutine call. Note that the value of the _DEBUG flag is taken
# over, which may happen when you forget to use "await" or "yield from"
# with a coroutine call.
# Note that the value of the _DEBUG flag is taken
# when the decorator is used, so to be of any use it must be set
# before you define your coroutines. A downside of using this feature
# is that tracebacks show entries for the CoroWrapper.__next__ method

View file

@ -59,7 +59,8 @@ class Future:
# The value must also be not-None, to enable a subclass to declare
# that it is not compatible by setting this to None.
# - It is set by __iter__() below so that Task._step() can tell
# the difference between `yield from Future()` (correct) vs.
# the difference between
# `await Future()` or`yield from Future()` (correct) vs.
# `yield Future()` (incorrect).
_asyncio_future_blocking = False
@ -236,7 +237,7 @@ def __iter__(self):
if not self.done():
self._asyncio_future_blocking = True
yield self # This tells Task to wait for completion.
assert self.done(), "yield from wasn't used with future"
assert self.done(), "await wasn't used with future"
return self.result() # May raise too.
__await__ = __iter__ # make compatible with 'await' expression

View file

@ -23,6 +23,10 @@ class _ContextManager:
with lock:
<block>
Deprecated, use 'async with' statement:
async with lock:
<block>
"""
def __init__(self, lock):
@ -64,6 +68,9 @@ def __iter__(self):
# <block>
# finally:
# lock.release()
# Deprecated, use 'async with' statement:
# async with lock:
# <block>
warnings.warn("'with (yield from lock)' is deprecated "
"use 'async with lock' instead",
DeprecationWarning, stacklevel=2)
@ -113,16 +120,16 @@ class Lock(_ContextManagerMixin):
release() call resets the state to unlocked; first coroutine which
is blocked in acquire() is being processed.
acquire() is a coroutine and should be called with 'yield from'.
acquire() is a coroutine and should be called with 'await'.
Locks also support the context management protocol. '(yield from lock)'
should be used as the context manager expression.
Locks also support the asynchronous context management protocol.
'async with lock' statement should be used.
Usage:
lock = Lock()
...
yield from lock
await lock.acquire()
try:
...
finally:
@ -132,13 +139,13 @@ class Lock(_ContextManagerMixin):
lock = Lock()
...
with (yield from lock):
async with lock:
...
Lock objects can be tested for locking state:
if not lock.locked():
yield from lock
await lock.acquire()
else:
# lock is acquired
...