From 1049c865a08ba549cd193185a8aebcd20232ff8b Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Fri, 3 Nov 2017 13:32:54 +0200 Subject: [PATCH] Multipart doc (#2459) * Convert a part of multipart's doc * Fix #2395: get rid of autodoc in multipart. * Fix typo --- aiohttp/multipart.py | 112 +++++++----------------- docs/api.rst | 9 -- docs/multipart_reference.rst | 162 ++++++++++++++++++++++++++++++++++- 3 files changed, 192 insertions(+), 91 deletions(-) diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py index 3cacf46e356..e28932313aa 100644 --- a/aiohttp/multipart.py +++ b/aiohttp/multipart.py @@ -162,8 +162,11 @@ def content_disposition_filename(params, name='filename'): class MultipartResponseWrapper(object): - """Wrapper around the :class:`MultipartBodyReader` to take care about - underlying connection and close it when it needs in.""" + """Wrapper around the MultipartBodyReader. + + It takes care about + underlying connection and close it when it needs in. + """ def __init__(self, resp, stream): self.resp = resp @@ -180,10 +183,7 @@ def __anext__(self): return part def at_eof(self): - """Returns ``True`` when all response data had been read. - - :rtype: bool - """ + """Returns True when all response data had been read.""" return self.resp.content.at_eof() async def next(self): @@ -238,11 +238,9 @@ def next(self): def read(self, *, decode=False): """Reads body part data. - :param bool decode: Decodes data following by encoding - method from `Content-Encoding` header. If it missed - data remains untouched - - :rtype: bytearray + decode: Decodes data following by encoding + method from Content-Encoding header. If it missed + data remains untouched """ if self._at_eof: return b'' @@ -257,9 +255,7 @@ def read(self, *, decode=False): def read_chunk(self, size=chunk_size): """Reads body part content chunk of the specified size. - :param int size: chunk size - - :rtype: bytearray + size: chunk size """ if self._at_eof: return b'' @@ -278,13 +274,8 @@ def read_chunk(self, size=chunk_size): return chunk async def _read_chunk_from_length(self, size): - """Reads body part content chunk of the specified size. - The body part must has `Content-Length` header with proper value. - - :param int size: chunk size - - :rtype: bytearray - """ + # Reads body part content chunk of the specified size. + # The body part must has Content-Length header with proper value. assert self._length is not None, \ 'Content-Length required for chunked read' chunk_size = min(size, self._length - self._read_bytes) @@ -292,13 +283,8 @@ async def _read_chunk_from_length(self, size): return chunk async def _read_chunk_from_stream(self, size): - """Reads content chunk of body part with unknown length. - The `Content-Length` header for body part is not necessary. - - :param int size: chunk size - - :rtype: bytearray - """ + # Reads content chunk of body part with unknown length. + # The Content-Length header for body part is not necessary. assert size >= len(self._boundary) + 2, \ 'Chunk size must be greater or equal than boundary length + 2' first_chunk = self._prev_chunk is None @@ -328,10 +314,7 @@ async def _read_chunk_from_stream(self, size): @asyncio.coroutine def readline(self): - """Reads body part by line by line. - - :rtype: bytearray - """ + """Reads body part by line by line.""" if self._at_eof: return b'' @@ -361,10 +344,7 @@ def readline(self): @asyncio.coroutine def release(self): - """Like :meth:`read`, but reads all the data to the void. - - :rtype: None - """ + """Like read(), but reads all the data to the void.""" if self._at_eof: return while not self._at_eof: @@ -372,13 +352,7 @@ def release(self): @asyncio.coroutine def text(self, *, encoding=None): - """Like :meth:`read`, but assumes that body part contains text data. - - :param str encoding: Custom text encoding. Overrides specified - in charset param of `Content-Type` header - - :rtype: str - """ + """Like read(), but assumes that body part contains text data.""" data = yield from self.read(decode=True) # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm # NOQA # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send # NOQA @@ -387,11 +361,7 @@ def text(self, *, encoding=None): @asyncio.coroutine def json(self, *, encoding=None): - """Like :meth:`read`, but assumes that body parts contains JSON data. - - :param str encoding: Custom JSON encoding. Overrides specified - in charset param of `Content-Type` header - """ + """Like read(), but assumes that body parts contains JSON data.""" data = yield from self.read(decode=True) if not data: return None @@ -400,11 +370,8 @@ def json(self, *, encoding=None): @asyncio.coroutine def form(self, *, encoding=None): - """Like :meth:`read`, but assumes that body parts contains form + """Like read(), but assumes that body parts contains form urlencoded data. - - :param str encoding: Custom form encoding. Overrides specified - in charset param of `Content-Type` header """ data = yield from self.read(decode=True) if not data: @@ -415,28 +382,12 @@ def form(self, *, encoding=None): encoding=encoding) def at_eof(self): - """Returns ``True`` if the boundary was reached or - ``False`` otherwise. - - :rtype: bool - """ + """Returns True if the boundary was reached or False otherwise.""" return self._at_eof def decode(self, data): - """Decodes data according the specified `Content-Encoding` - or `Content-Transfer-Encoding` headers value. - - Supports ``gzip``, ``deflate`` and ``identity`` encodings for - `Content-Encoding` header. - - Supports ``base64``, ``quoted-printable``, ``binary`` encodings for - `Content-Transfer-Encoding` header. - - :param bytearray data: Data to decode. - - :raises: :exc:`RuntimeError` - if encoding is unknown. - - :rtype: bytes + """Decodes data according the specified Content-Encoding + or Content-Transfer-Encoding headers value. """ if CONTENT_TRANSFER_ENCODING in self.headers: data = self._decode_content_transfer(data) @@ -470,24 +421,25 @@ def _decode_content_transfer(self, data): ''.format(encoding)) def get_charset(self, default=None): - """Returns charset parameter from ``Content-Type`` header or default. - """ + """Returns charset parameter from Content-Type header or default.""" ctype = self.headers.get(CONTENT_TYPE, '') mimetype = parse_mimetype(ctype) return mimetype.parameters.get('charset', default) @reify def name(self): - """Returns filename specified in Content-Disposition header or ``None`` - if missed or header is malformed.""" + """Returns name specified in Content-Disposition header or None + if missed or header is malformed. + """ _, params = parse_content_disposition( self.headers.get(CONTENT_DISPOSITION)) return content_disposition_filename(params, 'name') @reify def filename(self): - """Returns filename specified in Content-Disposition header or ``None`` - if missed or header is malformed.""" + """Returns filename specified in Content-Disposition header or None + if missed or header is malformed. + """ _, params = parse_content_disposition( self.headers.get(CONTENT_DISPOSITION)) return content_disposition_filename(params, 'filename') @@ -557,10 +509,8 @@ def from_response(cls, response): return obj def at_eof(self): - """Returns ``True`` if the final boundary was reached or - ``False`` otherwise. - - :rtype: bool + """Returns True if the final boundary was reached or + False otherwise. """ return self._at_eof diff --git a/docs/api.rst b/docs/api.rst index fe0a53ea13e..3168631fbbc 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -210,12 +210,3 @@ For concrete usage examples see :ref:`signals in aiohttp.web .. method:: freeze() Freeze the list. After the call any content modification is forbidden. - - -aiohttp.multipart module ------------------------- - -.. automodule:: aiohttp.multipart - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/multipart_reference.rst b/docs/multipart_reference.rst index 201e0129202..18d99b57bed 100644 --- a/docs/multipart_reference.rst +++ b/docs/multipart_reference.rst @@ -3,7 +3,7 @@ Multipart reference =================== -.. class:: MultipartResponseWrapper +.. class:: MultipartResponseWrapper(resp, stream) Wrapper around the :class:`MultipartBodyReader` to take care about underlying connection and close it when it needs in. @@ -24,3 +24,163 @@ Multipart reference Releases the connection gracefully, reading all the content to the void. + +.. class:: BodyPartReader(boundary, headers, content) + + Multipart reader for single body part. + + .. comethod:: read(*, decode=False) + + Reads body part data. + + :param bool decode: Decodes data following by encoding method + from ``Content-Encoding`` header. If it + missed data remains untouched + + :rtype: bytearray + + .. comethod:: read_chunk(size=chunk_size) + + Reads body part content chunk of the specified size. + + :param int size: chunk size + + :rtype: bytearray + + .. comethod:: readline() + + Reads body part by line by line. + + :rtype: bytearray + + .. comethod:: release() + + Like :meth:`read`, but reads all the data to the void. + + :rtype: None + + .. comethod:: text(*, encoding=None) + + Like :meth:`read`, but assumes that body part contains text data. + + :param str encoding: Custom text encoding. Overrides specified + in charset param of ``Content-Type`` header + + :rtype: str + + .. comethod:: json(*, encoding=None) + + Like :meth:`read`, but assumes that body parts contains JSON data. + + :param str encoding: Custom JSON encoding. Overrides specified + in charset param of ``Content-Type`` header + + .. comethod:: form(*, encoding=None) + + Like :meth:`read`, but assumes that body parts contains form + urlencoded data. + + :param str encoding: Custom form encoding. Overrides specified + in charset param of ``Content-Type`` header + + .. method:: at_eof() + + Returns ``True`` if the boundary was reached or ``False`` otherwise. + + :rtype: bool + + .. method:: decode(data) + + Decodes data according the specified ``Content-Encoding`` + or ``Content-Transfer-Encoding`` headers value. + + Supports ``gzip``, ``deflate`` and ``identity`` encodings for + ``Content-Encoding`` header. + + Supports ``base64``, ``quoted-printable``, ``binary`` encodings for + ``Content-Transfer-Encoding`` header. + + :param bytearray data: Data to decode. + + :raises: :exc:`RuntimeError` - if encoding is unknown. + + :rtype: bytes + + .. method:: get_charset(default=None) + + Returns charset parameter from ``Content-Type`` header or default. + + .. attribute:: name + + A field *name* specified in ``Content-Disposition`` header or ``None`` + if missed or header is malformed. + + Readonly :class:`str` property. + + .. attribute:: name + + A field *filename* specified in ``Content-Disposition`` header or ``None`` + if missed or header is malformed. + + Readonly :class:`str` property. + + +.. class:: MultipartReader(headers, content) + + Multipart body reader. + + .. classmethod:: from_response(cls, response) + + Constructs reader instance from HTTP response. + + :param response: :class:`~aiohttp.client.ClientResponse` instance + + .. method:: at_eof() + + Returns ``True`` if the final boundary was reached or + ``False`` otherwise. + + :rtype: bool + + .. comethod:: next() + + Emits the next multipart body part. + + .. comethod:: release() + + Reads all the body parts to the void till the final boundary. + + .. comethod:: fetch_next_part() + + Returns the next body part reader. + + +.. class:: MultipartWriter(subtype='mixed', boundary=None) + + Multipart body writer. + + .. attribute:: boundary + + .. method:: append(obj, headers=None) + + Append an object to writer. + + .. method:: append_payload(payload) + + Adds a new body part to multipart writer. + + .. method:: append_json(obj, headers=None) + + Helper to append JSON part. + + .. method:: append_form(obj, headers=None) + + Helper to append form urlencoded part. + + .. attribute:: size + + Size of the payload. + + .. comethod:: write(writer) + + Write body.