Skip to content

Commit

Permalink
Polish docs and ABC, convert everything except multipart and client t…
Browse files Browse the repository at this point in the history
…o async/await syntax (#2483)

* Make AbstractPayloadWriter.write() an async function

* Drop response.drain() from docs

* Add removal changenote

* Add a deprecation warning for StreamResponse.drain()

* Fix several tests

* Fix doc

* Polish README

* Fix tests

* Update CHANGES
  • Loading branch information
asvetlov committed Nov 9, 2017
1 parent 8fd679f commit 53edaa6
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 90 deletions.
3 changes: 3 additions & 0 deletions CHANGES/2483.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`StreamResponse.drain()` is not a part of public API anymore, just use
`await StreamResponse.write()`. `StreamResponse.write` is converted to
async function.
2 changes: 1 addition & 1 deletion aiohttp/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class AbstractPayloadWriter(ABC):
"""Abstract payload writer."""

@abstractmethod
def write(self, chunk):
async def write(self, chunk):
"""Write chunk into stream."""

@abstractmethod
Expand Down
2 changes: 1 addition & 1 deletion aiohttp/http_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ async def drain(self):
The intended use is to write
w.write(data)
await w.write(data)
await w.drain()
"""
if self._protocol.transport is not None:
Expand Down
7 changes: 4 additions & 3 deletions aiohttp/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from aiohttp.client import _RequestContextManager

from . import ClientSession, hdrs
from .helpers import noop, sentinel
from .helpers import sentinel
from .http import HttpVersion, RawRequestMessage
from .signals import Signal
from .web import Request, Server, UrlMappingMatchInfo
Expand Down Expand Up @@ -526,8 +526,9 @@ def make_mocked_request(method, path, headers=None, *,

if payload_writer is sentinel:
payload_writer = mock.Mock()
payload_writer.write_eof.side_effect = noop
payload_writer.drain.side_effect = noop
payload_writer.write = make_mocked_coro(None)
payload_writer.write_eof = make_mocked_coro(None)
payload_writer.drain = make_mocked_coro(None)

protocol.transport = transport
protocol.writer = writer
Expand Down
7 changes: 5 additions & 2 deletions aiohttp/web_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def _start(self, request,

return writer

def write(self, data):
async def write(self, data):
assert isinstance(data, (bytes, bytearray, memoryview)), \
"data argument must be byte-ish (%r)" % type(data)

Expand All @@ -402,12 +402,15 @@ def write(self, data):
if self._payload_writer is None:
raise RuntimeError("Cannot call write() before prepare()")

return self._payload_writer.write(data)
await self._payload_writer.write(data)

async def drain(self):
assert not self._eof_sent, "EOF has already been sent"
assert self._payload_writer is not None, \
"Response has not been started"
warnings.warn("drain method is deprecated, use await resp.write()",
DeprecationWarning,
stacklevel=2)
await self._payload_writer.drain()

async def write_eof(self, data=b''):
Expand Down
3 changes: 1 addition & 2 deletions docs/web_lowlevel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ parameter and performs one of the following actions:

2. Create a :class:`StreamResponse`, send headers by
:meth:`StreamResponse.prepare` call, send data chunks by
:meth:`StreamResponse.write` / :meth:`StreamResponse.drain`,
return finished response.
:meth:`StreamResponse.write` and return finished response.

3. Raise :class:`HTTPException` derived exception (see
:ref:`aiohttp-web-exceptions` section).
Expand Down
58 changes: 22 additions & 36 deletions docs/web_reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ and :ref:`aiohttp-web-signals` handlers.

:return: a cloned :class:`Request` instance.

.. coroutinemethod:: read()
.. comethod:: read()

Read request body, returns :class:`bytes` object with body content.

Expand All @@ -357,7 +357,7 @@ and :ref:`aiohttp-web-signals` handlers.
The method **does** store read data internally, subsequent
:meth:`~Request.read` call will return the same value.

.. coroutinemethod:: text()
.. comethod:: text()

Read request body, decode it using :attr:`charset` encoding or
``UTF-8`` if no encoding was specified in *MIME-type*.
Expand All @@ -369,7 +369,7 @@ and :ref:`aiohttp-web-signals` handlers.
The method **does** store read data internally, subsequent
:meth:`~Request.text` call will return the same value.

.. coroutinemethod:: json(*, loads=json.loads)
.. comethod:: json(*, loads=json.loads)

Read request body decoded as *json*.

Expand All @@ -391,7 +391,7 @@ and :ref:`aiohttp-web-signals` handlers.
:meth:`~Request.json` call will return the same value.


.. coroutinemethod:: multipart(*, reader=aiohttp.multipart.MultipartReader)
.. comethod:: multipart(*, reader=aiohttp.multipart.MultipartReader)

Returns :class:`aiohttp.multipart.MultipartReader` which processes
incoming *multipart* request.
Expand All @@ -412,7 +412,7 @@ and :ref:`aiohttp-web-signals` handlers.

.. seealso:: :ref:`aiohttp-multipart`

.. coroutinemethod:: post()
.. comethod:: post()

A :ref:`coroutine <coroutine>` that reads POST parameters from
request body.
Expand All @@ -430,7 +430,7 @@ and :ref:`aiohttp-web-signals` handlers.
The method **does** store read data internally, subsequent
:meth:`~Request.post` call will return the same value.

.. coroutinemethod:: release()
.. comethod:: release()

Release request.

Expand Down Expand Up @@ -610,7 +610,7 @@ StreamResponse
.. method:: enable_chunked_encoding

Enables :attr:`chunked` encoding for response. There are no ways to
disable it back. With enabled :attr:`chunked` encoding each `write()`
disable it back. With enabled :attr:`chunked` encoding each :meth:`write`
operation encoded in separate chunk.

.. warning:: chunked encoding can be enabled for ``HTTP/1.1`` only.
Expand Down Expand Up @@ -760,7 +760,7 @@ StreamResponse

Clear :attr:`tcp_cork` if *value* is ``True``.

.. coroutinemethod:: prepare(request)
.. comethod:: prepare(request)

:param aiohttp.web.Request request: HTTP request object, that the
response answers.
Expand All @@ -773,11 +773,13 @@ StreamResponse

.. versionadded:: 0.18

.. method:: write(data)
.. comethod:: write(data)

Send byte-ish data as the part of *response BODY*.
Send byte-ish data as the part of *response BODY*::

:meth:`prepare` must be called before.
await resp.write(data)

:meth:`prepare` must be invoked before the call.

Raises :exc:`TypeError` if data is not :class:`bytes`,
:class:`bytearray` or :class:`memoryview` instance.
Expand All @@ -786,23 +788,7 @@ StreamResponse

Raises :exc:`RuntimeError` if :meth:`write_eof` has been called.

.. coroutinemethod:: drain()

A :ref:`coroutine<coroutine>` to let the write buffer of the
underlying transport a chance to be flushed.

The intended use is to write::

resp.write(data)
await resp.drain()

Yielding from :meth:`drain` gives the opportunity for the loop
to schedule the write operation and flush the buffer. It should
especially be used when a possibly large amount of data is
written to the transport, and the coroutine does not yield-from
between calls to :meth:`write`.

.. coroutinemethod:: write_eof()
.. comethod:: write_eof()

A :ref:`coroutine<coroutine>` *may* be called as a mark of the
*HTTP response* processing finish.
Expand Down Expand Up @@ -923,7 +909,7 @@ WebSocketResponse
print(msg.data)


.. coroutinemethod:: prepare(request)
.. comethod:: prepare(request)

Starts websocket. After the call you can use websocket methods.

Expand Down Expand Up @@ -1403,23 +1389,23 @@ duplicated like one using :meth:`Application.copy`.
await loop.create_server(app.make_handler(),
'0.0.0.0', 8080)

.. coroutinemethod:: startup()
.. comethod:: startup()

A :ref:`coroutine<coroutine>` that will be called along with the
application's request handler.

The purpose of the method is calling :attr:`on_startup` signal
handlers.

.. coroutinemethod:: shutdown()
.. comethod:: shutdown()

A :ref:`coroutine<coroutine>` that should be called on
server stopping but before :meth:`cleanup()`.

The purpose of the method is calling :attr:`on_shutdown` signal
handlers.

.. coroutinemethod:: cleanup()
.. comethod:: cleanup()

A :ref:`coroutine<coroutine>` that should be called on
server stopping but after :meth:`shutdown`.
Expand Down Expand Up @@ -1465,7 +1451,7 @@ A protocol factory compatible with

.. versionadded:: 1.0

.. coroutinemethod:: Server.shutdown(timeout)
.. comethod:: Server.shutdown(timeout)

A :ref:`coroutine<coroutine>` that should be called to close all opened
connections.
Expand Down Expand Up @@ -1707,7 +1693,7 @@ Router is any object that implements :class:`AbstractRouter` interface.

.. versionadded:: 1.1

.. coroutinemethod:: resolve(request)
.. comethod:: resolve(request)

A :ref:`coroutine<coroutine>` that returns
:class:`AbstractMatchInfo` for *request*.
Expand Down Expand Up @@ -1860,7 +1846,7 @@ Resource classes hierarchy::

Read-only *name* of resource or ``None``.

.. coroutinemethod:: resolve(method, path)
.. comethod:: resolve(method, path)

Resolve resource by finding appropriate :term:`web-handler` for
``(method, path)`` combination.
Expand Down Expand Up @@ -2057,7 +2043,7 @@ and *405 Method Not Allowed*.

Actually it's a shortcut for ``route.resource.url_for(...)``.

.. coroutinemethod:: handle_expect_header(request)
.. comethod:: handle_expect_header(request)

``100-continue`` handler.

Expand Down
12 changes: 4 additions & 8 deletions tests/test_client_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,7 @@ async def handler(request):
# make sure connection is closed by client.
with pytest.raises(aiohttp.ServerDisconnectedError):
for _ in range(10):
resp_.write(b'data\n')
await resp_.drain()
await resp_.write(b'data\n')
await asyncio.sleep(0.5, loop=loop)
return resp_

Expand Down Expand Up @@ -665,8 +664,7 @@ async def test_no_error_on_conn_close_if_eof(loop, test_client):
async def handler(request):
resp_ = web.StreamResponse()
await resp_.prepare(request)
resp_.write(b'data\n')
await resp_.drain()
await resp_.write(b'data\n')
await asyncio.sleep(0.5, loop=loop)
return resp_

Expand Down Expand Up @@ -1782,7 +1780,7 @@ async def handler(request):
resp._length_check = False
resp.headers['Transfer-Encoding'] = 'chunked'
writer = await resp.prepare(request)
writer.write(b'9\r\n\r\n')
await writer.write(b'9\r\n\r\n')
await writer.write_eof()
return resp

Expand Down Expand Up @@ -1972,9 +1970,7 @@ async def test_broken_connection_2(loop, test_client):
async def handler(request):
resp = web.StreamResponse(headers={'content-length': '1000'})
await resp.prepare(request)
await resp.drain()
resp.write(b'answer')
await resp.drain()
await resp.write(b'answer')
request.transport.close()
return resp

Expand Down
6 changes: 3 additions & 3 deletions tests/test_client_functional_oldstyle.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def handler(request):

for hdr, val in request.message.headers.items():
if (hdr.upper() == 'EXPECT') and (val == '100-continue'):
request.writer.write(b'HTTP/1.0 100 Continue\r\n\r\n')
await request.writer.write(b'HTTP/1.0 100 Continue\r\n\r\n')
break

rob = router(properties, request)
Expand Down Expand Up @@ -274,7 +274,7 @@ async def _response(self, response, body=None,
except Exception:
return
else:
response.write(body.encode('utf8'))
await response.write(body.encode('utf8'))

return response

Expand Down Expand Up @@ -462,7 +462,7 @@ def test_POST_STREAM_DATA(self):
@aiohttp.streamer
async def stream(writer):
await fut
writer.write(data)
await writer.write(data)

self.loop.call_later(0.01, fut.set_result, True)

Expand Down
8 changes: 4 additions & 4 deletions tests/test_web_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,9 +935,9 @@ async def handler(request):
resp = web.StreamResponse()
resp.enable_chunked_encoding()
await resp.prepare(request)
resp.write(b'x')
resp.write(b'y')
resp.write(b'z')
await resp.write(b'x')
await resp.write(b'y')
await resp.write(b'z')
return resp

app = web.Application()
Expand Down Expand Up @@ -1464,7 +1464,7 @@ async def handler(request):
await resp.prepare(request)
await resp.drain()
await asyncio.sleep(0.01, loop=loop)
resp.write(b'test')
await resp.write(b'test')
await asyncio.sleep(0.01, loop=loop)
await resp.write_eof()
return resp
Expand Down
2 changes: 1 addition & 1 deletion tests/test_web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ async def handle2(request):
nonlocal processed
resp = web.StreamResponse()
await resp.prepare(request)
resp.write(b'test2')
await resp.write(b'test2')
await resp.write_eof()
processed.append(2)
return resp
Expand Down

0 comments on commit 53edaa6

Please sign in to comment.