Discussion:
[Python-checkins] cpython (merge 3.4 -> default): Merge 3.4 (asyncio doc)
victor.stinner
2014-10-11 14:30:30 UTC
Permalink
https://hg.python.org/cpython/rev/408bbdaef8d4
changeset: 92962:408bbdaef8d4
parent: 92960:24a1ca785fc3
parent: 92961:a33b3bef2a1c
user: Victor Stinner <victor.stinner at gmail.com>
date: Sat Oct 11 16:30:21 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-eventloop.rst | 7 +++++--
Doc/library/asyncio-protocol.rst | 7 +++++--
Doc/library/asyncio-stream.rst | 7 +++++--
3 files changed, 15 insertions(+), 6 deletions(-)


diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -676,10 +676,13 @@
:meth:`BaseEventLoop.add_reader` method and then close the event loop::

import asyncio
- import socket
+ try:
+ from socket import socketpair
+ except ImportError:
+ from asyncio.windows_utils import socketpair

# Create a pair of connected file descriptors
- rsock, wsock = socket.socketpair()
+ rsock, wsock = socketpair()
loop = asyncio.get_event_loop()

def reader():
diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst
--- a/Doc/library/asyncio-protocol.rst
+++ b/Doc/library/asyncio-protocol.rst
@@ -521,10 +521,13 @@
the event loop ::

import asyncio
- import socket
+ try:
+ from socket import socketpair
+ except ImportError:
+ from asyncio.windows_utils import socketpair

# Create a pair of connected sockets
- rsock, wsock = socket.socketpair()
+ rsock, wsock = socketpair()
loop = asyncio.get_event_loop()

class MyProtocol(asyncio.Protocol):
diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst
--- a/Doc/library/asyncio-stream.rst
+++ b/Doc/library/asyncio-stream.rst
@@ -296,11 +296,14 @@
:func:`open_connection` function::

import asyncio
- import socket
+ try:
+ from socket import socketpair
+ except ImportError:
+ from asyncio.windows_utils import socketpair

def wait_for_data(loop):
# Create a pair of connected sockets
- rsock, wsock = socket.socketpair()
+ rsock, wsock = socketpair()

# Register the open socket to wait for data
reader, writer = yield from asyncio.open_connection(sock=rsock, loop=loop)
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-12 09:35:34 UTC
Permalink
https://hg.python.org/cpython/rev/299e54ee1176
changeset: 92988:299e54ee1176
parent: 92985:1068bd9e3aec
parent: 92987:64a8f20488c4
user: Victor Stinner <victor.stinner at gmail.com>
date: Sun Oct 12 11:35:22 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-protocol.rst | 31 ++++++++++++-------
1 files changed, 19 insertions(+), 12 deletions(-)


diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst
--- a/Doc/library/asyncio-protocol.rst
+++ b/Doc/library/asyncio-protocol.rst
@@ -446,22 +446,27 @@

import asyncio

- class EchoClient(asyncio.Protocol):
- message = 'This is the message. It will be echoed.'
+ class EchoClientProtocol(asyncio.Protocol):
+ def __init__(self, message, loop):
+ self.message = message
+ self.loop = loop

def connection_made(self, transport):
transport.write(self.message.encode())
- print('data sent: {}'.format(self.message))
+ print('Data sent: {!r}'.format(self.message))

def data_received(self, data):
- print('data received: {}'.format(data.decode()))
+ print('Data received: {!r}'.format(data.decode()))

def connection_lost(self, exc):
- print('server closed the connection')
- asyncio.get_event_loop().stop()
+ print('The server closed the connection')
+ print('Stop the event lop')
+ self.loop.stop()

loop = asyncio.get_event_loop()
- coro = loop.create_connection(EchoClient, '127.0.0.1', 8888)
+ message = 'Hello World!'
+ coro = loop.create_connection(lambda: EchoClientProtocol(message, loop),
+ '127.0.0.1', 8888)
loop.run_until_complete(coro)
loop.run_forever()
loop.close()
@@ -481,7 +486,7 @@

import asyncio

- class EchoServer(asyncio.Protocol):
+ class EchoServerClientProtocol(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('Connection from {}'.format(peername))
@@ -494,11 +499,12 @@
print('Send: {!r}'.format(message))
self.transport.write(data)

- print('Close the socket')
+ print('Close the client socket')
self.transport.close()

loop = asyncio.get_event_loop()
- coro = loop.create_server(EchoServer, '127.0.0.1', 8888)
+ # Each client connection will create a new protocol instance
+ coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)

# Server requests until CTRL+c is pressed
@@ -575,7 +581,7 @@

import asyncio

- class EchoServerClientProtocol:
+ class EchoServerProtocol:
def connection_made(self, transport):
self.transport = transport

@@ -587,8 +593,9 @@

loop = asyncio.get_event_loop()
print("Starting UDP server")
+ # One protocol instance will be created to serve all client requests
listen = loop.create_datagram_endpoint(
- EchoServerClientProtocol, local_addr=('127.0.0.1', 9999))
+ EchoServerProtocol, local_addr=('127.0.0.1', 9999))
transport, protocol = loop.run_until_complete(listen)

try:
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-12 09:35:34 UTC
Permalink
https://hg.python.org/cpython/rev/1068bd9e3aec
changeset: 92985:1068bd9e3aec
parent: 92982:55d50b544a3d
parent: 92984:5443dee24548
user: Victor Stinner <victor.stinner at gmail.com>
date: Sun Oct 12 11:25:10 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-eventloop.rst | 3 +
Doc/library/asyncio-protocol.rst | 103 ++++++++++++++++-
2 files changed, 99 insertions(+), 7 deletions(-)


diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -243,6 +243,9 @@

On Windows with :class:`ProactorEventLoop`, this method is not supported.

+ See :ref:`UDP echo client protocol <asyncio-udp-echo-client-protocol>` and
+ :ref:`UDP echo server protocol <asyncio-udp-echo-server-protocol>` examples.
+

.. method:: BaseEventLoop.create_unix_connection(protocol_factory, path, \*, ssl=None, sock=None, server_hostname=None)

diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst
--- a/Doc/library/asyncio-protocol.rst
+++ b/Doc/library/asyncio-protocol.rst
@@ -473,6 +473,7 @@
running loop. At :meth:`~BaseEventLoop.run_until_complete` exit, the loop is
no longer running, so there is no need to stop the loop in case of an error.

+
TCP echo server
---------------

@@ -483,34 +484,122 @@
class EchoServer(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
- print('connection from {}'.format(peername))
+ print('Connection from {}'.format(peername))
self.transport = transport

def data_received(self, data):
- print('data received: {}'.format(data.decode()))
+ message = data.decode()
+ print('Data received: {!r}'.format(message))
+
+ print('Send: {!r}'.format(message))
self.transport.write(data)

- # close the socket
+ print('Close the socket')
self.transport.close()

loop = asyncio.get_event_loop()
coro = loop.create_server(EchoServer, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
- print('serving on {}'.format(server.sockets[0].getsockname()))

+ # Server requests until CTRL+c is pressed
+ print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
print("exit")
- finally:
- server.close()
- loop.close()
+
+ # Close the server
+ server.close()
+ loop.run_until_complete(server.wait_closed())
+ loop.close()

: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 not coroutines.

+
+.. _asyncio-udp-echo-client-protocol:
+
+UDP echo client protocol
+------------------------
+
+UDP echo client using the :meth:`BaseEventLoop.create_datagram_endpoint`
+method, send data and close the transport when we received the answer::
+
+ import asyncio
+
+ class EchoClientProtocol:
+ def __init__(self, message, loop):
+ self.message = message
+ self.loop = loop
+ self.transport = None
+
+ def connection_made(self, transport):
+ self.transport = transport
+ print('Send:', self.message)
+ self.transport.sendto(self.message.encode())
+
+ def datagram_received(self, data, addr):
+ print("Received:", data.decode())
+
+ print("Close the socket")
+ self.transport.close()
+
+ def error_received(self, exc):
+ print('Error received:', exc)
+
+ def connection_lost(self, exc):
+ print("Socket closed, stop the event loop")
+ loop = asyncio.get_event_loop()
+ loop.stop()
+
+ loop = asyncio.get_event_loop()
+ message = "Hello World!"
+ connect = loop.create_datagram_endpoint(
+ lambda: EchoClientProtocol(message, loop),
+ remote_addr=('127.0.0.1', 9999))
+ transport, protocol = loop.run_until_complete(connect)
+ loop.run_forever()
+ transport.close()
+ loop.close()
+
+
+.. _asyncio-udp-echo-server-protocol:
+
+UDP echo server protocol
+------------------------
+
+UDP echo server using the :meth:`BaseEventLoop.create_datagram_endpoint`
+method, send back received data::
+
+ import asyncio
+
+ class EchoServerClientProtocol:
+ def connection_made(self, transport):
+ self.transport = transport
+
+ def datagram_received(self, data, addr):
+ message = data.decode()
+ print('Received %r from %s' % (message, addr))
+ print('Send %r to %s' % (message, addr))
+ self.transport.sendto(data, addr)
+
+ loop = asyncio.get_event_loop()
+ print("Starting UDP server")
+ listen = loop.create_datagram_endpoint(
+ EchoServerClientProtocol, local_addr=('127.0.0.1', 9999))
+ transport, protocol = loop.run_until_complete(listen)
+
+ try:
+ loop.run_forever()
+ except KeyboardInterrupt:
+ pass
+
+ transport.close()
+ loop.close()
+
+
.. _asyncio-register-socket:

Register an open socket to wait for data using a protocol
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-12 22:10:11 UTC
Permalink
https://hg.python.org/cpython/rev/3ea5ebfd13e4
changeset: 93014:3ea5ebfd13e4
parent: 93008:4c9d27eef892
parent: 93013:1f649b8cf69a
user: Victor Stinner <victor.stinner at gmail.com>
date: Mon Oct 13 00:10:02 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-dev.rst | 47 ++++++----
Doc/library/asyncio-eventloop.rst | 64 +++++++------
Doc/library/asyncio-eventloops.rst | 2 +-
Doc/library/asyncio-protocol.rst | 32 +++++-
Doc/library/asyncio-stream.rst | 78 ++++++++++++++++++
Doc/library/asyncio-task.rst | 3 +-
6 files changed, 168 insertions(+), 58 deletions(-)


diff --git a/Doc/library/asyncio-dev.rst b/Doc/library/asyncio-dev.rst
--- a/Doc/library/asyncio-dev.rst
+++ b/Doc/library/asyncio-dev.rst
@@ -166,25 +166,34 @@
Output::

Task exception was never retrieved
- future: <Task finished bug() done at asyncio/coroutines.py:139 exception=Exception('not consumed',)>
- source_traceback: Object created at (most recent call last):
- File "test.py", line 10, in <module>
- asyncio.async(bug())
- File "asyncio/tasks.py", line 510, in async
- task = loop.create_task(coro_or_future)
+ future: <Task finished coro=<coro() done, defined at asyncio/coroutines.py:139> exception=Exception('not consumed',)>
Traceback (most recent call last):
- File "asyncio/tasks.py", line 244, in _step
+ File "asyncio/tasks.py", line 237, in _step
result = next(coro)
- File "coroutines.py", line 78, in __next__
- return next(self.gen)
File "asyncio/coroutines.py", line 141, in coro
res = func(*args, **kw)
- File "test.py", line 7, in bug
+ File "test.py", line 5, in bug
raise Exception("not consumed")
Exception: not consumed

:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
-traceback where the task was created.
+traceback where the task was created. Output in debug mode::
+
+ Task exception was never retrieved
+ future: <Task finished coro=<bug() done, defined at test.py:3> exception=Exception('not consumed',) created at test.py:8>
+ source_traceback: Object created at (most recent call last):
+ File "test.py", line 8, in <module>
+ asyncio.async(bug())
+ Traceback (most recent call last):
+ File "asyncio/tasks.py", line 237, in _step
+ result = next(coro)
+ File "asyncio/coroutines.py", line 79, in __next__
+ return next(self.gen)
+ File "asyncio/coroutines.py", line 141, in coro
+ res = func(*args, **kw)
+ File "test.py", line 5, in bug
+ raise Exception("not consumed")
+ Exception: not consumed

There are different options to fix this issue. The first option is to chain to
coroutine in another coroutine and use classic try/except::
@@ -303,15 +312,17 @@
Example of log::

Task was destroyed but it is pending!
- source_traceback: Object created at (most recent call last):
- File "test.py", line 17, in <module>
- task = asyncio.async(coro, loop=loop)
- File "asyncio/tasks.py", line 510, in async
- task = loop.create_task(coro_or_future)
- task: <Task pending kill_me() done at test.py:5 wait_for=<Future pending cb=[Task._wakeup()]>>
+ task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()]>>

:ref:`Enable the debug mode of asyncio <asyncio-debug-mode>` to get the
-traceback where the task was created.
+traceback where the task was created. Example of log in debug mode::
+
+ Task was destroyed but it is pending!
+ source_traceback: Object created at (most recent call last):
+ File "test.py", line 15, in <module>
+ task = asyncio.async(coro, loop=loop)
+ task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()] created at test.py:7> created at test.py:15>
+

