Unverified Kaydet (Commit) 8874342c authored tarafından Andrew Svetlov's avatar Andrew Svetlov Kaydeden (comit) GitHub

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

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

* Fix docstrings
üst abae67eb
...@@ -81,12 +81,11 @@ is called. ...@@ -81,12 +81,11 @@ is called.
If you wait for a future, you should check early if the future was cancelled to If you wait for a future, you should check early if the future was cancelled to
avoid useless operations. Example:: avoid useless operations. Example::
@coroutine async def slow_operation(fut):
def slow_operation(fut):
if fut.cancelled(): if fut.cancelled():
return return
# ... slow computation ... # ... slow computation ...
yield from fut await fut
# ... # ...
The :func:`shield` function can also be used to ignore cancellation. The :func:`shield` function can also be used to ignore cancellation.
...@@ -99,7 +98,7 @@ Concurrency and multithreading ...@@ -99,7 +98,7 @@ Concurrency and multithreading
An event loop runs in a thread and executes all callbacks and tasks in the same 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 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. and the event loop executes the next task.
To schedule a callback from a different thread, the To schedule a callback from a different thread, the
...@@ -192,8 +191,7 @@ Example with the bug:: ...@@ -192,8 +191,7 @@ Example with the bug::
import asyncio import asyncio
@asyncio.coroutine async def test():
def test():
print("never scheduled") print("never scheduled")
test() test()
...@@ -270,10 +268,9 @@ traceback where the task was created. Output in debug mode:: ...@@ -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 There are different options to fix this issue. The first option is to chain the
coroutine in another coroutine and use classic try/except:: coroutine in another coroutine and use classic try/except::
@asyncio.coroutine async def handle_exception():
def handle_exception():
try: try:
yield from bug() await bug()
except Exception: except Exception:
print("exception consumed") print("exception consumed")
...@@ -300,7 +297,7 @@ Chain coroutines correctly ...@@ -300,7 +297,7 @@ Chain coroutines correctly
-------------------------- --------------------------
When a coroutine function calls other coroutine functions and tasks, they 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. not guaranteed to be sequential.
Example with different bugs using :func:`asyncio.sleep` to simulate slow Example with different bugs using :func:`asyncio.sleep` to simulate slow
...@@ -308,26 +305,22 @@ operations:: ...@@ -308,26 +305,22 @@ operations::
import asyncio import asyncio
@asyncio.coroutine async def create():
def create(): await asyncio.sleep(3.0)
yield from asyncio.sleep(3.0)
print("(1) create file") print("(1) create file")
@asyncio.coroutine async def write():
def write(): await asyncio.sleep(1.0)
yield from asyncio.sleep(1.0)
print("(2) write into file") print("(2) write into file")
@asyncio.coroutine async def close():
def close():
print("(3) close file") print("(3) close file")
@asyncio.coroutine async def test():
def test():
asyncio.ensure_future(create()) asyncio.ensure_future(create())
asyncio.ensure_future(write()) asyncio.ensure_future(write())
asyncio.ensure_future(close()) asyncio.ensure_future(close())
yield from asyncio.sleep(2.0) await asyncio.sleep(2.0)
loop.stop() loop.stop()
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
...@@ -359,24 +352,22 @@ The loop stopped before the ``create()`` finished, ``close()`` has been called ...@@ -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: before ``write()``, whereas coroutine functions were called in this order:
``create()``, ``write()``, ``close()``. ``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 async def test():
def test(): await asyncio.ensure_future(create())
yield from asyncio.ensure_future(create()) await asyncio.ensure_future(write())
yield from asyncio.ensure_future(write()) await asyncio.ensure_future(close())
yield from asyncio.ensure_future(close()) await asyncio.sleep(2.0)
yield from asyncio.sleep(2.0)
loop.stop() loop.stop()
Or without ``asyncio.ensure_future()``:: Or without ``asyncio.ensure_future()``::
@asyncio.coroutine async def test():
def test(): await create()
yield from create() await write()
yield from write() await close()
yield from close() await asyncio.sleep(2.0)
yield from asyncio.sleep(2.0)
loop.stop() loop.stop()
......
...@@ -488,8 +488,9 @@ Coroutines can be scheduled in a protocol method using :func:`ensure_future`, ...@@ -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 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. 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 To have a reliable execution order,
coroutine with ``yield from``. For example, the :meth:`StreamWriter.drain` 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. coroutine can be used to wait until the write buffer is flushed.
...@@ -589,7 +590,7 @@ received data and close the connection:: ...@@ -589,7 +590,7 @@ received data and close the connection::
:meth:`Transport.close` can be called immediately after :meth:`Transport.close` can be called immediately after
:meth:`WriteTransport.write` even if data are not sent yet on the socket: both :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. methods are not coroutines.
.. seealso:: .. seealso::
......
...@@ -24,7 +24,7 @@ Queue ...@@ -24,7 +24,7 @@ Queue
A queue, useful for coordinating producer and consumer coroutines. A queue, useful for coordinating producer and consumer coroutines.
If *maxsize* is less than or equal to zero, the queue size is infinite. If 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`. 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 Unlike the standard library :mod:`queue`, you can reliably know this Queue's
......
...@@ -208,7 +208,7 @@ StreamWriter ...@@ -208,7 +208,7 @@ StreamWriter
The intended use is to write:: The intended use is to write::
w.write(data) w.write(data)
yield from w.drain() await w.drain()
When the size of the transport buffer reaches the high-water limit (the 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 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:: ...@@ -301,15 +301,14 @@ TCP echo client using the :func:`asyncio.open_connection` function::
import asyncio import asyncio
@asyncio.coroutine async def tcp_echo_client(message, loop):
def tcp_echo_client(message, loop): reader, writer = await asyncio.open_connection('127.0.0.1', 8888,
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888, loop=loop)
loop=loop)
print('Send: %r' % message) print('Send: %r' % message)
writer.write(message.encode()) writer.write(message.encode())
data = yield from reader.read(100) data = await reader.read(100)
print('Received: %r' % data.decode()) print('Received: %r' % data.decode())
print('Close the socket') print('Close the socket')
...@@ -335,16 +334,15 @@ TCP echo server using the :func:`asyncio.start_server` function:: ...@@ -335,16 +334,15 @@ TCP echo server using the :func:`asyncio.start_server` function::
import asyncio import asyncio
@asyncio.coroutine async def handle_echo(reader, writer):
def handle_echo(reader, writer): data = await reader.read(100)
data = yield from reader.read(100)
message = data.decode() message = data.decode()
addr = writer.get_extra_info('peername') addr = writer.get_extra_info('peername')
print("Received %r from %r" % (message, addr)) print("Received %r from %r" % (message, addr))
print("Send: %r" % message) print("Send: %r" % message)
writer.write(data) writer.write(data)
yield from writer.drain() await writer.drain()
print("Close the client socket") print("Close the client socket")
writer.close() writer.close()
...@@ -387,13 +385,13 @@ Simple example querying HTTP headers of the URL passed on the command line:: ...@@ -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) connect = asyncio.open_connection(url.hostname, 443, ssl=True)
else: else:
connect = asyncio.open_connection(url.hostname, 80) connect = asyncio.open_connection(url.hostname, 80)
reader, writer = yield from connect reader, writer = await connect
query = ('HEAD {path} HTTP/1.0\r\n' query = ('HEAD {path} HTTP/1.0\r\n'
'Host: {hostname}\r\n' 'Host: {hostname}\r\n'
'\r\n').format(path=url.path or '/', hostname=url.hostname) '\r\n').format(path=url.path or '/', hostname=url.hostname)
writer.write(query.encode('latin-1')) writer.write(query.encode('latin-1'))
while True: while True:
line = yield from reader.readline() line = await reader.readline()
if not line: if not line:
break break
line = line.decode('latin1').rstrip() line = line.decode('latin1').rstrip()
...@@ -428,19 +426,18 @@ Coroutine waiting until a socket receives data using the ...@@ -428,19 +426,18 @@ Coroutine waiting until a socket receives data using the
import asyncio import asyncio
from socket import socketpair from socket import socketpair
@asyncio.coroutine async def wait_for_data(loop):
def wait_for_data(loop):
# Create a pair of connected sockets # Create a pair of connected sockets
rsock, wsock = socketpair() rsock, wsock = socketpair()
# Register the open socket to wait for data # 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 # Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode()) loop.call_soon(wsock.send, 'abc'.encode())
# Wait for data # Wait for data
data = yield from reader.read(100) data = await reader.read(100)
# Got data, we are done: close the socket # Got data, we are done: close the socket
print("Received:", data.decode()) print("Received:", data.decode())
......
...@@ -347,21 +347,20 @@ wait for the subprocess exit. The subprocess is created by the ...@@ -347,21 +347,20 @@ wait for the subprocess exit. The subprocess is created by the
def process_exited(self): def process_exited(self):
self.exit_future.set_result(True) self.exit_future.set_result(True)
@asyncio.coroutine async def get_date(loop):
def get_date(loop):
code = 'import datetime; print(datetime.datetime.now())' code = 'import datetime; print(datetime.datetime.now())'
exit_future = asyncio.Future(loop=loop) exit_future = asyncio.Future(loop=loop)
# Create the subprocess controlled by the protocol DateProtocol, # Create the subprocess controlled by the protocol DateProtocol,
# redirect the standard output into a pipe # redirect the standard output into a pipe
create = loop.subprocess_exec(lambda: DateProtocol(exit_future), transport, protocol = await loop.subprocess_exec(
sys.executable, '-c', code, lambda: DateProtocol(exit_future),
stdin=None, stderr=None) sys.executable, '-c', code,
transport, protocol = yield from create stdin=None, stderr=None)
# Wait for the subprocess exit using the process_exited() method # Wait for the subprocess exit using the process_exited() method
# of the protocol # of the protocol
yield from exit_future await exit_future
# Close the stdout pipe # Close the stdout pipe
transport.close() transport.close()
...@@ -398,16 +397,16 @@ function:: ...@@ -398,16 +397,16 @@ function::
code = 'import datetime; print(datetime.datetime.now())' code = 'import datetime; print(datetime.datetime.now())'
# Create the subprocess, redirect the standard output into a pipe # Create the subprocess, redirect the standard output into a pipe
create = asyncio.create_subprocess_exec(sys.executable, '-c', code, proc = await asyncio.create_subprocess_exec(
stdout=asyncio.subprocess.PIPE) sys.executable, '-c', code,
proc = yield from create stdout=asyncio.subprocess.PIPE)
# Read one line of output # Read one line of output
data = yield from proc.stdout.readline() data = await proc.stdout.readline()
line = data.decode('ascii').rstrip() line = data.decode('ascii').rstrip()
# Wait for the subprocess exit # Wait for the subprocess exit
yield from proc.wait() await proc.wait()
return line return line
if sys.platform == "win32": if sys.platform == "win32":
......
...@@ -515,7 +515,7 @@ Task functions ...@@ -515,7 +515,7 @@ Task functions
Example:: Example::
for f in as_completed(fs): for f in as_completed(fs):
result = yield from f # The 'yield from' may raise result = await f # The 'await' may raise
# Use result # Use result
.. note:: .. note::
...@@ -630,11 +630,11 @@ Task functions ...@@ -630,11 +630,11 @@ Task functions
The statement:: The statement::
res = yield from shield(something()) res = await shield(something())
is exactly equivalent to the statement:: 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 *except* that if the coroutine containing it is cancelled, the task running
in ``something()`` is not cancelled. From the point of view of in ``something()`` is not cancelled. From the point of view of
...@@ -647,7 +647,7 @@ Task functions ...@@ -647,7 +647,7 @@ Task functions
combine ``shield()`` with a try/except clause, as follows:: combine ``shield()`` with a try/except clause, as follows::
try: try:
res = yield from shield(something()) res = await shield(something())
except CancelledError: except CancelledError:
res = None res = None
...@@ -690,7 +690,7 @@ Task functions ...@@ -690,7 +690,7 @@ Task functions
Usage:: Usage::
done, pending = yield from asyncio.wait(fs) done, pending = await asyncio.wait(fs)
.. note:: .. note::
...@@ -714,7 +714,7 @@ Task functions ...@@ -714,7 +714,7 @@ Task functions
This function is a :ref:`coroutine <coroutine>`, usage:: 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 .. versionchanged:: 3.4.3
If the wait is cancelled, the future *fut* is now also cancelled. If the wait is cancelled, the future *fut* is now also cancelled.
...@@ -19,8 +19,9 @@ def _is_debug_mode(): ...@@ -19,8 +19,9 @@ def _is_debug_mode():
# If you set _DEBUG to true, @coroutine will wrap the resulting # If you set _DEBUG to true, @coroutine will wrap the resulting
# generator objects in a CoroWrapper instance (defined below). That # generator objects in a CoroWrapper instance (defined below). That
# instance will log a message when the generator is never iterated # instance will log a message when the generator is never iterated
# over, which may happen when you forget to use "yield from" with a # over, which may happen when you forget to use "await" or "yield from"
# coroutine call. Note that the value of the _DEBUG flag is taken # 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 # 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 # before you define your coroutines. A downside of using this feature
# is that tracebacks show entries for the CoroWrapper.__next__ method # is that tracebacks show entries for the CoroWrapper.__next__ method
......
...@@ -59,7 +59,8 @@ class Future: ...@@ -59,7 +59,8 @@ class Future:
# The value must also be not-None, to enable a subclass to declare # The value must also be not-None, to enable a subclass to declare
# that it is not compatible by setting this to None. # that it is not compatible by setting this to None.
# - It is set by __iter__() below so that Task._step() can tell # - 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). # `yield Future()` (incorrect).
_asyncio_future_blocking = False _asyncio_future_blocking = False
...@@ -236,7 +237,7 @@ class Future: ...@@ -236,7 +237,7 @@ class Future:
if not self.done(): if not self.done():
self._asyncio_future_blocking = True self._asyncio_future_blocking = True
yield self # This tells Task to wait for completion. 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. return self.result() # May raise too.
__await__ = __iter__ # make compatible with 'await' expression __await__ = __iter__ # make compatible with 'await' expression
......
...@@ -23,6 +23,10 @@ class _ContextManager: ...@@ -23,6 +23,10 @@ class _ContextManager:
with lock: with lock:
<block> <block>
Deprecated, use 'async with' statement:
async with lock:
<block>
""" """
def __init__(self, lock): def __init__(self, lock):
...@@ -64,6 +68,9 @@ class _ContextManagerMixin: ...@@ -64,6 +68,9 @@ class _ContextManagerMixin:
# <block> # <block>
# finally: # finally:
# lock.release() # lock.release()
# Deprecated, use 'async with' statement:
# async with lock:
# <block>
warnings.warn("'with (yield from lock)' is deprecated " warnings.warn("'with (yield from lock)' is deprecated "
"use 'async with lock' instead", "use 'async with lock' instead",
DeprecationWarning, stacklevel=2) DeprecationWarning, stacklevel=2)
...@@ -113,16 +120,16 @@ class Lock(_ContextManagerMixin): ...@@ -113,16 +120,16 @@ class Lock(_ContextManagerMixin):
release() call resets the state to unlocked; first coroutine which release() call resets the state to unlocked; first coroutine which
is blocked in acquire() is being processed. 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)' Locks also support the asynchronous context management protocol.
should be used as the context manager expression. 'async with lock' statement should be used.
Usage: Usage:
lock = Lock() lock = Lock()
... ...
yield from lock await lock.acquire()
try: try:
... ...
finally: finally:
...@@ -132,13 +139,13 @@ class Lock(_ContextManagerMixin): ...@@ -132,13 +139,13 @@ class Lock(_ContextManagerMixin):
lock = Lock() lock = Lock()
... ...
with (yield from lock): async with lock:
... ...
Lock objects can be tested for locking state: Lock objects can be tested for locking state:
if not lock.locked(): if not lock.locked():
yield from lock await lock.acquire()
else: else:
# lock is acquired # lock is acquired
... ...
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment