From d31b31516c71890e8735606aec1dbf2bfb8fd6be Mon Sep 17 00:00:00 2001 From: Xtreak Date: Fri, 13 Sep 2019 11:52:38 +0100 Subject: bpo-36889: Document Stream class and add docstrings (GH-14488) * This just copies the docs from `StreamWriter` and `StreamReader`. * Add docstring for asyncio functions. https://bugs.python.org/issue36889 Automerge-Triggered-By: @asvetlov --- Doc/library/asyncio-api-index.rst | 36 ++++++-- Doc/library/asyncio-stream.rst | 179 ++++++++++++++++++++++++++++++++++++-- Lib/asyncio/streams.py | 21 +++++ 3 files changed, 225 insertions(+), 11 deletions(-) diff --git a/Doc/library/asyncio-api-index.rst b/Doc/library/asyncio-api-index.rst index d5b5659..716cf09 100644 --- a/Doc/library/asyncio-api-index.rst +++ b/Doc/library/asyncio-api-index.rst @@ -132,23 +132,47 @@ High-level APIs to work with network IO. :widths: 50 50 :class: full-width-table + * - ``await`` :func:`connect` + - Establish a TCP connection to send and receive data. + * - ``await`` :func:`open_connection` - - Establish a TCP connection. + - Establish a TCP connection. (Deprecated in favor of :func:`connect`) + + * - ``await`` :func:`connect_unix` + - Establish a Unix socket connection to send and receive data. * - ``await`` :func:`open_unix_connection` - - Establish a Unix socket connection. + - Establish a Unix socket connection. (Deprecated in favor of :func:`connect_unix`) - * - ``await`` :func:`start_server` + * - :class:`StreamServer` - Start a TCP server. - * - ``await`` :func:`start_unix_server` + * - ``await`` :func:`start_server` + - Start a TCP server. (Deprecated in favor of :class:`StreamServer`) + + * - :class:`UnixStreamServer` - Start a Unix socket server. + * - ``await`` :func:`start_unix_server` + - Start a Unix socket server. (Deprecated in favor of :class:`UnixStreamServer`) + + * - :func:`connect_read_pipe` + - Establish a connection to :term:`file-like object ` *pipe* + to receive data. + + * - :func:`connect_write_pipe` + - Establish a connection to :term:`file-like object ` *pipe* + to send data. + + * - :class:`Stream` + - Stream is a single object combining APIs of :class:`StreamReader` and + :class:`StreamWriter`. + * - :class:`StreamReader` - - High-level async/await object to receive network data. + - High-level async/await object to receive network data. (Deprecated in favor of :class:`Stream`) * - :class:`StreamWriter` - - High-level async/await object to send network data. + - High-level async/await object to send network data. (Deprecated in favor of :class:`Stream`) .. rubric:: Examples diff --git a/Doc/library/asyncio-stream.rst b/Doc/library/asyncio-stream.rst index dfe520d..feebd22 100644 --- a/Doc/library/asyncio-stream.rst +++ b/Doc/library/asyncio-stream.rst @@ -46,7 +46,6 @@ and work with streams: Connect to TCP socket on *host* : *port* address and return a :class:`Stream` object of mode :attr:`StreamMode.READWRITE`. - *limit* determines the buffer size limit used by the returned :class:`Stream` instance. By default the *limit* is set to 64 KiB. @@ -367,13 +366,184 @@ Stream Represents a Stream object that provides APIs to read and write data to the IO stream . It includes the API provided by :class:`StreamReader` - and :class:`StreamWriter`. + and :class:`StreamWriter`. It can also be used as :term:`asynchronous iterator` + where :meth:`readline` is used. It raises :exc:`StopAsyncIteration` when + :meth:`readline` returns empty data. Do not instantiate *Stream* objects directly; use API like :func:`connect` and :class:`StreamServer` instead. .. versionadded:: 3.8 + .. attribute:: mode + + Returns the mode of the stream which is a :class:`StreamMode` value. It could + be one of the below: + + * :attr:`StreamMode.READ` - Connection can receive data. + * :attr:`StreamMode.WRITE` - Connection can send data. + * :attr:`StreamMode.READWRITE` - Connection can send and receive data. + + .. coroutinemethod:: abort() + + Aborts the connection immediately, without waiting for the send buffer to drain. + + .. method:: at_eof() + + Return ``True`` if the buffer is empty. + + .. method:: can_write_eof() + + Return *True* if the underlying transport supports + the :meth:`write_eof` method, *False* otherwise. + + .. method:: close() + + The method closes the stream and the underlying socket. + + It is possible to directly await on the `close()` method:: + + await stream.close() + + The ``await`` pauses the current coroutine until the stream and the underlying + socket are closed (and SSL shutdown is performed for a secure connection). + + .. coroutinemethod:: drain() + + Wait until it is appropriate to resume writing to the stream. + Example:: + + stream.write(data) + await stream.drain() + + This is a flow control method that interacts with the underlying + IO write buffer. When the size of the buffer reaches + the high watermark, *drain()* blocks until the size of the + buffer is drained down to the low watermark and writing can + be resumed. When there is nothing to wait for, the :meth:`drain` + returns immediately. + + .. deprecated:: 3.8 + + It is recommended to directly await on the `write()` method instead:: + + await stream.write(data) + + .. method:: get_extra_info(name, default=None) + + Access optional transport information; see + :meth:`BaseTransport.get_extra_info` for details. + + .. method:: is_closing() + + Return ``True`` if the stream is closed or in the process of + being closed. + + .. coroutinemethod:: read(n=-1) + + Read up to *n* bytes. If *n* is not provided, or set to ``-1``, + read until EOF and return all read bytes. + + If EOF was received and the internal buffer is empty, + return an empty ``bytes`` object. + + .. coroutinemethod:: readexactly(n) + + Read exactly *n* bytes. + + Raise an :exc:`IncompleteReadError` if EOF is reached before *n* + can be read. Use the :attr:`IncompleteReadError.partial` + attribute to get the partially read data. + + .. coroutinemethod:: readline() + + Read one line, where "line" is a sequence of bytes + ending with ``\n``. + + If EOF is received and ``\n`` was not found, the method + returns partially read data. + + If EOF is received and the internal buffer is empty, + return an empty ``bytes`` object. + + .. coroutinemethod:: readuntil(separator=b'\\n') + + Read data from the stream until *separator* is found. + + On success, the data and separator will be removed from the + internal buffer (consumed). Returned data will include the + separator at the end. + + If the amount of data read exceeds the configured stream limit, a + :exc:`LimitOverrunError` exception is raised, and the data + is left in the internal buffer and can be read again. + + If EOF is reached before the complete separator is found, + an :exc:`IncompleteReadError` exception is raised, and the internal + buffer is reset. The :attr:`IncompleteReadError.partial` attribute + may contain a portion of the separator. + + .. coroutinemethod:: sendfile(file, offset=0, count=None, *, fallback=True) + + Sends a *file* over the stream using an optimized syscall if available. + + For other parameters meaning please see :meth:`AbstractEventloop.sendfile`. + + .. coroutinemethod:: start_tls(sslcontext, *, server_hostname=None, \ + ssl_handshake_timeout=None) + + Upgrades the existing transport-based connection to TLS. + + For other parameters meaning please see :meth:`AbstractEventloop.start_tls`. + + .. coroutinemethod:: wait_closed() + + Wait until the stream is closed. + + Should be called after :meth:`close` to wait until the underlying + connection is closed. + + .. coroutinemethod:: write(data) + + Write *data* to the underlying socket; wait until the data is sent, e.g.:: + + await stream.write(data) + + .. method:: write(data) + + The method attempts to write the *data* to the underlying socket immediately. + If that fails, the data is queued in an internal write buffer until it can be + sent. :meth:`drain` can be used to flush the underlying buffer once writing is + available:: + + stream.write(data) + await stream.drain() + + .. deprecated:: 3.8 + + It is recommended to directly await on the `write()` method instead:: + + await stream.write(data) + + .. method:: writelines(data) + + The method writes a list (or any iterable) of bytes to the underlying socket + immediately. + If that fails, the data is queued in an internal write buffer until it can be + sent. + + It is possible to directly await on the `writelines()` method:: + + await stream.writelines(lines) + + The ``await`` pauses the current coroutine until the data is written to the + socket. + + .. method:: write_eof() + + Close the write end of the stream after the buffered write + data is flushed. + StreamMode ========== @@ -459,8 +629,7 @@ StreamReader .. method:: at_eof() - Return ``True`` if the buffer is empty and :meth:`feed_eof` - was called. + Return ``True`` if the buffer is empty. StreamWriter @@ -504,7 +673,7 @@ StreamWriter If that fails, the data is queued in an internal write buffer until it can be sent. - Starting with Python 3.8, it is possible to directly await on the `write()` + Starting with Python 3.8, it is possible to directly await on the `writelines()` method:: await stream.writelines(lines) diff --git a/Lib/asyncio/streams.py b/Lib/asyncio/streams.py index 4943e8e..b709dc1 100644 --- a/Lib/asyncio/streams.py +++ b/Lib/asyncio/streams.py @@ -70,6 +70,13 @@ def connect(host=None, port=None, *, server_hostname=None, ssl_handshake_timeout=None, happy_eyeballs_delay=None, interleave=None): + """Connect to TCP socket on *host* : *port* address to send and receive data. + + *limit* determines the buffer size limit used by the returned `Stream` + instance. By default the *limit* is set to 64 KiB. + + The rest of the arguments are passed directly to `loop.create_connection()`. + """ # Design note: # Don't use decorator approach but explicit non-async # function to fail fast and explicitly @@ -108,6 +115,13 @@ async def _connect(host, port, def connect_read_pipe(pipe, *, limit=_DEFAULT_LIMIT): + """Establish a connection to a file-like object *pipe* to receive data. + + Takes a file-like object *pipe* to return a Stream object of the mode + StreamMode.READ that has similar API of StreamReader. It can also be used + as an async context manager. + """ + # Design note: # Don't use decorator approach but explicit non-async # function to fail fast and explicitly @@ -129,6 +143,13 @@ async def _connect_read_pipe(pipe, limit): def connect_write_pipe(pipe, *, limit=_DEFAULT_LIMIT): + """Establish a connection to a file-like object *pipe* to send data. + + Takes a file-like object *pipe* to return a Stream object of the mode + StreamMode.WRITE that has similar API of StreamWriter. It can also be used + as an async context manager. + """ + # Design note: # Don't use decorator approach but explicit non-async # function to fail fast and explicitly -- cgit v0.12