.. seealso::

diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -258,8 +258,6 @@
establish the connection in the background. When successful, the
coroutine returns a ``(transport, protocol)`` pair.

- On Windows with :class:`ProactorEventLoop`, SSL/TLS is not supported.
-
See the :meth:`BaseEventLoop.create_connection` method for parameters.

Availability: UNIX.
@@ -270,36 +268,42 @@

.. method:: BaseEventLoop.create_server(protocol_factory, host=None, port=None, \*, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None)

- Create a TCP server bound to *host* and *port*. Return a :class:`Server` object,
- its :attr:`~Server.sockets` attribute contains created sockets. Use the
- :meth:`Server.close` method to stop the server: close listening sockets.
+ Create a TCP server (socket type :data:`~socket.SOCK_STREAM`) bound to
+ *host* and *port*.
+
+ Return a :class:`Server` object, its :attr:`~Server.sockets` attribute
+ contains created sockets. Use the :meth:`Server.close` method to stop the
+ server: close listening sockets.
+
+ Parameters:
+
+ * If *host* is an empty string or ``None``, all interfaces are assumed
+ and a list of multiple sockets will be returned (most likely
+ one for IPv4 and another one for IPv6).
+
+ * *family* can be set to either :data:`socket.AF_INET` or
+ :data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. If not set
+ it will be determined from host (defaults to :data:`socket.AF_UNSPEC`).
+
+ * *flags* is a bitmask for :meth:`getaddrinfo`.
+
+ * *sock* can optionally be specified in order to use a preexisting
+ socket object. If specified, *host* and *port* should be omitted (must be
+ :const:`None`).
+
+ * *backlog* is the maximum number of queued connections passed to
+ :meth:`~socket.socket.listen` (defaults to 100).
+
+ * *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over the
+ accepted connections.
+
+ * *reuse_address* tells the kernel to reuse a local socket in
+ TIME_WAIT state, without waiting for its natural timeout to
+ expire. If not specified will automatically be set to True on
+ UNIX.

This method is a :ref:`coroutine <coroutine>`.

- If *host* is an empty string or ``None``, all interfaces are assumed
- and a list of multiple sockets will be returned (most likely
- one for IPv4 and another one for IPv6).
-
- *family* can be set to either :data:`socket.AF_INET` or
- :data:`~socket.AF_INET6` to force the socket to use IPv4 or IPv6. If not set
- it will be determined from host (defaults to :data:`socket.AF_UNSPEC`).
-
- *flags* is a bitmask for :meth:`getaddrinfo`.
-
- *sock* can optionally be specified in order to use a preexisting
- socket object.
-
- *backlog* is the maximum number of queued connections passed to
- :meth:`~socket.socket.listen` (defaults to 100).
-
- *ssl* can be set to an :class:`~ssl.SSLContext` to enable SSL over the
- accepted connections.
-
- *reuse_address* tells the kernel to reuse a local socket in
- TIME_WAIT state, without waiting for its natural timeout to
- expire. If not specified will automatically be set to True on
- UNIX.
-
On Windows with :class:`ProactorEventLoop`, SSL/TLS is not supported.

.. seealso::
@@ -462,7 +466,7 @@

*protocol_factory* should instantiate object with :class:`BaseProtocol`
interface. *pipe* is file-like object.
- Return pair (transport, protocol), where transport support
+ Return pair (transport, protocol), where *transport* supports
:class:`WriteTransport` interface.

With :class:`SelectorEventLoop` event loop, the *pipe* is set to
diff --git a/Doc/library/asyncio-eventloops.rst b/Doc/library/asyncio-eventloops.rst
--- a/Doc/library/asyncio-eventloops.rst
+++ b/Doc/library/asyncio-eventloops.rst
@@ -76,7 +76,7 @@

Common limits of Windows event loops:

-- :meth:`~BaseEventLoop.create_unix_server` and
+- :meth:`~BaseEventLoop.create_unix_connection` and
:meth:`~BaseEventLoop.create_unix_server` are not supported: the socket
family :data:`socket.AF_UNIX` is specific to UNIX
- :meth:`~BaseEventLoop.add_signal_handler` and
diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst
--- a/Doc/library/asyncio-protocol.rst
+++ b/Doc/library/asyncio-protocol.rst
@@ -439,10 +439,13 @@
Protocol examples
=================

-TCP echo client
----------------
+.. _asyncio-tcp-echo-client-protocol:

-TCP echo client example, send data and wait until the connection is closed::
+TCP echo client protocol
+------------------------
+
+TCP echo client using the :meth:`BaseEventLoop.create_connection` method, send
+data and wait until the connection is closed::

import asyncio

@@ -478,11 +481,19 @@
running loop. At :meth:`~BaseEventLoop.run_until_complete` exit, the loop is
no longer running, so there is no need to stop the loop in case of an error.

+.. seealso::

-TCP echo server
----------------
+ The :ref:`TCP echo client using streams <asyncio-tcp-echo-client-streams>`
+ example uses the :func:`asyncio.open_connection` function.

-TCP echo server example, send back received data and close the connection::
+
+.. _asyncio-tcp-echo-server-protocol:
+
+TCP echo server protocol
+------------------------
+
+TCP echo server using the :meth:`BaseEventLoop.create_server` method, send back
+received data and close the connection::

import asyncio

@@ -507,12 +518,12 @@
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)

- # Server requests until CTRL+c is pressed
+ # Serve requests until CTRL+c is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
- print("exit")
+ pass

# Close the server
server.close()
@@ -524,6 +535,11 @@
methods are asynchronous. ``yield from`` is not needed because these transport
methods are not coroutines.

+.. seealso::
+
+ The :ref:`TCP echo server using streams <asyncio-tcp-echo-server-streams>`
+ example uses the :func:`asyncio.start_server` function.
+

.. _asyncio-udp-echo-client-protocol:

diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst
--- a/Doc/library/asyncio-stream.rst
+++ b/Doc/library/asyncio-stream.rst
@@ -241,6 +241,84 @@
Stream examples
===============

+.. _asyncio-tcp-echo-client-streams:
+
+TCP echo client using streams
+-----------------------------
+
+TCP echo client using the :func:`asyncio.open_connection` function::
+
+ import asyncio
+
+ def tcp_echo_client(message, loop):
+ reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,
+ loop=loop)
+
+ print('Send: %r' % message)
+ writer.write(message.encode())
+
+ data = yield from reader.read(100)
+ print('Received: %r' % data.decode())
+
+ print('Close the socket')
+ writer.close()
+
+ message = 'Hello World!'
+ loop = asyncio.get_event_loop()
+ loop.run_until_complete(tcp_echo_client(message, loop))
+ loop.close()
+
+.. seealso::
+
+ The :ref:`TCP echo client protocol <asyncio-tcp-echo-client-protocol>`
+ example uses the :meth:`BaseEventLoop.create_connection` method.
+
+
+.. _asyncio-tcp-echo-server-streams:
+
+TCP echo server using streams
+-----------------------------
+
+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)
+ 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()
+
+ print("Close the client socket")
+ writer.close()
+
+ loop = asyncio.get_event_loop()
+ coro = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
+ server = loop.run_until_complete(coro)
+
+ # Serve requests until CTRL+c is pressed
+ print('Serving on {}'.format(server.sockets[0].getsockname()))
+ try:
+ loop.run_forever()
+ except KeyboardInterrupt:
+ pass
+
+ # Close the server
+ server.close()
+ loop.run_until_complete(server.wait_closed())
+ loop.close()
+
+.. seealso::
+
+ The :ref:`TCP echo server protocol <asyncio-tcp-echo-server-protocol>`
+ example uses the :meth:`BaseEventLoop.create_server` method.
+
+
Get HTTP headers
----------------

diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -478,7 +478,8 @@

.. function:: async(coro_or_future, \*, loop=None)

- Wrap a :ref:`coroutine object <coroutine>` in a future.
+ Schedule the execution of a :ref:`coroutine object <coroutine>`: wrap it in
+ a future. Return a :class:`Task` object.

If the argument is a :class:`Future`, it is returned directly.
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-12 22:56:12 UTC
Permalink
https://hg.python.org/cpython/rev/7620bf3b8281
changeset: 93016:7620bf3b8281
parent: 93014:3ea5ebfd13e4
parent: 93015:a66c05e1cea4
user: Victor Stinner <victor.stinner at gmail.com>
date: Mon Oct 13 00:56:02 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-stream.rst | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)


diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst
--- a/Doc/library/asyncio-stream.rst
+++ b/Doc/library/asyncio-stream.rst
@@ -250,6 +250,7 @@

import asyncio

+ @asyncio.coroutine
def tcp_echo_client(message, loop):
reader, writer = yield from asyncio.open_connection('127.0.0.1', 8888,
loop=loop)
@@ -379,6 +380,7 @@
except ImportError:
from asyncio.windows_utils import socketpair

+ @asyncio.coroutine
def wait_for_data(loop):
# Create a pair of connected sockets
rsock, wsock = socketpair()
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-13 22:53:36 UTC
Permalink
https://hg.python.org/cpython/rev/d9a3d23cf8f0
changeset: 93049:d9a3d23cf8f0
parent: 93043:18be8ceaa20f
parent: 93048:d894aa49d5e4
user: Victor Stinner <victor.stinner at gmail.com>
date: Tue Oct 14 00:53:13 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-protocol.rst | 19 +-
Doc/library/asyncio-subprocess.rst | 260 ++++++++++++----
Doc/library/subprocess.rst | 2 +-
3 files changed, 200 insertions(+), 81 deletions(-)


diff --git a/Doc/library/asyncio-protocol.rst b/Doc/library/asyncio-protocol.rst
--- a/Doc/library/asyncio-protocol.rst
+++ b/Doc/library/asyncio-protocol.rst
@@ -207,10 +207,15 @@
.. method:: get_pipe_transport(fd)

Return the transport for the communication pipe corresponding to the
- integer file descriptor *fd*. The return value can be a readable or
- writable streaming transport, depending on the *fd*. If *fd* doesn't
- correspond to a pipe belonging to this transport, :const:`None` is
- returned.
+ integer file descriptor *fd*:
+
+ * ``0``: readable streaming transport of the standard input (*stdin*),
+ or :const:`None` if the subprocess was not created with ``stdin=PIPE``
+ * ``1``: writable streaming transport of the standard output (*stdout*),
+ or :const:`None` if the subprocess was not created with ``stdout=PIPE``
+ * ``2``: writable streaming transport of the standard error (*stderr*),
+ or :const:`None` if the subprocess was not created with ``stderr=PIPE``
+ * other *fd*: :const:`None`

.. method:: get_returncode()

@@ -239,6 +244,12 @@
On Windows, the Windows API function TerminateProcess() is called to
stop the subprocess.

+ .. method:: close()
+
+ Ask the subprocess to stop by calling the :meth:`terminate` method if the
+ subprocess hasn't returned yet, and close transports of all pipes
+ (*stdin*, *stdout* and *stderr*).
+

.. _asyncio-protocol:

diff --git a/Doc/library/asyncio-subprocess.rst b/Doc/library/asyncio-subprocess.rst
--- a/Doc/library/asyncio-subprocess.rst
+++ b/Doc/library/asyncio-subprocess.rst
@@ -27,23 +27,34 @@
Create a subprocess: high-level API using Process
-------------------------------------------------

-.. function:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds)
+.. function:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds)

- Run the shell command *cmd*. See :meth:`BaseEventLoop.subprocess_shell` for
- parameters. Return a :class:`~asyncio.subprocess.Process` instance.
+ Create a subprocess.

- The optional *limit* parameter sets the buffer limit passed to the
- :class:`StreamReader`.
+ The *limit* parameter sets the buffer limit passed to the
+ :class:`StreamReader`. See :meth:`BaseEventLoop.subprocess_exec` for other
+ parameters.
+
+ Return a :class:`~asyncio.subprocess.Process` instance.

This function is a :ref:`coroutine <coroutine>`.

-.. function:: create_subprocess_exec(\*args, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds)
+.. function:: create_subprocess_shell(cmd, stdin=None, stdout=None, stderr=None, loop=None, limit=None, \*\*kwds)

- Create a subprocess. See :meth:`BaseEventLoop.subprocess_exec` for
- parameters. Return a :class:`~asyncio.subprocess.Process` instance.
+ Run the shell command *cmd*.

- The optional *limit* parameter sets the buffer limit passed to the
- :class:`StreamReader`.
+ The *limit* parameter sets the buffer limit passed to the
+ :class:`StreamReader`. See :meth:`BaseEventLoop.subprocess_shell` for other
+ parameters.
+
+ Return a :class:`~asyncio.subprocess.Process` instance.
+
+ It is the application's responsibility to ensure that all whitespace and
+ metacharacters are quoted appropriately to avoid `shell injection
+ <http://en.wikipedia.org/wiki/Shell_injection#Shell_injection>`_
+ vulnerabilities. The :func:`shlex.quote` function can be used to properly
+ escape whitespace and shell metacharacters in strings that are going to be
+ used to construct shell commands.

This function is a :ref:`coroutine <coroutine>`.

@@ -69,6 +80,9 @@
however, where :class:`~subprocess.Popen` takes a single argument which is
list of strings, :func:`subprocess_exec` takes multiple string arguments.

+ The *protocol_factory* must instanciate a subclass of the
+ :class:`asyncio.SubprocessProtocol` class.
+
Other parameters:

* *stdin*: Either a file-like object representing the pipe to be connected
@@ -109,16 +123,24 @@
using the platform's "shell" syntax. This is similar to the standard library
:class:`subprocess.Popen` class called with ``shell=True``.

+ The *protocol_factory* must instanciate a subclass of the
+ :class:`asyncio.SubprocessProtocol` class.
+
See :meth:`~BaseEventLoop.subprocess_exec` for more details about
the remaining arguments.

Returns a pair of ``(transport, protocol)``, where *transport* is an
instance of :class:`BaseSubprocessTransport`.

+ It is the application's responsibility to ensure that all whitespace and
+ metacharacters are quoted appropriately to avoid `shell injection
+ <http://en.wikipedia.org/wiki/Shell_injection#Shell_injection>`_
+ vulnerabilities. The :func:`shlex.quote` function can be used to properly
+ escape whitespace and shell metacharacters in strings that are going to be
+ used to construct shell commands.
+
This method is a :ref:`coroutine <coroutine>`.

- See the constructor of the :class:`subprocess.Popen` class for parameters.
-
.. seealso::

The :meth:`BaseEventLoop.connect_read_pipe` and
@@ -153,35 +175,37 @@

.. class:: asyncio.subprocess.Process

- .. attribute:: pid
+ A subprocess created by the :func:`create_subprocess_exec` or the
+ :func:`create_subprocess_shell` function.

- The identifier of the process.
+ The API of the :class:`~asyncio.subprocess.Process` class was designed to be
+ closed the API of the :class:`subprocess.Popen` class, but they are some
+ differences:

- Note that if you set the *shell* argument to ``True``, this is the
- process identifier of the spawned shell.
+ * There is no explicit :meth:`~subprocess.Popen.poll` method
+ * The :meth:`~subprocess.Popen.communicate` and
+ :meth:`~subprocess.Popen.wait` methods don't take a *timeout* parameter:
+ use the :func:`wait_for` function
+ * The *universal_newlines* parameter is not supported (only bytes strings
+ are supported)
+ * The :meth:`~asyncio.subprocess.Process.wait` method of
+ the :class:`~asyncio.subprocess.Process` class is asynchronous whereas the
+ :meth:`~subprocess.Popen.wait` method of the :class:`~subprocess.Popen`
+ class is implemented as a busy loop.

- .. attribute:: returncode
+ .. method:: wait()

- Return code of the process when it exited. A ``None`` value indicates
- that the process has not terminated yet.
+ Wait for child process to terminate. Set and return :attr:`returncode`
+ attribute.

- A negative value ``-N`` indicates that the child was terminated by signal
- ``N`` (Unix only).
+ This method is a :ref:`coroutine <coroutine>`.

- .. attribute:: stdin
+ .. note::

- Standard input stream (write), ``None`` if the process was created with
- ``stdin=None``.
-
- .. attribute:: stdout
-
- Standard output stream (read), ``None`` if the process was created with
- ``stdout=None``.
-
- .. attribute:: stderr
-
- Standard error stream (read), ``None`` if the process was created with
- ``stderr=None``.
+ This will deadlock when using ``stdout=PIPE`` or ``stderr=PIPE`` and
+ the child process generates enough output to a pipe such that it
+ blocks waiting for the OS pipe buffer to accept more data. Use the
+ :meth:`communicate` method when using pipes to avoid that.

.. method:: communicate(input=None)

@@ -191,33 +215,28 @@
process, or ``None``, if no data should be sent to the child. The type
of *input* must be bytes.

+ :meth:`communicate` returns a tuple ``(stdout_data, stderr_data)``.
+
If a :exc:`BrokenPipeError` or :exc:`ConnectionResetError` exception is
raised when writing *input* into stdin, the exception is ignored. It
occurs when the process exits before all data are written into stdin.

- :meth:`communicate` returns a tuple ``(stdoutdata, stderrdata)``.
-
Note that if you want to send data to the process's stdin, you need to
create the Process object with ``stdin=PIPE``. Similarly, to get anything
other than ``None`` in the result tuple, you need to give ``stdout=PIPE``
and/or ``stderr=PIPE`` too.

+ This method is a :ref:`coroutine <coroutine>`.
+
.. note::

The data read is buffered in memory, so do not use this method if the
data size is large or unlimited.

- This method is a :ref:`coroutine <coroutine>`.
-
.. versionchanged:: 3.4.2
The method now ignores :exc:`BrokenPipeError` and
:exc:`ConnectionResetError`.

- .. method:: kill()
-
- Kills the child. On Posix OSs the function sends :py:data:`SIGKILL` to
- the child. On Windows :meth:`kill` is an alias for :meth:`terminate`.
-
.. method:: send_signal(signal)

Sends the signal *signal* to the child process.
@@ -235,53 +254,142 @@
to the child. On Windows the Win32 API function
:c:func:`TerminateProcess` is called to stop the child.

- .. method:: wait():
+ .. method:: kill()

- Wait for child process to terminate. Set and return :attr:`returncode`
- attribute.
+ Kills the child. On Posix OSs the function sends :py:data:`SIGKILL` to
+ the child. On Windows :meth:`kill` is an alias for :meth:`terminate`.

- This method is a :ref:`coroutine <coroutine>`.
+ .. attribute:: stdin

+ Standard input stream (:class:`StreamWriter`), ``None`` if the process
+ was created with ``stdin=None``.

-Example
--------
+ .. attribute:: stdout

-Implement a function similar to :func:`subprocess.getstatusoutput`, except that
-it does not use a shell. Get the output of the "python -m platform" command and
-display the output::
+ Standard output stream (:class:`StreamReader`), ``None`` if the process
+ was created with ``stdout=None``.
+
+ .. attribute:: stderr
+
+ Standard error stream (:class:`StreamReader`), ``None`` if the process
+ was created with ``stderr=None``.
+
+ .. warning::
+
+ Use the :meth:`communicate` method rather than :attr:`.stdin.write
+ <stdin>`, :attr:`.stdout.read <stdout>` or :attr:`.stderr.read <stderr>`
+ to avoid deadlocks due to streams pausing reading or writing and blocking
+ the child process.
+
+ .. attribute:: pid
+
+ The identifier of the process.
+
+ Note that for processes created by the :func:`create_subprocess_shell`
+ function, this attribute is the process identifier of the spawned shell.
+
+ .. attribute:: returncode
+
+ Return code of the process when it exited. A ``None`` value indicates
+ that the process has not terminated yet.
+
+ A negative value ``-N`` indicates that the child was terminated by signal
+ ``N`` (Unix only).
+
+
+Subprocess examples
+===================
+
+Subprocess using transport and protocol
+---------------------------------------
+
+Example of a subprocess protocol using to get the output of a subprocess and to
+wait for the subprocess exit. The subprocess is created by the
+:meth:`BaseEventLoop.subprocess_exec` method::

import asyncio
- import os
import sys
- from asyncio import subprocess
+
+ class DateProtocol(asyncio.SubprocessProtocol):
+ def __init__(self, exit_future):
+ self.exit_future = exit_future
+ self.output = bytearray()
+
+ def pipe_data_received(self, fd, data):
+ self.output.extend(data)
+
+ def process_exited(self):
+ self.exit_future.set_result(True)

@asyncio.coroutine
- def getstatusoutput(*args):
- proc = yield from asyncio.create_subprocess_exec(
- *args,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- try:
- stdout, _ = yield from proc.communicate()
- except:
- proc.kill()
- yield from proc.wait()
- raise
- exitcode = yield from proc.wait()
- return (exitcode, stdout)
+ def get_date(loop):
+ code = 'import datetime; print(datetime.datetime.now())'
+ exit_future = asyncio.Future(loop=loop)

- if os.name == 'nt':
+ # 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
+
+ # Wait for the subprocess exit using the process_exited() method
+ # of the protocol
+ yield from exit_future
+
+ # Close the stdout pipe
+ transport.close()
+
+ # Read the output which was collected by the pipe_data_received()
+ # method of the protocol
+ data = bytes(protocol.output)
+ return data.decode('ascii').rstrip()
+
+ if sys.platform == "win32":
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
- coro = getstatusoutput(sys.executable, '-m', 'platform')
- exitcode, stdout = loop.run_until_complete(coro)
- if not exitcode:
- stdout = stdout.decode('ascii').rstrip()
- print("Platform: %s" % stdout)
+
+ date = loop.run_until_complete(get_date(loop))
+ print("Current date: %s" % date)
+ loop.close()
+
+
+Subprocess using streams
+------------------------
+
+Example using the :class:`~asyncio.subprocess.Process` class to control the
+subprocess and the :class:`StreamReader` class to read from the standard
+output. The subprocess is created by the :func:`create_subprocess_exec`
+function::
+
+ import asyncio.subprocess
+ import sys
+
+ @asyncio.coroutine
+ def get_date():
+ 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
+
+ # Read one line of output
+ data = yield from proc.stdout.readline()
+ line = data.decode('ascii').rstrip()
+
+ # Wait for the subprocess exit
+ yield from proc.wait()
+ return line
+
+ if sys.platform == "win32":
+ loop = asyncio.ProactorEventLoop()
+ asyncio.set_event_loop(loop)
else:
- print("Python failed with exit code %s:" % exitcode, flush=True)
- sys.stdout.buffer.write(stdout)
- sys.stdout.buffer.flush()
+ loop = asyncio.get_event_loop()
+
+ date = loop.run_until_complete(get_date())
+ print("Current date: %s" % date)
loop.close()
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -634,7 +634,7 @@
``None``, if no data should be sent to the child. The type of *input*
must be bytes or, if *universal_newlines* was ``True``, a string.

- :meth:`communicate` returns a tuple ``(stdoutdata, stderrdata)``.
+ :meth:`communicate` returns a tuple ``(stdout_data, stderr_data)``.
The data will be bytes or, if *universal_newlines* was ``True``, strings.

Note that if you want to send data to the process's stdin, you need to create
--
Repository URL: https://hg.python.org/cpython
victor.stinner
2014-10-15 16:50:00 UTC
Permalink
https://hg.python.org/cpython/rev/4135060ecf04
changeset: 93078:4135060ecf04
parent: 93076:8195d48a5c43
parent: 93077:52d4dde01a10
user: Victor Stinner <victor.stinner at gmail.com>
date: Wed Oct 15 18:49:32 2014 +0200
summary:
Merge 3.4 (asyncio doc)

files:
Doc/library/asyncio-eventloop.rst | 61 +++++++++++++++---
Doc/library/asyncio-task.rst | 58 +++++++++++++----
2 files changed, 94 insertions(+), 25 deletions(-)


diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst
--- a/Doc/library/asyncio-eventloop.rst
+++ b/Doc/library/asyncio-eventloop.rst
@@ -649,24 +649,27 @@

.. _asyncio-hello-world-callback:

-Hello World with a callback
----------------------------
+Hello World with call_soon()
+----------------------------

-Print ``"Hello World"`` every two seconds using a callback scheduled by the
-:meth:`BaseEventLoop.call_soon` method::
+Example using the :meth:`BaseEventLoop.call_soon` method to schedule a
+callback. The callback displays ``"Hello World"`` and then stops the event
+loop::

import asyncio

- def print_and_repeat(loop):
+ def hello_world(loop):
print('Hello World')
- loop.call_later(2, print_and_repeat, loop)
+ loop.stop()

loop = asyncio.get_event_loop()
- loop.call_soon(print_and_repeat, loop)
- try:
- loop.run_forever()
- finally:
- loop.close()
+
+ # Schedule a call to hello_world()
+ loop.call_soon(hello_world, loop)
+
+ # Blocking call interrupted by loop.stop()
+ loop.run_forever()
+ loop.close()

.. seealso::

@@ -674,6 +677,42 @@
uses a :ref:`coroutine <coroutine>`.


+.. _asyncio-date-callback:
+
+Display the current date with call_later()
+------------------------------------------
+
+Example of callback displaying the current date every second. The callback uses
+the :meth:`BaseEventLoop.call_later` method to reschedule itself during 5
+seconds, and then stops the event loop::
+
+ import asyncio
+ import datetime
+
+ def display_date(end_time, loop):
+ print(datetime.datetime.now())
+ if (loop.time() + 1.0) < end_time:
+ loop.call_later(1, display_date, end_time, loop)
+ else:
+ loop.stop()
+
+ loop = asyncio.get_event_loop()
+
+ # Schedule the first call to display_date()
+ end_time = loop.time() + 5.0
+ loop.call_soon(display_date, end_time, loop)
+
+ # Blocking call interrupted by loop.stop()
+ loop.run_forever()
+ loop.close()
+
+.. seealso::
+
+ The :ref:`coroutine displaying the current date
+ <asyncio-date-coroutine>` example uses a :ref:`coroutine
+ <coroutine>`.
+
+
.. _asyncio-watch-read-event:

Watch a file descriptor for read events
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -77,30 +77,60 @@

.. _asyncio-hello-world-coroutine:

-Example: "Hello World" coroutine
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Example: Hello World coroutine
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-Print ``"Hello World"`` every two seconds using a coroutine::
+Example of coroutine displaying ``"Hello World"``::

import asyncio

@asyncio.coroutine
- def greet_every_two_seconds():
- while True:
- print('Hello World')
- yield from asyncio.sleep(2)
+ def hello_world():
+ print("Hello World!")

loop = asyncio.get_event_loop()
- try:
- loop.run_until_complete(greet_every_two_seconds())
- finally:
- loop.close()
+ # Blocking call which returns when the hello_world() coroutine is done
+ loop.run_until_complete(hello_world())
+ loop.close()

.. seealso::

- The :ref:`Hello World with a callback <asyncio-hello-world-callback>`
- example uses a callback scheduled by the :meth:`BaseEventLoop.call_soon`
- method.
+ The :ref:`Hello World with call_soon() <asyncio-hello-world-callback>`
+ example uses the :meth:`BaseEventLoop.call_soon` method to schedule a
+ callback.
+
+
+.. _asyncio-date-coroutine:
+
+Example: Coroutine displaying the current date
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Example of coroutine displaying the current date every second during 5 seconds
+using the :meth:`sleep` function::
+
+ import asyncio
+ import datetime
+
+ @asyncio.coroutine
+ def display_date(loop):
+ end_time = loop.time() + 5.0
+ while True:
+ print(datetime.datetime.now())
+ if (loop.time() + 1.0) >= end_time:
+ break
+ yield from asyncio.sleep(1)
+
+ loop = asyncio.get_event_loop()
+ # Blocking call which returns when the display_date() coroutine is done
+ loop.run_until_complete(display_date(loop))
+ loop.close()
+
+.. seealso::
+
+ The :ref:`display the current date with call_later()
+ <asyncio-date-callback>` example uses a callback with the
+ :meth:`BaseEventLoop.call_later` method.
+

Example: Chain coroutines
^^^^^^^^^^^^^^^^^^^^^^^^^
--
Repository URL: https://hg.python.org/cpython
Loading...