{
    "file_diffs": [
        {
            "old_file_content": "",
            "new_file_content": "Fixed decoding base64 chunk in BodyPartReader -- by :user:`hyzyla`.\n",
            "header": {
                "file": {
                    "path": "CHANGES/3867.bugfix.rst"
                },
                "misc_line": "new file mode 100644"
            },
            "index_line": {
                "old_commit_hash": "00000000",
                "new_commit_hash": "12376bf6",
                "mode": ""
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "/dev/null"
            },
            "plus_file": {
                "path": "b/CHANGES/3867.bugfix.rst"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 0,
                            "length": 0
                        },
                        "new_range": {
                            "start": 1,
                            "length": null
                        },
                        "section": ""
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "Fixed decoding base64 chunk in BodyPartReader -- by :user:`hyzyla`.",
                                "type": "added"
                            }
                        ]
                    },
                    "modified_entities": [],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import base64\nimport binascii\nimport json\nimport re\nimport uuid\nimport warnings\nimport zlib\nfrom collections import deque\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    AsyncIterator,\n    Deque,\n    Dict,\n    Iterator,\n    List,\n    Mapping,\n    Optional,\n    Sequence,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\nfrom urllib.parse import parse_qsl, unquote, urlencode\n\nfrom multidict import CIMultiDict, CIMultiDictProxy\n\nfrom .compression_utils import ZLibCompressor, ZLibDecompressor\nfrom .hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_LENGTH,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom .helpers import CHAR, TOKEN, parse_mimetype, reify\nfrom .http import HeadersParser\nfrom .payload import (\n    JsonPayload,\n    LookupError,\n    Order,\n    Payload,\n    StringPayload,\n    get_payload,\n    payload_type,\n)\nfrom .streams import StreamReader\n\n__all__ = (\n    \"MultipartReader\",\n    \"MultipartWriter\",\n    \"BodyPartReader\",\n    \"BadContentDispositionHeader\",\n    \"BadContentDispositionParam\",\n    \"parse_content_disposition\",\n    \"content_disposition_filename\",\n)\n\n\nif TYPE_CHECKING:\n    from .client_reqrep import ClientResponse\n\n\nclass BadContentDispositionHeader(RuntimeWarning):\n    pass\n\n\nclass BadContentDispositionParam(RuntimeWarning):\n    pass\n\n\ndef parse_content_disposition(\n    header: Optional[str],\n) -> Tuple[Optional[str], Dict[str, str]]:\n    def is_token(string: str) -> bool:\n        return bool(string) and TOKEN >= set(string)\n\n    def is_quoted(string: str) -> bool:\n        return string[0] == string[-1] == '\"'\n\n    def is_rfc5987(string: str) -> bool:\n        return is_token(string) and string.count(\"'\") == 2\n\n    def is_extended_param(string: str) -> bool:\n        return string.endswith(\"*\")\n\n    def is_continuous_param(string: str) -> bool:\n        pos = string.find(\"*\") + 1\n        if not pos:\n            return False\n        substring = string[pos:-1] if string.endswith(\"*\") else string[pos:]\n        return substring.isdigit()\n\n    def unescape(text: str, *, chars: str = \"\".join(map(re.escape, CHAR))) -> str:\n        return re.sub(f\"\\\\\\\\([{chars}])\", \"\\\\1\", text)\n\n    if not header:\n        return None, {}\n\n    disptype, *parts = header.split(\";\")\n    if not is_token(disptype):\n        warnings.warn(BadContentDispositionHeader(header))\n        return None, {}\n\n    params: Dict[str, str] = {}\n    while parts:\n        item = parts.pop(0)\n\n        if \"=\" not in item:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        key, value = item.split(\"=\", 1)\n        key = key.lower().strip()\n        value = value.lstrip()\n\n        if key in params:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        if not is_token(key):\n            warnings.warn(BadContentDispositionParam(item))\n            continue\n\n        elif is_continuous_param(key):\n            if is_quoted(value):\n                value = unescape(value[1:-1])\n            elif not is_token(value):\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        elif is_extended_param(key):\n            if is_rfc5987(value):\n                encoding, _, value = value.split(\"'\", 2)\n                encoding = encoding or \"utf-8\"\n            else:\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n            try:\n                value = unquote(value, encoding, \"strict\")\n            except UnicodeDecodeError:  # pragma: nocover\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        else:\n            failed = True\n            if is_quoted(value):\n                failed = False\n                value = unescape(value[1:-1].lstrip(\"\\\\/\"))\n            elif is_token(value):\n                failed = False\n            elif parts:\n                # maybe just ; in filename, in any case this is just\n                # one case fix, for proper fix we need to redesign parser\n                _value = f\"{value};{parts[0]}\"\n                if is_quoted(_value):\n                    parts.pop(0)\n                    value = unescape(_value[1:-1].lstrip(\"\\\\/\"))\n                    failed = False\n\n            if failed:\n                warnings.warn(BadContentDispositionHeader(header))\n                return None, {}\n\n        params[key] = value\n\n    return disptype.lower(), params\n\n\ndef content_disposition_filename(\n    params: Mapping[str, str], name: str = \"filename\"\n) -> Optional[str]:\n    name_suf = \"%s*\" % name\n    if not params:\n        return None\n    elif name_suf in params:\n        return params[name_suf]\n    elif name in params:\n        return params[name]\n    else:\n        parts = []\n        fnparams = sorted(\n            (key, value) for key, value in params.items() if key.startswith(name_suf)\n        )\n        for num, (key, value) in enumerate(fnparams):\n            _, tail = key.split(\"*\", 1)\n            if tail.endswith(\"*\"):\n                tail = tail[:-1]\n            if tail == str(num):\n                parts.append(value)\n            else:\n                break\n        if not parts:\n            return None\n        value = \"\".join(parts)\n        if \"'\" in value:\n            encoding, _, value = value.split(\"'\", 2)\n            encoding = encoding or \"utf-8\"\n            return unquote(value, encoding, \"strict\")\n        return value\n\n\nclass MultipartResponseWrapper:\n    \"\"\"Wrapper around the MultipartReader.\n\n    It takes care about\n    underlying connection and close it when it needs in.\n    \"\"\"\n\n    def __init__(\n        self,\n        resp: \"ClientResponse\",\n        stream: \"MultipartReader\",\n    ) -> None:\n        self.resp = resp\n        self.stream = stream\n\n    def __aiter__(self) -> \"MultipartResponseWrapper\":\n        return self\n\n    async def __anext__(\n        self,\n    ) -> Union[\"MultipartReader\", \"BodyPartReader\"]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True when all response data had been read.\"\"\"\n        return self.resp.content.at_eof()\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", \"BodyPartReader\"]]:\n        \"\"\"Emits next multipart reader object.\"\"\"\n        item = await self.stream.next()\n        if self.stream.at_eof():\n            await self.release()\n        return item\n\n    async def release(self) -> None:\n        \"\"\"Release the connection gracefully.\n\n        All remaining content is read to the void.\n        \"\"\"\n        await self.resp.release()\n\n\nclass BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")\n\n\n@payload_type(BodyPartReader, order=Order.try_first)\nclass BodyPartReaderPayload(Payload):\n    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:\n        super().__init__(value, *args, **kwargs)\n\n        params: Dict[str, str] = {}\n        if value.name is not None:\n            params[\"name\"] = value.name\n        if value.filename is not None:\n            params[\"filename\"] = value.filename\n\n        if params:\n            self.set_content_disposition(\"attachment\", True, **params)\n\n    async def write(self, writer: Any) -> None:\n        field = self._value\n        chunk = await field.read_chunk(size=2**16)\n        while chunk:\n            await writer.write(field.decode(chunk))\n            chunk = await field.read_chunk(size=2**16)\n\n\nclass MultipartReader:\n    \"\"\"Multipart body reader.\"\"\"\n\n    #: Response wrapper, used when multipart readers constructs from response.\n    response_wrapper_cls = MultipartResponseWrapper\n    #: Multipart reader class, used to handle multipart/* body parts.\n    #: None points to type(self)\n    multipart_reader_cls = None\n    #: Body part reader class for non multipart/* content types.\n    part_reader_cls = BodyPartReader\n\n    def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None:\n        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])\n        assert self._mimetype.type == \"multipart\", \"multipart/* content type expected\"\n        if \"boundary\" not in self._mimetype.parameters:\n            raise ValueError(\n                \"boundary missed for Content-Type: %s\" % headers[CONTENT_TYPE]\n            )\n\n        self.headers = headers\n        self._boundary = (\"--\" + self._get_boundary()).encode()\n        self._content = content\n        self._default_charset: Optional[str] = None\n        self._last_part: Optional[Union[\"MultipartReader\", BodyPartReader]] = None\n        self._at_eof = False\n        self._at_bof = True\n        self._unread: List[bytes] = []\n\n    def __aiter__(\n        self,\n    ) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    @classmethod\n    def from_response(\n        cls,\n        response: \"ClientResponse\",\n    ) -> MultipartResponseWrapper:\n        \"\"\"Constructs reader instance from HTTP response.\n\n        :param response: :class:`~aiohttp.client.ClientResponse` instance\n        \"\"\"\n        obj = cls.response_wrapper_cls(\n            response, cls(response.headers, response.content)\n        )\n        return obj\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the final boundary was reached, false otherwise.\"\"\"\n        return self._at_eof\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        \"\"\"Emits the next multipart body part.\"\"\"\n        # So, if we're at BOF, we need to skip till the boundary.\n        if self._at_eof:\n            return None\n        await self._maybe_release_last_part()\n        if self._at_bof:\n            await self._read_until_first_boundary()\n            self._at_bof = False\n        else:\n            await self._read_boundary()\n        if self._at_eof:  # we just read the last boundary, nothing to do there\n            return None\n\n        part = await self.fetch_next_part()\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6\n        if (\n            self._last_part is None\n            and self._mimetype.subtype == \"form-data\"\n            and isinstance(part, BodyPartReader)\n        ):\n            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))\n            if params.get(\"name\") == \"_charset_\":\n                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json\n                # is 19 characters, so 32 should be more than enough for any valid encoding.\n                charset = await part.read_chunk(32)\n                if len(charset) > 31:\n                    raise RuntimeError(\"Invalid default charset\")\n                self._default_charset = charset.strip().decode()\n                part = await self.fetch_next_part()\n        self._last_part = part\n        return self._last_part\n\n    async def release(self) -> None:\n        \"\"\"Reads all the body parts to the void till the final boundary.\"\"\"\n        while not self._at_eof:\n            item = await self.next()\n            if item is None:\n                break\n            await item.release()\n\n    async def fetch_next_part(\n        self,\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Returns the next body part reader.\"\"\"\n        headers = await self._read_headers()\n        return self._get_part_reader(headers)\n\n    def _get_part_reader(\n        self,\n        headers: \"CIMultiDictProxy[str]\",\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Dispatches the response by the `Content-Type` header.\n\n        Returns a suitable reader instance.\n\n        :param dict headers: Response headers\n        \"\"\"\n        ctype = headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n\n        if mimetype.type == \"multipart\":\n            if self.multipart_reader_cls is None:\n                return type(self)(headers, self._content)\n            return self.multipart_reader_cls(headers, self._content)\n        else:\n            return self.part_reader_cls(\n                self._boundary,\n                headers,\n                self._content,\n                subtype=self._mimetype.subtype,\n                default_charset=self._default_charset,\n            )\n\n    def _get_boundary(self) -> str:\n        boundary = self._mimetype.parameters[\"boundary\"]\n        if len(boundary) > 70:\n            raise ValueError(\"boundary %r is too long (70 chars max)\" % boundary)\n\n        return boundary\n\n    async def _readline(self) -> bytes:\n        if self._unread:\n            return self._unread.pop()\n        return await self._content.readline()\n\n    async def _read_until_first_boundary(self) -> None:\n        while True:\n            chunk = await self._readline()\n            if chunk == b\"\":\n                raise ValueError(\n                    \"Could not find starting boundary %r\" % (self._boundary)\n                )\n            chunk = chunk.rstrip()\n            if chunk == self._boundary:\n                return\n            elif chunk == self._boundary + b\"--\":\n                self._at_eof = True\n                return\n\n    async def _read_boundary(self) -> None:\n        chunk = (await self._readline()).rstrip()\n        if chunk == self._boundary:\n            pass\n        elif chunk == self._boundary + b\"--\":\n            self._at_eof = True\n            epilogue = await self._readline()\n            next_line = await self._readline()\n\n            # the epilogue is expected and then either the end of input or the\n            # parent multipart boundary, if the parent boundary is found then\n            # it should be marked as unread and handed to the parent for\n            # processing\n            if next_line[:2] == b\"--\":\n                self._unread.append(next_line)\n            # otherwise the request is likely missing an epilogue and both\n            # lines should be passed to the parent for processing\n            # (this handles the old behavior gracefully)\n            else:\n                self._unread.extend([next_line, epilogue])\n        else:\n            raise ValueError(f\"Invalid boundary {chunk!r}, expected {self._boundary!r}\")\n\n    async def _read_headers(self) -> \"CIMultiDictProxy[str]\":\n        lines = [b\"\"]\n        while True:\n            chunk = await self._content.readline()\n            chunk = chunk.strip()\n            lines.append(chunk)\n            if not chunk:\n                break\n        parser = HeadersParser()\n        headers, raw_headers = parser.parse_headers(lines)\n        return headers\n\n    async def _maybe_release_last_part(self) -> None:\n        \"\"\"Ensures that the last read body part is read completely.\"\"\"\n        if self._last_part is not None:\n            if not self._last_part.at_eof():\n                await self._last_part.release()\n            self._unread.extend(self._last_part._unread)\n            self._last_part = None\n\n\n_Part = Tuple[Payload, str, str]\n\n\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"\n\n    def __init__(self, subtype: str = \"mixed\", boundary: Optional[str] = None) -> None:\n        boundary = boundary if boundary is not None else uuid.uuid4().hex\n        # The underlying Payload API demands a str (utf-8), not bytes,\n        # so we need to ensure we don't lose anything during conversion.\n        # As a result, require the boundary to be ASCII only.\n        # In both situations.\n\n        try:\n            self._boundary = boundary.encode(\"ascii\")\n        except UnicodeEncodeError:\n            raise ValueError(\"boundary should contain ASCII only chars\") from None\n        ctype = f\"multipart/{subtype}; boundary={self._boundary_value}\"\n\n        super().__init__(None, content_type=ctype)\n\n        self._parts: List[_Part] = []\n        self._is_form_data = subtype == \"form-data\"\n\n    def __enter__(self) -> \"MultipartWriter\":\n        return self\n\n    def __exit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        pass\n\n    def __iter__(self) -> Iterator[_Part]:\n        return iter(self._parts)\n\n    def __len__(self) -> int:\n        return len(self._parts)\n\n    def __bool__(self) -> bool:\n        return True\n\n    _valid_tchar_regex = re.compile(rb\"\\A[!#$%&'*+\\-.^_`|~\\w]+\\Z\")\n    _invalid_qdtext_char_regex = re.compile(rb\"[\\x00-\\x08\\x0A-\\x1F\\x7F]\")\n\n    @property\n    def _boundary_value(self) -> str:\n        \"\"\"Wrap boundary parameter value in quotes, if necessary.\n\n        Reads self.boundary and returns a unicode string.\n        \"\"\"\n        # Refer to RFCs 7231, 7230, 5234.\n        #\n        # parameter      = token \"=\" ( token / quoted-string )\n        # token          = 1*tchar\n        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE\n        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text\n        # obs-text       = %x80-FF\n        # quoted-pair    = \"\\\" ( HTAB / SP / VCHAR / obs-text )\n        # tchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n        #                  / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n        #                  / DIGIT / ALPHA\n        #                  ; any VCHAR, except delimiters\n        # VCHAR           = %x21-7E\n        value = self._boundary\n        if re.match(self._valid_tchar_regex, value):\n            return value.decode(\"ascii\")  # cannot fail\n\n        if re.search(self._invalid_qdtext_char_regex, value):\n            raise ValueError(\"boundary value contains invalid characters\")\n\n        # escape %x5C and %x22\n        quoted_value_content = value.replace(b\"\\\\\", b\"\\\\\\\\\")\n        quoted_value_content = quoted_value_content.replace(b'\"', b'\\\\\"')\n\n        return '\"' + quoted_value_content.decode(\"ascii\") + '\"'\n\n    @property\n    def boundary(self) -> str:\n        return self._boundary.decode(\"ascii\")\n\n    def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload:\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Payload):\n            obj.headers.update(headers)\n            return self.append_payload(obj)\n        else:\n            try:\n                payload = get_payload(obj, headers=headers)\n            except LookupError:\n                raise TypeError(\"Cannot create payload from %r\" % obj)\n            else:\n                return self.append_payload(payload)\n\n    def append_payload(self, payload: Payload) -> Payload:\n        \"\"\"Adds a new body part to multipart writer.\"\"\"\n        encoding: Optional[str] = None\n        te_encoding: Optional[str] = None\n        if self._is_form_data:\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n            assert (\n                not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING}\n                & payload.headers.keys()\n            )\n            # Set default Content-Disposition in case user doesn't create one\n            if CONTENT_DISPOSITION not in payload.headers:\n                name = f\"section-{len(self._parts)}\"\n                payload.set_content_disposition(\"form-data\", name=name)\n        else:\n            # compression\n            encoding = payload.headers.get(CONTENT_ENCODING, \"\").lower()\n            if encoding and encoding not in (\"deflate\", \"gzip\", \"identity\"):\n                raise RuntimeError(f\"unknown content encoding: {encoding}\")\n            if encoding == \"identity\":\n                encoding = None\n\n            # te encoding\n            te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n            if te_encoding not in (\"\", \"base64\", \"quoted-printable\", \"binary\"):\n                raise RuntimeError(f\"unknown content transfer encoding: {te_encoding}\")\n            if te_encoding == \"binary\":\n                te_encoding = None\n\n            # size\n            size = payload.size\n            if size is not None and not (encoding or te_encoding):\n                payload.headers[CONTENT_LENGTH] = str(size)\n\n        self._parts.append((payload, encoding, te_encoding))  # type: ignore[arg-type]\n        return payload\n\n    def append_json(\n        self, obj: Any, headers: Optional[Mapping[str, str]] = None\n    ) -> Payload:\n        \"\"\"Helper to append JSON part.\"\"\"\n        if headers is None:\n            headers = CIMultiDict()\n\n        return self.append_payload(JsonPayload(obj, headers=headers))\n\n    def append_form(\n        self,\n        obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]],\n        headers: Optional[Mapping[str, str]] = None,\n    ) -> Payload:\n        \"\"\"Helper to append form urlencoded part.\"\"\"\n        assert isinstance(obj, (Sequence, Mapping))\n\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Mapping):\n            obj = list(obj.items())\n        data = urlencode(obj, doseq=True)\n\n        return self.append_payload(\n            StringPayload(\n                data, headers=headers, content_type=\"application/x-www-form-urlencoded\"\n            )\n        )\n\n    @property\n    def size(self) -> Optional[int]:\n        \"\"\"Size of the payload.\"\"\"\n        total = 0\n        for part, encoding, te_encoding in self._parts:\n            if encoding or te_encoding or part.size is None:\n                return None\n\n            total += int(\n                2\n                + len(self._boundary)\n                + 2\n                + part.size  # b'--'+self._boundary+b'\\r\\n'\n                + len(part._binary_headers)\n                + 2  # b'\\r\\n'\n            )\n\n        total += 2 + len(self._boundary) + 4  # b'--'+self._boundary+b'--\\r\\n'\n        return total\n\n    async def write(self, writer: Any, close_boundary: bool = True) -> None:\n        \"\"\"Write body.\"\"\"\n        for part, encoding, te_encoding in self._parts:\n            if self._is_form_data:\n                # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2\n                assert CONTENT_DISPOSITION in part.headers\n                assert \"name=\" in part.headers[CONTENT_DISPOSITION]\n\n            await writer.write(b\"--\" + self._boundary + b\"\\r\\n\")\n            await writer.write(part._binary_headers)\n\n            if encoding or te_encoding:\n                w = MultipartPayloadWriter(writer)\n                if encoding:\n                    w.enable_compression(encoding)\n                if te_encoding:\n                    w.enable_encoding(te_encoding)\n                await part.write(w)  # type: ignore[arg-type]\n                await w.write_eof()\n            else:\n                await part.write(writer)\n\n            await writer.write(b\"\\r\\n\")\n\n        if close_boundary:\n            await writer.write(b\"--\" + self._boundary + b\"--\\r\\n\")\n\n\nclass MultipartPayloadWriter:\n    def __init__(self, writer: Any) -> None:\n        self._writer = writer\n        self._encoding: Optional[str] = None\n        self._compress: Optional[ZLibCompressor] = None\n        self._encoding_buffer: Optional[bytearray] = None\n\n    def enable_encoding(self, encoding: str) -> None:\n        if encoding == \"base64\":\n            self._encoding = encoding\n            self._encoding_buffer = bytearray()\n        elif encoding == \"quoted-printable\":\n            self._encoding = \"quoted-printable\"\n\n    def enable_compression(\n        self, encoding: str = \"deflate\", strategy: int = zlib.Z_DEFAULT_STRATEGY\n    ) -> None:\n        self._compress = ZLibCompressor(\n            encoding=encoding,\n            suppress_deflate_header=True,\n            strategy=strategy,\n        )\n\n    async def write_eof(self) -> None:\n        if self._compress is not None:\n            chunk = self._compress.flush()\n            if chunk:\n                self._compress = None\n                await self.write(chunk)\n\n        if self._encoding == \"base64\":\n            if self._encoding_buffer:\n                await self._writer.write(base64.b64encode(self._encoding_buffer))\n\n    async def write(self, chunk: bytes) -> None:\n        if self._compress is not None:\n            if chunk:\n                chunk = await self._compress.compress(chunk)\n                if not chunk:\n                    return\n\n        if self._encoding == \"base64\":\n            buf = self._encoding_buffer\n            assert buf is not None\n            buf.extend(chunk)\n\n            if buf:\n                div, mod = divmod(len(buf), 3)\n                enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :])\n                if enc_chunk:\n                    b64chunk = base64.b64encode(enc_chunk)\n                    await self._writer.write(b64chunk)\n        elif self._encoding == \"quoted-printable\":\n            await self._writer.write(binascii.b2a_qp(chunk))\n        else:\n            await self._writer.write(chunk)\n",
            "new_file_content": "import base64\nimport binascii\nimport json\nimport re\nimport uuid\nimport warnings\nimport zlib\nfrom collections import deque\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    AsyncIterator,\n    Deque,\n    Dict,\n    Iterator,\n    List,\n    Mapping,\n    Optional,\n    Sequence,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\nfrom urllib.parse import parse_qsl, unquote, urlencode\n\nfrom multidict import CIMultiDict, CIMultiDictProxy\n\nfrom .compression_utils import ZLibCompressor, ZLibDecompressor\nfrom .hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_LENGTH,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom .helpers import CHAR, TOKEN, parse_mimetype, reify\nfrom .http import HeadersParser\nfrom .payload import (\n    JsonPayload,\n    LookupError,\n    Order,\n    Payload,\n    StringPayload,\n    get_payload,\n    payload_type,\n)\nfrom .streams import StreamReader\n\n__all__ = (\n    \"MultipartReader\",\n    \"MultipartWriter\",\n    \"BodyPartReader\",\n    \"BadContentDispositionHeader\",\n    \"BadContentDispositionParam\",\n    \"parse_content_disposition\",\n    \"content_disposition_filename\",\n)\n\n\nif TYPE_CHECKING:\n    from .client_reqrep import ClientResponse\n\n\nclass BadContentDispositionHeader(RuntimeWarning):\n    pass\n\n\nclass BadContentDispositionParam(RuntimeWarning):\n    pass\n\n\ndef parse_content_disposition(\n    header: Optional[str],\n) -> Tuple[Optional[str], Dict[str, str]]:\n    def is_token(string: str) -> bool:\n        return bool(string) and TOKEN >= set(string)\n\n    def is_quoted(string: str) -> bool:\n        return string[0] == string[-1] == '\"'\n\n    def is_rfc5987(string: str) -> bool:\n        return is_token(string) and string.count(\"'\") == 2\n\n    def is_extended_param(string: str) -> bool:\n        return string.endswith(\"*\")\n\n    def is_continuous_param(string: str) -> bool:\n        pos = string.find(\"*\") + 1\n        if not pos:\n            return False\n        substring = string[pos:-1] if string.endswith(\"*\") else string[pos:]\n        return substring.isdigit()\n\n    def unescape(text: str, *, chars: str = \"\".join(map(re.escape, CHAR))) -> str:\n        return re.sub(f\"\\\\\\\\([{chars}])\", \"\\\\1\", text)\n\n    if not header:\n        return None, {}\n\n    disptype, *parts = header.split(\";\")\n    if not is_token(disptype):\n        warnings.warn(BadContentDispositionHeader(header))\n        return None, {}\n\n    params: Dict[str, str] = {}\n    while parts:\n        item = parts.pop(0)\n\n        if \"=\" not in item:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        key, value = item.split(\"=\", 1)\n        key = key.lower().strip()\n        value = value.lstrip()\n\n        if key in params:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        if not is_token(key):\n            warnings.warn(BadContentDispositionParam(item))\n            continue\n\n        elif is_continuous_param(key):\n            if is_quoted(value):\n                value = unescape(value[1:-1])\n            elif not is_token(value):\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        elif is_extended_param(key):\n            if is_rfc5987(value):\n                encoding, _, value = value.split(\"'\", 2)\n                encoding = encoding or \"utf-8\"\n            else:\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n            try:\n                value = unquote(value, encoding, \"strict\")\n            except UnicodeDecodeError:  # pragma: nocover\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        else:\n            failed = True\n            if is_quoted(value):\n                failed = False\n                value = unescape(value[1:-1].lstrip(\"\\\\/\"))\n            elif is_token(value):\n                failed = False\n            elif parts:\n                # maybe just ; in filename, in any case this is just\n                # one case fix, for proper fix we need to redesign parser\n                _value = f\"{value};{parts[0]}\"\n                if is_quoted(_value):\n                    parts.pop(0)\n                    value = unescape(_value[1:-1].lstrip(\"\\\\/\"))\n                    failed = False\n\n            if failed:\n                warnings.warn(BadContentDispositionHeader(header))\n                return None, {}\n\n        params[key] = value\n\n    return disptype.lower(), params\n\n\ndef content_disposition_filename(\n    params: Mapping[str, str], name: str = \"filename\"\n) -> Optional[str]:\n    name_suf = \"%s*\" % name\n    if not params:\n        return None\n    elif name_suf in params:\n        return params[name_suf]\n    elif name in params:\n        return params[name]\n    else:\n        parts = []\n        fnparams = sorted(\n            (key, value) for key, value in params.items() if key.startswith(name_suf)\n        )\n        for num, (key, value) in enumerate(fnparams):\n            _, tail = key.split(\"*\", 1)\n            if tail.endswith(\"*\"):\n                tail = tail[:-1]\n            if tail == str(num):\n                parts.append(value)\n            else:\n                break\n        if not parts:\n            return None\n        value = \"\".join(parts)\n        if \"'\" in value:\n            encoding, _, value = value.split(\"'\", 2)\n            encoding = encoding or \"utf-8\"\n            return unquote(value, encoding, \"strict\")\n        return value\n\n\nclass MultipartResponseWrapper:\n    \"\"\"Wrapper around the MultipartReader.\n\n    It takes care about\n    underlying connection and close it when it needs in.\n    \"\"\"\n\n    def __init__(\n        self,\n        resp: \"ClientResponse\",\n        stream: \"MultipartReader\",\n    ) -> None:\n        self.resp = resp\n        self.stream = stream\n\n    def __aiter__(self) -> \"MultipartResponseWrapper\":\n        return self\n\n    async def __anext__(\n        self,\n    ) -> Union[\"MultipartReader\", \"BodyPartReader\"]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True when all response data had been read.\"\"\"\n        return self.resp.content.at_eof()\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", \"BodyPartReader\"]]:\n        \"\"\"Emits next multipart reader object.\"\"\"\n        item = await self.stream.next()\n        if self.stream.at_eof():\n            await self.release()\n        return item\n\n    async def release(self) -> None:\n        \"\"\"Release the connection gracefully.\n\n        All remaining content is read to the void.\n        \"\"\"\n        await self.resp.release()\n\n\nclass BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        # For the case of base64 data, we must read a fragment of size with a\n        # remainder of 0 by dividing by 4 for string without symbols \\n or \\r\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)\n        if encoding and encoding.lower() == \"base64\":\n            stripped_chunk = b\"\".join(chunk.split())\n            remainder = len(stripped_chunk) % 4\n\n            while remainder != 0 and not self.at_eof():\n                over_chunk_size = 4 - remainder\n                over_chunk = b\"\"\n\n                if self._prev_chunk:\n                    over_chunk = self._prev_chunk[:over_chunk_size]\n                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]\n\n                if len(over_chunk) != over_chunk_size:\n                    over_chunk += await self._content.read(4 - len(over_chunk))\n\n                if not over_chunk:\n                    self._at_eof = True\n\n                stripped_chunk += b\"\".join(over_chunk.split())\n                chunk += over_chunk\n                remainder = len(stripped_chunk) % 4\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")\n\n\n@payload_type(BodyPartReader, order=Order.try_first)\nclass BodyPartReaderPayload(Payload):\n    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:\n        super().__init__(value, *args, **kwargs)\n\n        params: Dict[str, str] = {}\n        if value.name is not None:\n            params[\"name\"] = value.name\n        if value.filename is not None:\n            params[\"filename\"] = value.filename\n\n        if params:\n            self.set_content_disposition(\"attachment\", True, **params)\n\n    async def write(self, writer: Any) -> None:\n        field = self._value\n        chunk = await field.read_chunk(size=2**16)\n        while chunk:\n            await writer.write(field.decode(chunk))\n            chunk = await field.read_chunk(size=2**16)\n\n\nclass MultipartReader:\n    \"\"\"Multipart body reader.\"\"\"\n\n    #: Response wrapper, used when multipart readers constructs from response.\n    response_wrapper_cls = MultipartResponseWrapper\n    #: Multipart reader class, used to handle multipart/* body parts.\n    #: None points to type(self)\n    multipart_reader_cls = None\n    #: Body part reader class for non multipart/* content types.\n    part_reader_cls = BodyPartReader\n\n    def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None:\n        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])\n        assert self._mimetype.type == \"multipart\", \"multipart/* content type expected\"\n        if \"boundary\" not in self._mimetype.parameters:\n            raise ValueError(\n                \"boundary missed for Content-Type: %s\" % headers[CONTENT_TYPE]\n            )\n\n        self.headers = headers\n        self._boundary = (\"--\" + self._get_boundary()).encode()\n        self._content = content\n        self._default_charset: Optional[str] = None\n        self._last_part: Optional[Union[\"MultipartReader\", BodyPartReader]] = None\n        self._at_eof = False\n        self._at_bof = True\n        self._unread: List[bytes] = []\n\n    def __aiter__(\n        self,\n    ) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    @classmethod\n    def from_response(\n        cls,\n        response: \"ClientResponse\",\n    ) -> MultipartResponseWrapper:\n        \"\"\"Constructs reader instance from HTTP response.\n\n        :param response: :class:`~aiohttp.client.ClientResponse` instance\n        \"\"\"\n        obj = cls.response_wrapper_cls(\n            response, cls(response.headers, response.content)\n        )\n        return obj\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the final boundary was reached, false otherwise.\"\"\"\n        return self._at_eof\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        \"\"\"Emits the next multipart body part.\"\"\"\n        # So, if we're at BOF, we need to skip till the boundary.\n        if self._at_eof:\n            return None\n        await self._maybe_release_last_part()\n        if self._at_bof:\n            await self._read_until_first_boundary()\n            self._at_bof = False\n        else:\n            await self._read_boundary()\n        if self._at_eof:  # we just read the last boundary, nothing to do there\n            return None\n\n        part = await self.fetch_next_part()\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6\n        if (\n            self._last_part is None\n            and self._mimetype.subtype == \"form-data\"\n            and isinstance(part, BodyPartReader)\n        ):\n            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))\n            if params.get(\"name\") == \"_charset_\":\n                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json\n                # is 19 characters, so 32 should be more than enough for any valid encoding.\n                charset = await part.read_chunk(32)\n                if len(charset) > 31:\n                    raise RuntimeError(\"Invalid default charset\")\n                self._default_charset = charset.strip().decode()\n                part = await self.fetch_next_part()\n        self._last_part = part\n        return self._last_part\n\n    async def release(self) -> None:\n        \"\"\"Reads all the body parts to the void till the final boundary.\"\"\"\n        while not self._at_eof:\n            item = await self.next()\n            if item is None:\n                break\n            await item.release()\n\n    async def fetch_next_part(\n        self,\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Returns the next body part reader.\"\"\"\n        headers = await self._read_headers()\n        return self._get_part_reader(headers)\n\n    def _get_part_reader(\n        self,\n        headers: \"CIMultiDictProxy[str]\",\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Dispatches the response by the `Content-Type` header.\n\n        Returns a suitable reader instance.\n\n        :param dict headers: Response headers\n        \"\"\"\n        ctype = headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n\n        if mimetype.type == \"multipart\":\n            if self.multipart_reader_cls is None:\n                return type(self)(headers, self._content)\n            return self.multipart_reader_cls(headers, self._content)\n        else:\n            return self.part_reader_cls(\n                self._boundary,\n                headers,\n                self._content,\n                subtype=self._mimetype.subtype,\n                default_charset=self._default_charset,\n            )\n\n    def _get_boundary(self) -> str:\n        boundary = self._mimetype.parameters[\"boundary\"]\n        if len(boundary) > 70:\n            raise ValueError(\"boundary %r is too long (70 chars max)\" % boundary)\n\n        return boundary\n\n    async def _readline(self) -> bytes:\n        if self._unread:\n            return self._unread.pop()\n        return await self._content.readline()\n\n    async def _read_until_first_boundary(self) -> None:\n        while True:\n            chunk = await self._readline()\n            if chunk == b\"\":\n                raise ValueError(\n                    \"Could not find starting boundary %r\" % (self._boundary)\n                )\n            chunk = chunk.rstrip()\n            if chunk == self._boundary:\n                return\n            elif chunk == self._boundary + b\"--\":\n                self._at_eof = True\n                return\n\n    async def _read_boundary(self) -> None:\n        chunk = (await self._readline()).rstrip()\n        if chunk == self._boundary:\n            pass\n        elif chunk == self._boundary + b\"--\":\n            self._at_eof = True\n            epilogue = await self._readline()\n            next_line = await self._readline()\n\n            # the epilogue is expected and then either the end of input or the\n            # parent multipart boundary, if the parent boundary is found then\n            # it should be marked as unread and handed to the parent for\n            # processing\n            if next_line[:2] == b\"--\":\n                self._unread.append(next_line)\n            # otherwise the request is likely missing an epilogue and both\n            # lines should be passed to the parent for processing\n            # (this handles the old behavior gracefully)\n            else:\n                self._unread.extend([next_line, epilogue])\n        else:\n            raise ValueError(f\"Invalid boundary {chunk!r}, expected {self._boundary!r}\")\n\n    async def _read_headers(self) -> \"CIMultiDictProxy[str]\":\n        lines = [b\"\"]\n        while True:\n            chunk = await self._content.readline()\n            chunk = chunk.strip()\n            lines.append(chunk)\n            if not chunk:\n                break\n        parser = HeadersParser()\n        headers, raw_headers = parser.parse_headers(lines)\n        return headers\n\n    async def _maybe_release_last_part(self) -> None:\n        \"\"\"Ensures that the last read body part is read completely.\"\"\"\n        if self._last_part is not None:\n            if not self._last_part.at_eof():\n                await self._last_part.release()\n            self._unread.extend(self._last_part._unread)\n            self._last_part = None\n\n\n_Part = Tuple[Payload, str, str]\n\n\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"\n\n    def __init__(self, subtype: str = \"mixed\", boundary: Optional[str] = None) -> None:\n        boundary = boundary if boundary is not None else uuid.uuid4().hex\n        # The underlying Payload API demands a str (utf-8), not bytes,\n        # so we need to ensure we don't lose anything during conversion.\n        # As a result, require the boundary to be ASCII only.\n        # In both situations.\n\n        try:\n            self._boundary = boundary.encode(\"ascii\")\n        except UnicodeEncodeError:\n            raise ValueError(\"boundary should contain ASCII only chars\") from None\n        ctype = f\"multipart/{subtype}; boundary={self._boundary_value}\"\n\n        super().__init__(None, content_type=ctype)\n\n        self._parts: List[_Part] = []\n        self._is_form_data = subtype == \"form-data\"\n\n    def __enter__(self) -> \"MultipartWriter\":\n        return self\n\n    def __exit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        pass\n\n    def __iter__(self) -> Iterator[_Part]:\n        return iter(self._parts)\n\n    def __len__(self) -> int:\n        return len(self._parts)\n\n    def __bool__(self) -> bool:\n        return True\n\n    _valid_tchar_regex = re.compile(rb\"\\A[!#$%&'*+\\-.^_`|~\\w]+\\Z\")\n    _invalid_qdtext_char_regex = re.compile(rb\"[\\x00-\\x08\\x0A-\\x1F\\x7F]\")\n\n    @property\n    def _boundary_value(self) -> str:\n        \"\"\"Wrap boundary parameter value in quotes, if necessary.\n\n        Reads self.boundary and returns a unicode string.\n        \"\"\"\n        # Refer to RFCs 7231, 7230, 5234.\n        #\n        # parameter      = token \"=\" ( token / quoted-string )\n        # token          = 1*tchar\n        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE\n        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text\n        # obs-text       = %x80-FF\n        # quoted-pair    = \"\\\" ( HTAB / SP / VCHAR / obs-text )\n        # tchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n        #                  / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n        #                  / DIGIT / ALPHA\n        #                  ; any VCHAR, except delimiters\n        # VCHAR           = %x21-7E\n        value = self._boundary\n        if re.match(self._valid_tchar_regex, value):\n            return value.decode(\"ascii\")  # cannot fail\n\n        if re.search(self._invalid_qdtext_char_regex, value):\n            raise ValueError(\"boundary value contains invalid characters\")\n\n        # escape %x5C and %x22\n        quoted_value_content = value.replace(b\"\\\\\", b\"\\\\\\\\\")\n        quoted_value_content = quoted_value_content.replace(b'\"', b'\\\\\"')\n\n        return '\"' + quoted_value_content.decode(\"ascii\") + '\"'\n\n    @property\n    def boundary(self) -> str:\n        return self._boundary.decode(\"ascii\")\n\n    def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload:\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Payload):\n            obj.headers.update(headers)\n            return self.append_payload(obj)\n        else:\n            try:\n                payload = get_payload(obj, headers=headers)\n            except LookupError:\n                raise TypeError(\"Cannot create payload from %r\" % obj)\n            else:\n                return self.append_payload(payload)\n\n    def append_payload(self, payload: Payload) -> Payload:\n        \"\"\"Adds a new body part to multipart writer.\"\"\"\n        encoding: Optional[str] = None\n        te_encoding: Optional[str] = None\n        if self._is_form_data:\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n            assert (\n                not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING}\n                & payload.headers.keys()\n            )\n            # Set default Content-Disposition in case user doesn't create one\n            if CONTENT_DISPOSITION not in payload.headers:\n                name = f\"section-{len(self._parts)}\"\n                payload.set_content_disposition(\"form-data\", name=name)\n        else:\n            # compression\n            encoding = payload.headers.get(CONTENT_ENCODING, \"\").lower()\n            if encoding and encoding not in (\"deflate\", \"gzip\", \"identity\"):\n                raise RuntimeError(f\"unknown content encoding: {encoding}\")\n            if encoding == \"identity\":\n                encoding = None\n\n            # te encoding\n            te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n            if te_encoding not in (\"\", \"base64\", \"quoted-printable\", \"binary\"):\n                raise RuntimeError(f\"unknown content transfer encoding: {te_encoding}\")\n            if te_encoding == \"binary\":\n                te_encoding = None\n\n            # size\n            size = payload.size\n            if size is not None and not (encoding or te_encoding):\n                payload.headers[CONTENT_LENGTH] = str(size)\n\n        self._parts.append((payload, encoding, te_encoding))  # type: ignore[arg-type]\n        return payload\n\n    def append_json(\n        self, obj: Any, headers: Optional[Mapping[str, str]] = None\n    ) -> Payload:\n        \"\"\"Helper to append JSON part.\"\"\"\n        if headers is None:\n            headers = CIMultiDict()\n\n        return self.append_payload(JsonPayload(obj, headers=headers))\n\n    def append_form(\n        self,\n        obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]],\n        headers: Optional[Mapping[str, str]] = None,\n    ) -> Payload:\n        \"\"\"Helper to append form urlencoded part.\"\"\"\n        assert isinstance(obj, (Sequence, Mapping))\n\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Mapping):\n            obj = list(obj.items())\n        data = urlencode(obj, doseq=True)\n\n        return self.append_payload(\n            StringPayload(\n                data, headers=headers, content_type=\"application/x-www-form-urlencoded\"\n            )\n        )\n\n    @property\n    def size(self) -> Optional[int]:\n        \"\"\"Size of the payload.\"\"\"\n        total = 0\n        for part, encoding, te_encoding in self._parts:\n            if encoding or te_encoding or part.size is None:\n                return None\n\n            total += int(\n                2\n                + len(self._boundary)\n                + 2\n                + part.size  # b'--'+self._boundary+b'\\r\\n'\n                + len(part._binary_headers)\n                + 2  # b'\\r\\n'\n            )\n\n        total += 2 + len(self._boundary) + 4  # b'--'+self._boundary+b'--\\r\\n'\n        return total\n\n    async def write(self, writer: Any, close_boundary: bool = True) -> None:\n        \"\"\"Write body.\"\"\"\n        for part, encoding, te_encoding in self._parts:\n            if self._is_form_data:\n                # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2\n                assert CONTENT_DISPOSITION in part.headers\n                assert \"name=\" in part.headers[CONTENT_DISPOSITION]\n\n            await writer.write(b\"--\" + self._boundary + b\"\\r\\n\")\n            await writer.write(part._binary_headers)\n\n            if encoding or te_encoding:\n                w = MultipartPayloadWriter(writer)\n                if encoding:\n                    w.enable_compression(encoding)\n                if te_encoding:\n                    w.enable_encoding(te_encoding)\n                await part.write(w)  # type: ignore[arg-type]\n                await w.write_eof()\n            else:\n                await part.write(writer)\n\n            await writer.write(b\"\\r\\n\")\n\n        if close_boundary:\n            await writer.write(b\"--\" + self._boundary + b\"--\\r\\n\")\n\n\nclass MultipartPayloadWriter:\n    def __init__(self, writer: Any) -> None:\n        self._writer = writer\n        self._encoding: Optional[str] = None\n        self._compress: Optional[ZLibCompressor] = None\n        self._encoding_buffer: Optional[bytearray] = None\n\n    def enable_encoding(self, encoding: str) -> None:\n        if encoding == \"base64\":\n            self._encoding = encoding\n            self._encoding_buffer = bytearray()\n        elif encoding == \"quoted-printable\":\n            self._encoding = \"quoted-printable\"\n\n    def enable_compression(\n        self, encoding: str = \"deflate\", strategy: int = zlib.Z_DEFAULT_STRATEGY\n    ) -> None:\n        self._compress = ZLibCompressor(\n            encoding=encoding,\n            suppress_deflate_header=True,\n            strategy=strategy,\n        )\n\n    async def write_eof(self) -> None:\n        if self._compress is not None:\n            chunk = self._compress.flush()\n            if chunk:\n                self._compress = None\n                await self.write(chunk)\n\n        if self._encoding == \"base64\":\n            if self._encoding_buffer:\n                await self._writer.write(base64.b64encode(self._encoding_buffer))\n\n    async def write(self, chunk: bytes) -> None:\n        if self._compress is not None:\n            if chunk:\n                chunk = await self._compress.compress(chunk)\n                if not chunk:\n                    return\n\n        if self._encoding == \"base64\":\n            buf = self._encoding_buffer\n            assert buf is not None\n            buf.extend(chunk)\n\n            if buf:\n                div, mod = divmod(len(buf), 3)\n                enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :])\n                if enc_chunk:\n                    b64chunk = base64.b64encode(enc_chunk)\n                    await self._writer.write(b64chunk)\n        elif self._encoding == \"quoted-printable\":\n            await self._writer.write(binascii.b2a_qp(chunk))\n        else:\n            await self._writer.write(chunk)\n",
            "header": {
                "file": {
                    "path": "aiohttp/multipart.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "26780e30",
                "new_commit_hash": "da016039",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/aiohttp/multipart.py"
            },
            "plus_file": {
                "path": "b/aiohttp/multipart.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 323,
                            "length": 6
                        },
                        "new_range": {
                            "start": 323,
                            "length": 31
                        },
                        "section": "class BodyPartReader:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        else:",
                                "type": "context"
                            },
                            {
                                "content": "            chunk = await self._read_chunk_from_stream(size)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        # For the case of base64 data, we must read a fragment of size with a",
                                "type": "added"
                            },
                            {
                                "content": "        # remainder of 0 by dividing by 4 for string without symbols \\n or \\r",
                                "type": "added"
                            },
                            {
                                "content": "        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)",
                                "type": "added"
                            },
                            {
                                "content": "        if encoding and encoding.lower() == \"base64\":",
                                "type": "added"
                            },
                            {
                                "content": "            stripped_chunk = b\"\".join(chunk.split())",
                                "type": "added"
                            },
                            {
                                "content": "            remainder = len(stripped_chunk) % 4",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "            while remainder != 0 and not self.at_eof():",
                                "type": "added"
                            },
                            {
                                "content": "                over_chunk_size = 4 - remainder",
                                "type": "added"
                            },
                            {
                                "content": "                over_chunk = b\"\"",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "                if self._prev_chunk:",
                                "type": "added"
                            },
                            {
                                "content": "                    over_chunk = self._prev_chunk[:over_chunk_size]",
                                "type": "added"
                            },
                            {
                                "content": "                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "                if len(over_chunk) != over_chunk_size:",
                                "type": "added"
                            },
                            {
                                "content": "                    over_chunk += await self._content.read(4 - len(over_chunk))",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "                if not over_chunk:",
                                "type": "added"
                            },
                            {
                                "content": "                    self._at_eof = True",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "                stripped_chunk += b\"\".join(over_chunk.split())",
                                "type": "added"
                            },
                            {
                                "content": "                chunk += over_chunk",
                                "type": "added"
                            },
                            {
                                "content": "                remainder = len(stripped_chunk) % 4",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        self._read_bytes += len(chunk)",
                                "type": "context"
                            },
                            {
                                "content": "        if self._read_bytes == self._length:",
                                "type": "context"
                            },
                            {
                                "content": "            self._at_eof = True",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "aiohttp/multipart.py",
                            "type": "class",
                            "name": "BodyPartReader",
                            "content": "class BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        # For the case of base64 data, we must read a fragment of size with a\n        # remainder of 0 by dividing by 4 for string without symbols \\n or \\r\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)\n        if encoding and encoding.lower() == \"base64\":\n            stripped_chunk = b\"\".join(chunk.split())\n            remainder = len(stripped_chunk) % 4\n\n            while remainder != 0 and not self.at_eof():\n                over_chunk_size = 4 - remainder\n                over_chunk = b\"\"\n\n                if self._prev_chunk:\n                    over_chunk = self._prev_chunk[:over_chunk_size]\n                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]\n\n                if len(over_chunk) != over_chunk_size:\n                    over_chunk += await self._content.read(4 - len(over_chunk))\n\n                if not over_chunk:\n                    self._at_eof = True\n\n                stripped_chunk += b\"\".join(over_chunk.split())\n                chunk += over_chunk\n                remainder = len(stripped_chunk) % 4\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 253,
                            "end_lineno": 552,
                            "parent": null
                        },
                        {
                            "file_name": "aiohttp/multipart.py",
                            "type": "method",
                            "name": "BodyPartReader.read_chunk",
                            "content": "class BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        # For the case of base64 data, we must read a fragment of size with a\n        # remainder of 0 by dividing by 4 for string without symbols \\n or \\r\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)\n        if encoding and encoding.lower() == \"base64\":\n            stripped_chunk = b\"\".join(chunk.split())\n            remainder = len(stripped_chunk) % 4\n\n            while remainder != 0 and not self.at_eof():\n                over_chunk_size = 4 - remainder\n                over_chunk = b\"\"\n\n                if self._prev_chunk:\n                    over_chunk = self._prev_chunk[:over_chunk_size]\n                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]\n\n                if len(over_chunk) != over_chunk_size:\n                    over_chunk += await self._content.read(4 - len(over_chunk))\n\n                if not over_chunk:\n                    self._at_eof = True\n\n                stripped_chunk += b\"\".join(over_chunk.split())\n                chunk += over_chunk\n                remainder = len(stripped_chunk) % 4\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 314,
                            "end_lineno": 359,
                            "parent": {
                                "file_name": "aiohttp/multipart.py",
                                "type": "class",
                                "name": "BodyPartReader",
                                "content": "class BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        # For the case of base64 data, we must read a fragment of size with a\n        # remainder of 0 by dividing by 4 for string without symbols \\n or \\r\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)\n        if encoding and encoding.lower() == \"base64\":\n            stripped_chunk = b\"\".join(chunk.split())\n            remainder = len(stripped_chunk) % 4\n\n            while remainder != 0 and not self.at_eof():\n                over_chunk_size = 4 - remainder\n                over_chunk = b\"\"\n\n                if self._prev_chunk:\n                    over_chunk = self._prev_chunk[:over_chunk_size]\n                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]\n\n                if len(over_chunk) != over_chunk_size:\n                    over_chunk += await self._content.read(4 - len(over_chunk))\n\n                if not over_chunk:\n                    self._at_eof = True\n\n                stripped_chunk += b\"\".join(over_chunk.split())\n                chunk += over_chunk\n                remainder = len(stripped_chunk) % 4\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 253,
                                "end_lineno": 552,
                                "parent": null
                            }
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import asyncio\nimport io\nimport json\nimport pathlib\nimport sys\nimport zlib\nfrom unittest import mock\n\nimport pytest\n\nimport aiohttp\nfrom aiohttp import payload\nfrom aiohttp.hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom aiohttp.helpers import parse_mimetype\nfrom aiohttp.multipart import MultipartResponseWrapper\nfrom aiohttp.streams import StreamReader\nfrom aiohttp.test_utils import make_mocked_coro\n\nBOUNDARY = b\"--:\"\n\n\nnewline = b\"\\r\\n\"\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef stream(buf):\n    writer = mock.Mock()\n\n    async def write(chunk):\n        buf.extend(chunk)\n\n    writer.write.side_effect = write\n    return writer\n\n\n@pytest.fixture\ndef writer():\n    return aiohttp.MultipartWriter(boundary=\":\")\n\n\nclass Response:\n    def __init__(self, headers, content):\n        self.headers = headers\n        self.content = content\n\n\nclass Stream:\n    def __init__(self, content):\n        self.content = io.BytesIO(content)\n\n    async def read(self, size=None):\n        return self.content.read(size)\n\n    def at_eof(self):\n        return self.content.tell() == len(self.content.getbuffer())\n\n    async def readline(self):\n        return self.content.readline()\n\n    def unread_data(self, data):\n        self.content = io.BytesIO(data + self.content.read())\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.content.close()\n\n\nclass StreamWithShortenRead(Stream):\n    def __init__(self, content):\n        self._first = True\n        super().__init__(content)\n\n    async def read(self, size=None):\n        if size is not None and self._first:\n            self._first = False\n            size = size // 2\n        return await super().read(size)\n\n\nclass TestMultipartResponseWrapper:\n    def test_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.at_eof()\n        assert wrapper.resp.content.at_eof.called\n\n    async def test_next(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = False\n        await wrapper.next()\n        assert wrapper.stream.next.called\n\n    async def test_release(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        await wrapper.release()\n        assert wrapper.resp.release.called\n\n    async def test_release_when_stream_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = True\n        await wrapper.next()\n        assert wrapper.stream.next.called\n        assert wrapper.resp.release.called\n\n\nclass TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size\n\n\nclass TestMultipartReader:\n    def test_from_response(self) -> None:\n        with Stream(b\"--:%s\\r\\nhello%s--:--\" % (newline, newline)) as stream:\n            resp = Response(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = aiohttp.MultipartReader.from_response(resp)\n        assert isinstance(res, MultipartResponseWrapper)\n        assert isinstance(res.stream, aiohttp.MultipartReader)\n\n    def test_bad_boundary(self) -> None:\n        with Stream(b\"\") as stream:\n            resp = Response(\n                {CONTENT_TYPE: \"multipart/related;boundary=\" + \"a\" * 80}, stream\n            )\n            with pytest.raises(ValueError):\n                aiohttp.MultipartReader.from_response(resp)\n\n    def test_dispatch(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_bodypart(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_multipart(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\" b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader(\n                {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n            )\n        assert isinstance(res, reader.__class__)\n\n    def test_dispatch_custom_multipart_reader(self) -> None:\n        class CustomReader(aiohttp.MultipartReader):\n            pass\n\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n            Stream(\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"test\\r\\n\"\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"passed\\r\\n\"\n                b\"----:----\\r\\n\"\n                b\"--:--\"\n            ),\n        )\n        reader.multipart_reader_cls = CustomReader\n        res = reader._get_part_reader(\n            {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n        )\n        assert isinstance(res, CustomReader)\n\n    async def test_emit_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = await reader.next()\n        assert isinstance(res, reader.part_reader_cls)\n\n    async def test_invalid_boundary(self) -> None:\n        with Stream(b\"---:%s\\r\\necho%s---:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(ValueError):\n                await reader.next()\n\n    @pytest.mark.skipif(sys.version_info < (3, 10), reason=\"Needs anext()\")\n    async def test_read_boundary_across_chunks(self) -> None:\n        class SplitBoundaryStream:\n            def __init__(self) -> None:\n                self.content = [\n                    b\"--foobar\\r\\n\\r\\n\",\n                    b\"Hello,\\r\\n-\",\n                    b\"-fo\",\n                    b\"ob\",\n                    b\"ar\\r\\n\",\n                    b\"\\r\\nwor\",\n                    b\"ld!\",\n                    b\"\\r\\n--f\",\n                    b\"oobar--\",\n                ]\n\n            async def read(self, size=None) -> bytes:\n                chunk = self.content.pop(0)\n                assert len(chunk) <= size\n                return chunk\n\n            def at_eof(self) -> bool:\n                return not self.content\n\n            async def readline(self) -> bytes:\n                line = b\"\"\n                while self.content and b\"\\n\" not in line:\n                    line += self.content.pop(0)\n                line, *extra = line.split(b\"\\n\", maxsplit=1)\n                if extra and extra[0]:\n                    self.content.insert(0, extra[0])\n                return line + b\"\\n\"\n\n            def unread_data(self, data: bytes) -> None:\n                if self.content:\n                    self.content[0] = data + self.content[0]\n                else:\n                    self.content.append(data)\n\n        stream = SplitBoundaryStream()\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\"foobar\"'}, stream\n        )\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"Hello,\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"world!\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        with pytest.raises(StopAsyncIteration):\n            await anext(reader)\n\n    async def test_release(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Type: multipart/related;boundary=--:--\",\n                    b\"\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\",\n                    b\"\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/mixed;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_release(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            res = await reader.next()\n            assert res is None\n\n    async def test_second_next_releases_previous_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_release_without_read_the_last_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            second = await reader.next()\n            third = await reader.next()\n\n            assert first.at_eof()\n            assert second.at_eof()\n            assert second.at_eof()\n            assert third is None\n\n    async def test_read_chunk_by_length_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Length: 4\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"Content-Length: 6\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    read_part += await part.read_chunk(3)\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"test\", b\"passed\"]\n\n    async def test_read_chunk_from_stream_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"chunk\",\n                    b\"--:\",\n                    b\"\",\n                    b\"two_chunks\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    chunk = await part.read_chunk(5)\n                    assert chunk\n                    read_part += chunk\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"chunk\", b\"two_chunks\"]\n\n    async def test_reading_skips_prelude(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"Multi-part data is not supported.\",\n                    b\"\",\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_read_form_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"ascii\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain;charset=UTF-8\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field2\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field3\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            field1 = await reader.next()\n            assert field1.name == \"field1\"\n            assert field1.get_charset(\"default\") == \"ascii\"\n            field2 = await reader.next()\n            assert field2.name == \"field2\"\n            assert field2.get_charset(\"default\") == \"UTF-8\"\n            field3 = await reader.next()\n            assert field3.name == \"field3\"\n            assert field3.get_charset(\"default\") == \"ascii\"\n\n    async def test_read_form_invalid_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"this-value-is-too-long-to-be-a-charset\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(RuntimeError, match=\"Invalid default charset\"):\n                await reader.next()\n\n\nasync def test_writer(writer) -> None:\n    assert writer.size == 7\n    assert writer.boundary == \":\"\n\n\nasync def test_writer_serialize_io_chunk(buf, stream, writer) -> None:\n    with io.BytesIO(b\"foobarbaz\") as file_handle:\n        writer.append(file_handle)\n        await writer.write(stream)\n    assert (\n        buf == b\"--:\\r\\nContent-Type: application/octet-stream\"\n        b\"\\r\\nContent-Length: 9\\r\\n\\r\\nfoobarbaz\\r\\n--:--\\r\\n\"\n    )\n\n\nasync def test_writer_serialize_json(buf, stream, writer) -> None:\n    writer.append_json({\"привет\": \"мир\"})\n    await writer.write(stream)\n    assert (\n        b'{\"\\\\u043f\\\\u0440\\\\u0438\\\\u0432\\\\u0435\\\\u0442\":'\n        b' \"\\\\u043c\\\\u0438\\\\u0440\"}' in buf\n    )\n\n\nasync def test_writer_serialize_form(buf, stream, writer) -> None:\n    data = [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"zoo\")]\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"foo=bar&foo=baz&boo=zoo\" in buf\n\n\nasync def test_writer_serialize_form_dict(buf, stream, writer) -> None:\n    data = {\"hello\": \"мир\"}\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"hello=%D0%BC%D0%B8%D1%80\" in buf\n\n\nasync def test_writer_write(buf, stream, writer) -> None:\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n\n    sub_multipart = aiohttp.MultipartWriter(boundary=\"::\")\n    sub_multipart.append(\"nested content\")\n    sub_multipart.headers[\"X-CUSTOM\"] = \"test\"\n    writer.append(sub_multipart)\n    await writer.write(stream)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b'Content-Type: multipart/mixed; boundary=\"::\"\\r\\n'\n        b\"X-CUSTOM: test\\r\\nContent-Length: 93\\r\\n\\r\\n\"\n        b\"--::\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 14\\r\\n\\r\\n\"\n        b\"nested content\\r\\n\"\n        b\"--::--\\r\\n\"\n        b\"\\r\\n\"\n        b\"--:--\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_close_boundary(buf, stream) -> None:\n    writer = aiohttp.MultipartWriter(boundary=\":\")\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n    await writer.write(stream, close_boundary=False)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_parts(buf, stream, writer) -> None:\n    await writer.write(stream)\n    assert b\"--:--\\r\\n\" == bytes(buf)\n\n\nasync def test_writer_serialize_with_content_encoding_gzip(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"gzip\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: gzip\" == headers\n    )\n\n    decompressor = zlib.decompressobj(wbits=16 + zlib.MAX_WBITS)\n    data = decompressor.decompress(message.split(b\"\\r\\n\")[0])\n    data += decompressor.flush()\n    assert b\"Time to Relax!\" == data\n\n\nasync def test_writer_serialize_with_content_encoding_deflate(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"deflate\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: deflate\" == headers\n    )\n\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\\r\\n--:--\\r\\n\"\n    assert thing == message\n\n\nasync def test_writer_serialize_with_content_encoding_identity(buf, stream, writer):\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n    writer.append(thing, {CONTENT_ENCODING: \"identity\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: application/octet-stream\\r\\n\"\n        b\"Content-Encoding: identity\\r\\n\"\n        b\"Content-Length: 16\" == headers\n    )\n\n    assert thing == message.split(b\"\\r\\n\")[0]\n\n\ndef test_writer_serialize_with_content_encoding_unknown(buf, stream, writer):\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"snappy\"})\n\n\nasync def test_writer_with_content_transfer_encoding_base64(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"base64\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: base64\" == headers\n    )\n\n    assert b\"VGltZSB0byBSZWxheCE=\" == message.split(b\"\\r\\n\")[0]\n\n\nasync def test_writer_content_transfer_encoding_quote_printable(buf, stream, writer):\n    writer.append(\"Привет, мир!\", {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: quoted-printable\" == headers\n    )\n\n    assert (\n        b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n        b\" =D0=BC=D0=B8=D1=80!\" == message.split(b\"\\r\\n\")[0]\n    )\n\n\ndef test_writer_content_transfer_encoding_unknown(buf, stream, writer) -> None:\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"unknown\"})\n\n\nclass TestMultipartWriter:\n    def test_default_subtype(self, writer) -> None:\n        mimetype = parse_mimetype(writer.headers.get(CONTENT_TYPE))\n\n        assert \"multipart\" == mimetype.type\n        assert \"mixed\" == mimetype.subtype\n\n    def test_unquoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=\"abc123\")\n        expected = {CONTENT_TYPE: \"multipart/mixed; boundary=abc123\"}\n        assert expected == writer.headers\n\n    def test_quoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=R\"\\\"\")\n        expected = {CONTENT_TYPE: R'multipart/mixed; boundary=\"\\\\\\\"\"'}\n        assert expected == writer.headers\n\n    def test_bad_boundary(self) -> None:\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"тест\")\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"test\\n\")\n\n    def test_default_headers(self, writer) -> None:\n        expected = {CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'}\n        assert expected == writer.headers\n\n    def test_iter_parts(self, writer) -> None:\n        writer.append(\"foo\")\n        writer.append(\"bar\")\n        writer.append(\"baz\")\n        assert 3 == len(list(writer))\n\n    def test_append(self, writer) -> None:\n        assert 0 == len(writer)\n        writer.append(\"hello, world!\")\n        assert 1 == len(writer)\n        assert isinstance(writer._parts[0][0], payload.Payload)\n\n    def test_append_with_headers(self, writer) -> None:\n        writer.append(\"hello, world!\", {\"x-foo\": \"bar\"})\n        assert 1 == len(writer)\n        assert \"x-foo\" in writer._parts[0][0].headers\n        assert writer._parts[0][0].headers[\"x-foo\"] == \"bar\"\n\n    def test_append_json(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"application/json\"\n\n    def test_append_part(self, writer) -> None:\n        part = payload.get_payload(\"test\", headers={CONTENT_TYPE: \"text/plain\"})\n        writer.append(part, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_json_overrides_content_type(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_form(self, writer) -> None:\n        writer.append_form({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_multipart(self, writer) -> None:\n        subwriter = aiohttp.MultipartWriter(boundary=\":\")\n        subwriter.append_json({\"foo\": \"bar\"})\n        writer.append(subwriter, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_set_content_disposition_after_append(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        part = writer.append(\"some-data\")\n        part.set_content_disposition(\"form-data\", name=\"method\")\n        assert 'name=\"method\"' in part.headers[CONTENT_DISPOSITION]\n\n    def test_automatic_content_disposition(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        writer.append_json(())\n        part = payload.StringPayload(\"foo\")\n        part.set_content_disposition(\"form-data\", name=\"second\")\n        writer.append_payload(part)\n        writer.append(\"foo\")\n\n        disps = tuple(p[0].headers[CONTENT_DISPOSITION] for p in writer._parts)\n        assert 'name=\"section-0\"' in disps[0]\n        assert 'name=\"second\"' in disps[1]\n        assert 'name=\"section-2\"' in disps[2]\n\n    def test_with(self) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            writer.append(\"foo\")\n            writer.append(b\"bar\")\n            writer.append_json({\"baz\": True})\n        assert 3 == len(writer)\n\n    def test_append_int_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1)\n\n    def test_append_float_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1.1)\n\n    def test_append_none_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(None)\n\n    async def test_write_preserves_content_disposition(self, buf, stream) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            part = writer.append(b\"foo\", headers={CONTENT_TYPE: \"test/passed\"})\n            part.set_content_disposition(\"form-data\", filename=\"bug\")\n        await writer.write(stream)\n\n        headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: test/passed\\r\\n\"\n            b\"Content-Length: 3\\r\\n\"\n            b\"Content-Disposition:\"\n            b' form-data; filename=\"bug\"'\n        )\n        assert message == b\"foo\\r\\n--:--\\r\\n\"\n\n    async def test_preserve_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_set_content_disposition_override(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_reset_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={CONTENT_TYPE: \"text/plain\"},\n                )\n\n            assert CONTENT_DISPOSITION in part.headers\n\n            part.set_content_disposition(\"attachments\", filename=\"bug.py\")\n\n            await writer.write(stream)\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain\\r\\n\"\n            b\"Content-Disposition:\"\n            b' attachments; filename=\"bug.py\"'\n        )\n\n\nasync def test_async_for_reader() -> None:\n    data = [{\"test\": \"passed\"}, 42, b\"plain text\", b\"aiohttp\\n\", b\"no epilogue\"]\n    with Stream(\n        b\"\\r\\n\".join(\n            [\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[0]).encode(),\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[1]).encode(),\n                b\"--:\",\n                b'Content-Type: multipart/related; boundary=\"::\"',\n                b\"\",\n                b\"--::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[2],\n                b\"--::\",\n                b'Content-Disposition: attachment; filename=\"aiohttp\"',\n                b\"Content-Type: text/plain\",\n                b\"Content-Length: 28\",\n                b\"Content-Encoding: gzip\",\n                b\"\",\n                b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03K\\xcc\\xcc\\xcf())\"\n                b\"\\xe0\\x02\\x00\\xd6\\x90\\xe2O\\x08\\x00\\x00\\x00\",\n                b\"--::\",\n                b'Content-Type: multipart/related; boundary=\":::\"',\n                b\"\",\n                b\"--:::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[4],\n                b\"--:::--\",\n                b\"--::--\",\n                b\"\",\n                b\"--:--\",\n                b\"\",\n            ]\n        )\n    ) as stream:\n        reader = aiohttp.MultipartReader(\n            headers={CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'},\n            content=stream,\n        )\n        idata = iter(data)\n\n        async def check(reader):\n            async for part in reader:\n                if isinstance(part, aiohttp.BodyPartReader):\n                    if part.headers[CONTENT_TYPE] == \"application/json\":\n                        assert next(idata) == (await part.json())\n                    else:\n                        assert next(idata) == await part.read(decode=True)\n                else:\n                    await check(part)\n\n        await check(reader)\n\n\nasync def test_async_for_bodypart() -> None:\n    with Stream(b\"foobarbaz\\r\\n--:--\") as stream:\n        part = aiohttp.BodyPartReader(boundary=b\"--:\", headers={}, content=stream)\n        async for data in part:\n            assert data == b\"foobarbaz\"\n",
            "new_file_content": "import asyncio\nimport io\nimport json\nimport pathlib\nimport sys\nimport zlib\nfrom unittest import mock\n\nimport pytest\n\nimport aiohttp\nfrom aiohttp import payload\nfrom aiohttp.hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom aiohttp.helpers import parse_mimetype\nfrom aiohttp.multipart import MultipartResponseWrapper\nfrom aiohttp.streams import StreamReader\nfrom aiohttp.test_utils import make_mocked_coro\n\nBOUNDARY = b\"--:\"\n\n\nnewline = b\"\\r\\n\"\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef stream(buf):\n    writer = mock.Mock()\n\n    async def write(chunk):\n        buf.extend(chunk)\n\n    writer.write.side_effect = write\n    return writer\n\n\n@pytest.fixture\ndef writer():\n    return aiohttp.MultipartWriter(boundary=\":\")\n\n\nclass Response:\n    def __init__(self, headers, content):\n        self.headers = headers\n        self.content = content\n\n\nclass Stream:\n    def __init__(self, content):\n        self.content = io.BytesIO(content)\n\n    async def read(self, size=None):\n        return self.content.read(size)\n\n    def at_eof(self):\n        return self.content.tell() == len(self.content.getbuffer())\n\n    async def readline(self):\n        return self.content.readline()\n\n    def unread_data(self, data):\n        self.content = io.BytesIO(data + self.content.read())\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.content.close()\n\n\nclass StreamWithShortenRead(Stream):\n    def __init__(self, content):\n        self._first = True\n        super().__init__(content)\n\n    async def read(self, size=None):\n        if size is not None and self._first:\n            self._first = False\n            size = size // 2\n        return await super().read(size)\n\n\nclass TestMultipartResponseWrapper:\n    def test_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.at_eof()\n        assert wrapper.resp.content.at_eof.called\n\n    async def test_next(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = False\n        await wrapper.next()\n        assert wrapper.stream.next.called\n\n    async def test_release(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        await wrapper.release()\n        assert wrapper.resp.release.called\n\n    async def test_release_when_stream_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = True\n        await wrapper.next()\n        assert wrapper.stream.next.called\n        assert wrapper.resp.release.called\n\n\nclass TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n                result += obj.decode(chunk)\n        assert b\"Time to Relax!\" == result\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size\n\n\nclass TestMultipartReader:\n    def test_from_response(self) -> None:\n        with Stream(b\"--:%s\\r\\nhello%s--:--\" % (newline, newline)) as stream:\n            resp = Response(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = aiohttp.MultipartReader.from_response(resp)\n        assert isinstance(res, MultipartResponseWrapper)\n        assert isinstance(res.stream, aiohttp.MultipartReader)\n\n    def test_bad_boundary(self) -> None:\n        with Stream(b\"\") as stream:\n            resp = Response(\n                {CONTENT_TYPE: \"multipart/related;boundary=\" + \"a\" * 80}, stream\n            )\n            with pytest.raises(ValueError):\n                aiohttp.MultipartReader.from_response(resp)\n\n    def test_dispatch(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_bodypart(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_multipart(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\" b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader(\n                {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n            )\n        assert isinstance(res, reader.__class__)\n\n    def test_dispatch_custom_multipart_reader(self) -> None:\n        class CustomReader(aiohttp.MultipartReader):\n            pass\n\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n            Stream(\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"test\\r\\n\"\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"passed\\r\\n\"\n                b\"----:----\\r\\n\"\n                b\"--:--\"\n            ),\n        )\n        reader.multipart_reader_cls = CustomReader\n        res = reader._get_part_reader(\n            {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n        )\n        assert isinstance(res, CustomReader)\n\n    async def test_emit_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = await reader.next()\n        assert isinstance(res, reader.part_reader_cls)\n\n    async def test_invalid_boundary(self) -> None:\n        with Stream(b\"---:%s\\r\\necho%s---:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(ValueError):\n                await reader.next()\n\n    @pytest.mark.skipif(sys.version_info < (3, 10), reason=\"Needs anext()\")\n    async def test_read_boundary_across_chunks(self) -> None:\n        class SplitBoundaryStream:\n            def __init__(self) -> None:\n                self.content = [\n                    b\"--foobar\\r\\n\\r\\n\",\n                    b\"Hello,\\r\\n-\",\n                    b\"-fo\",\n                    b\"ob\",\n                    b\"ar\\r\\n\",\n                    b\"\\r\\nwor\",\n                    b\"ld!\",\n                    b\"\\r\\n--f\",\n                    b\"oobar--\",\n                ]\n\n            async def read(self, size=None) -> bytes:\n                chunk = self.content.pop(0)\n                assert len(chunk) <= size\n                return chunk\n\n            def at_eof(self) -> bool:\n                return not self.content\n\n            async def readline(self) -> bytes:\n                line = b\"\"\n                while self.content and b\"\\n\" not in line:\n                    line += self.content.pop(0)\n                line, *extra = line.split(b\"\\n\", maxsplit=1)\n                if extra and extra[0]:\n                    self.content.insert(0, extra[0])\n                return line + b\"\\n\"\n\n            def unread_data(self, data: bytes) -> None:\n                if self.content:\n                    self.content[0] = data + self.content[0]\n                else:\n                    self.content.append(data)\n\n        stream = SplitBoundaryStream()\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\"foobar\"'}, stream\n        )\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"Hello,\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"world!\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        with pytest.raises(StopAsyncIteration):\n            await anext(reader)\n\n    async def test_release(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Type: multipart/related;boundary=--:--\",\n                    b\"\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\",\n                    b\"\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/mixed;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_release(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            res = await reader.next()\n            assert res is None\n\n    async def test_second_next_releases_previous_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_release_without_read_the_last_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            second = await reader.next()\n            third = await reader.next()\n\n            assert first.at_eof()\n            assert second.at_eof()\n            assert second.at_eof()\n            assert third is None\n\n    async def test_read_chunk_by_length_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Length: 4\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"Content-Length: 6\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    read_part += await part.read_chunk(3)\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"test\", b\"passed\"]\n\n    async def test_read_chunk_from_stream_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"chunk\",\n                    b\"--:\",\n                    b\"\",\n                    b\"two_chunks\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    chunk = await part.read_chunk(5)\n                    assert chunk\n                    read_part += chunk\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"chunk\", b\"two_chunks\"]\n\n    async def test_reading_skips_prelude(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"Multi-part data is not supported.\",\n                    b\"\",\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_read_form_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"ascii\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain;charset=UTF-8\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field2\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field3\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            field1 = await reader.next()\n            assert field1.name == \"field1\"\n            assert field1.get_charset(\"default\") == \"ascii\"\n            field2 = await reader.next()\n            assert field2.name == \"field2\"\n            assert field2.get_charset(\"default\") == \"UTF-8\"\n            field3 = await reader.next()\n            assert field3.name == \"field3\"\n            assert field3.get_charset(\"default\") == \"ascii\"\n\n    async def test_read_form_invalid_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"this-value-is-too-long-to-be-a-charset\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(RuntimeError, match=\"Invalid default charset\"):\n                await reader.next()\n\n\nasync def test_writer(writer) -> None:\n    assert writer.size == 7\n    assert writer.boundary == \":\"\n\n\nasync def test_writer_serialize_io_chunk(buf, stream, writer) -> None:\n    with io.BytesIO(b\"foobarbaz\") as file_handle:\n        writer.append(file_handle)\n        await writer.write(stream)\n    assert (\n        buf == b\"--:\\r\\nContent-Type: application/octet-stream\"\n        b\"\\r\\nContent-Length: 9\\r\\n\\r\\nfoobarbaz\\r\\n--:--\\r\\n\"\n    )\n\n\nasync def test_writer_serialize_json(buf, stream, writer) -> None:\n    writer.append_json({\"привет\": \"мир\"})\n    await writer.write(stream)\n    assert (\n        b'{\"\\\\u043f\\\\u0440\\\\u0438\\\\u0432\\\\u0435\\\\u0442\":'\n        b' \"\\\\u043c\\\\u0438\\\\u0440\"}' in buf\n    )\n\n\nasync def test_writer_serialize_form(buf, stream, writer) -> None:\n    data = [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"zoo\")]\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"foo=bar&foo=baz&boo=zoo\" in buf\n\n\nasync def test_writer_serialize_form_dict(buf, stream, writer) -> None:\n    data = {\"hello\": \"мир\"}\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"hello=%D0%BC%D0%B8%D1%80\" in buf\n\n\nasync def test_writer_write(buf, stream, writer) -> None:\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n\n    sub_multipart = aiohttp.MultipartWriter(boundary=\"::\")\n    sub_multipart.append(\"nested content\")\n    sub_multipart.headers[\"X-CUSTOM\"] = \"test\"\n    writer.append(sub_multipart)\n    await writer.write(stream)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b'Content-Type: multipart/mixed; boundary=\"::\"\\r\\n'\n        b\"X-CUSTOM: test\\r\\nContent-Length: 93\\r\\n\\r\\n\"\n        b\"--::\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 14\\r\\n\\r\\n\"\n        b\"nested content\\r\\n\"\n        b\"--::--\\r\\n\"\n        b\"\\r\\n\"\n        b\"--:--\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_close_boundary(buf, stream) -> None:\n    writer = aiohttp.MultipartWriter(boundary=\":\")\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n    await writer.write(stream, close_boundary=False)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_parts(buf, stream, writer) -> None:\n    await writer.write(stream)\n    assert b\"--:--\\r\\n\" == bytes(buf)\n\n\nasync def test_writer_serialize_with_content_encoding_gzip(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"gzip\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: gzip\" == headers\n    )\n\n    decompressor = zlib.decompressobj(wbits=16 + zlib.MAX_WBITS)\n    data = decompressor.decompress(message.split(b\"\\r\\n\")[0])\n    data += decompressor.flush()\n    assert b\"Time to Relax!\" == data\n\n\nasync def test_writer_serialize_with_content_encoding_deflate(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"deflate\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: deflate\" == headers\n    )\n\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\\r\\n--:--\\r\\n\"\n    assert thing == message\n\n\nasync def test_writer_serialize_with_content_encoding_identity(buf, stream, writer):\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n    writer.append(thing, {CONTENT_ENCODING: \"identity\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: application/octet-stream\\r\\n\"\n        b\"Content-Encoding: identity\\r\\n\"\n        b\"Content-Length: 16\" == headers\n    )\n\n    assert thing == message.split(b\"\\r\\n\")[0]\n\n\ndef test_writer_serialize_with_content_encoding_unknown(buf, stream, writer):\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"snappy\"})\n\n\nasync def test_writer_with_content_transfer_encoding_base64(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"base64\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: base64\" == headers\n    )\n\n    assert b\"VGltZSB0byBSZWxheCE=\" == message.split(b\"\\r\\n\")[0]\n\n\nasync def test_writer_content_transfer_encoding_quote_printable(buf, stream, writer):\n    writer.append(\"Привет, мир!\", {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: quoted-printable\" == headers\n    )\n\n    assert (\n        b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n        b\" =D0=BC=D0=B8=D1=80!\" == message.split(b\"\\r\\n\")[0]\n    )\n\n\ndef test_writer_content_transfer_encoding_unknown(buf, stream, writer) -> None:\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"unknown\"})\n\n\nclass TestMultipartWriter:\n    def test_default_subtype(self, writer) -> None:\n        mimetype = parse_mimetype(writer.headers.get(CONTENT_TYPE))\n\n        assert \"multipart\" == mimetype.type\n        assert \"mixed\" == mimetype.subtype\n\n    def test_unquoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=\"abc123\")\n        expected = {CONTENT_TYPE: \"multipart/mixed; boundary=abc123\"}\n        assert expected == writer.headers\n\n    def test_quoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=R\"\\\"\")\n        expected = {CONTENT_TYPE: R'multipart/mixed; boundary=\"\\\\\\\"\"'}\n        assert expected == writer.headers\n\n    def test_bad_boundary(self) -> None:\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"тест\")\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"test\\n\")\n\n    def test_default_headers(self, writer) -> None:\n        expected = {CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'}\n        assert expected == writer.headers\n\n    def test_iter_parts(self, writer) -> None:\n        writer.append(\"foo\")\n        writer.append(\"bar\")\n        writer.append(\"baz\")\n        assert 3 == len(list(writer))\n\n    def test_append(self, writer) -> None:\n        assert 0 == len(writer)\n        writer.append(\"hello, world!\")\n        assert 1 == len(writer)\n        assert isinstance(writer._parts[0][0], payload.Payload)\n\n    def test_append_with_headers(self, writer) -> None:\n        writer.append(\"hello, world!\", {\"x-foo\": \"bar\"})\n        assert 1 == len(writer)\n        assert \"x-foo\" in writer._parts[0][0].headers\n        assert writer._parts[0][0].headers[\"x-foo\"] == \"bar\"\n\n    def test_append_json(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"application/json\"\n\n    def test_append_part(self, writer) -> None:\n        part = payload.get_payload(\"test\", headers={CONTENT_TYPE: \"text/plain\"})\n        writer.append(part, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_json_overrides_content_type(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_form(self, writer) -> None:\n        writer.append_form({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_multipart(self, writer) -> None:\n        subwriter = aiohttp.MultipartWriter(boundary=\":\")\n        subwriter.append_json({\"foo\": \"bar\"})\n        writer.append(subwriter, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_set_content_disposition_after_append(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        part = writer.append(\"some-data\")\n        part.set_content_disposition(\"form-data\", name=\"method\")\n        assert 'name=\"method\"' in part.headers[CONTENT_DISPOSITION]\n\n    def test_automatic_content_disposition(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        writer.append_json(())\n        part = payload.StringPayload(\"foo\")\n        part.set_content_disposition(\"form-data\", name=\"second\")\n        writer.append_payload(part)\n        writer.append(\"foo\")\n\n        disps = tuple(p[0].headers[CONTENT_DISPOSITION] for p in writer._parts)\n        assert 'name=\"section-0\"' in disps[0]\n        assert 'name=\"second\"' in disps[1]\n        assert 'name=\"section-2\"' in disps[2]\n\n    def test_with(self) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            writer.append(\"foo\")\n            writer.append(b\"bar\")\n            writer.append_json({\"baz\": True})\n        assert 3 == len(writer)\n\n    def test_append_int_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1)\n\n    def test_append_float_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1.1)\n\n    def test_append_none_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(None)\n\n    async def test_write_preserves_content_disposition(self, buf, stream) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            part = writer.append(b\"foo\", headers={CONTENT_TYPE: \"test/passed\"})\n            part.set_content_disposition(\"form-data\", filename=\"bug\")\n        await writer.write(stream)\n\n        headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: test/passed\\r\\n\"\n            b\"Content-Length: 3\\r\\n\"\n            b\"Content-Disposition:\"\n            b' form-data; filename=\"bug\"'\n        )\n        assert message == b\"foo\\r\\n--:--\\r\\n\"\n\n    async def test_preserve_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_set_content_disposition_override(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_reset_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={CONTENT_TYPE: \"text/plain\"},\n                )\n\n            assert CONTENT_DISPOSITION in part.headers\n\n            part.set_content_disposition(\"attachments\", filename=\"bug.py\")\n\n            await writer.write(stream)\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain\\r\\n\"\n            b\"Content-Disposition:\"\n            b' attachments; filename=\"bug.py\"'\n        )\n\n\nasync def test_async_for_reader() -> None:\n    data = [{\"test\": \"passed\"}, 42, b\"plain text\", b\"aiohttp\\n\", b\"no epilogue\"]\n    with Stream(\n        b\"\\r\\n\".join(\n            [\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[0]).encode(),\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[1]).encode(),\n                b\"--:\",\n                b'Content-Type: multipart/related; boundary=\"::\"',\n                b\"\",\n                b\"--::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[2],\n                b\"--::\",\n                b'Content-Disposition: attachment; filename=\"aiohttp\"',\n                b\"Content-Type: text/plain\",\n                b\"Content-Length: 28\",\n                b\"Content-Encoding: gzip\",\n                b\"\",\n                b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03K\\xcc\\xcc\\xcf())\"\n                b\"\\xe0\\x02\\x00\\xd6\\x90\\xe2O\\x08\\x00\\x00\\x00\",\n                b\"--::\",\n                b'Content-Type: multipart/related; boundary=\":::\"',\n                b\"\",\n                b\"--:::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[4],\n                b\"--:::--\",\n                b\"--::--\",\n                b\"\",\n                b\"--:--\",\n                b\"\",\n            ]\n        )\n    ) as stream:\n        reader = aiohttp.MultipartReader(\n            headers={CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'},\n            content=stream,\n        )\n        idata = iter(data)\n\n        async def check(reader):\n            async for part in reader:\n                if isinstance(part, aiohttp.BodyPartReader):\n                    if part.headers[CONTENT_TYPE] == \"application/json\":\n                        assert next(idata) == (await part.json())\n                    else:\n                        assert next(idata) == await part.read(decode=True)\n                else:\n                    await check(part)\n\n        await check(reader)\n\n\nasync def test_async_for_bodypart() -> None:\n    with Stream(b\"foobarbaz\\r\\n--:--\") as stream:\n        part = aiohttp.BodyPartReader(boundary=b\"--:\", headers={}, content=stream)\n        async for data in part:\n            assert data == b\"foobarbaz\"\n",
            "header": {
                "file": {
                    "path": "tests/test_multipart.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "6fc9fe57",
                "new_commit_hash": "bbbc1c66",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/tests/test_multipart.py"
            },
            "plus_file": {
                "path": "b/tests/test_multipart.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 378,
                            "length": 6
                        },
                        "new_range": {
                            "start": 378,
                            "length": 17
                        },
                        "section": "class TestPartReader:"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        )",
                                "type": "context"
                            },
                            {
                                "content": "        assert result == expected",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    async def test_decode_with_content_transfer_encoding_base64(self) -> None:",
                                "type": "added"
                            },
                            {
                                "content": "        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:",
                                "type": "added"
                            },
                            {
                                "content": "            obj = aiohttp.BodyPartReader(",
                                "type": "added"
                            },
                            {
                                "content": "                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream",
                                "type": "added"
                            },
                            {
                                "content": "            )",
                                "type": "added"
                            },
                            {
                                "content": "            result = b\"\"",
                                "type": "added"
                            },
                            {
                                "content": "            while not obj.at_eof():",
                                "type": "added"
                            },
                            {
                                "content": "                chunk = await obj.read_chunk(size=6)",
                                "type": "added"
                            },
                            {
                                "content": "                result += obj.decode(chunk)",
                                "type": "added"
                            },
                            {
                                "content": "        assert b\"Time to Relax!\" == result",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))",
                                "type": "context"
                            },
                            {
                                "content": "    async def test_read_with_content_transfer_encoding_binary(",
                                "type": "context"
                            },
                            {
                                "content": "        self, encoding: str",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "tests/test_multipart.py",
                            "type": "class",
                            "name": "TestPartReader",
                            "content": "class TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n                result += obj.decode(chunk)\n        assert b\"Time to Relax!\" == result\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 121,
                            "end_lineno": 665,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "tests/test_multipart.py",
                            "type": "method",
                            "name": "TestPartReader.test_decode_with_content_transfer_encoding_base64",
                            "content": "class TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n                result += obj.decode(chunk)\n        assert b\"Time to Relax!\" == result\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 381,
                            "end_lineno": 390,
                            "parent": {
                                "file_name": "tests/test_multipart.py",
                                "type": "class",
                                "name": "TestPartReader",
                                "content": "class TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n                result += obj.decode(chunk)\n        assert b\"Time to Relax!\" == result\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 121,
                                "end_lineno": 665,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "2f7c45ebc0e2adee709815fc26264c7940b732fd^",
    "new_commit_hash": "2f7c45ebc0e2adee709815fc26264c7940b732fd",
    "commit_message": "Fix decoding base64 chunk for BodyPartReader (#3867) (#8688)\n\n(cherry picked from commit aeb01ce3bda7497d7cc6c434ac6806aca291e273)\r\n\r\n---------\r\n\r\nCo-authored-by: Yevhenii Hyzyla <hyzyla@gmail.com>\r\nCo-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>",
    "commit_date": "2024-08-12T22:43:14+01:00",
    "metadata": {}
}
{
    "repo_name": "aiohttp",
    "new_commit_hash": "2f7c45ebc0e2adee709815fc26264c7940b732fd",
    "test_file_codes": [
        "import asyncio\nimport io\nimport json\nimport pathlib\nimport sys\nimport zlib\nfrom unittest import mock\n\nimport pytest\n\nimport aiohttp\nfrom aiohttp import payload\nfrom aiohttp.hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom aiohttp.helpers import parse_mimetype\nfrom aiohttp.multipart import MultipartResponseWrapper\nfrom aiohttp.streams import StreamReader\nfrom aiohttp.test_utils import make_mocked_coro\n\nBOUNDARY = b\"--:\"\n\n\nnewline = b\"\\r\\n\"\n\n\n@pytest.fixture\ndef buf():\n    return bytearray()\n\n\n@pytest.fixture\ndef stream(buf):\n    writer = mock.Mock()\n\n    async def write(chunk):\n        buf.extend(chunk)\n\n    writer.write.side_effect = write\n    return writer\n\n\n@pytest.fixture\ndef writer():\n    return aiohttp.MultipartWriter(boundary=\":\")\n\n\nclass Response:\n    def __init__(self, headers, content):\n        self.headers = headers\n        self.content = content\n\n\nclass Stream:\n    def __init__(self, content):\n        self.content = io.BytesIO(content)\n\n    async def read(self, size=None):\n        return self.content.read(size)\n\n    def at_eof(self):\n        return self.content.tell() == len(self.content.getbuffer())\n\n    async def readline(self):\n        return self.content.readline()\n\n    def unread_data(self, data):\n        self.content = io.BytesIO(data + self.content.read())\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, exc_type, exc_value, traceback):\n        self.content.close()\n\n\nclass StreamWithShortenRead(Stream):\n    def __init__(self, content):\n        self._first = True\n        super().__init__(content)\n\n    async def read(self, size=None):\n        if size is not None and self._first:\n            self._first = False\n            size = size // 2\n        return await super().read(size)\n\n\nclass TestMultipartResponseWrapper:\n    def test_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.at_eof()\n        assert wrapper.resp.content.at_eof.called\n\n    async def test_next(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = False\n        await wrapper.next()\n        assert wrapper.stream.next.called\n\n    async def test_release(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        await wrapper.release()\n        assert wrapper.resp.release.called\n\n    async def test_release_when_stream_at_eof(self) -> None:\n        wrapper = MultipartResponseWrapper(mock.Mock(), mock.Mock())\n        wrapper.resp.release = make_mocked_coro(None)\n        wrapper.stream.next = make_mocked_coro(b\"\")\n        wrapper.stream.at_eof.return_value = True\n        await wrapper.next()\n        assert wrapper.stream.next.called\n        assert wrapper.resp.release.called\n\n\nclass TestPartReader:\n    async def test_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_next_next(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.next()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n            result = await obj.next()\n            assert result is None\n\n    async def test_read(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_at_eof(self) -> None:\n        with Stream(b\"--:\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            obj._at_eof = True\n            result = await obj.read_chunk()\n        assert b\"\" == result\n\n    async def test_read_chunk_without_content_length(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            c1 = await obj.read_chunk(8)\n            c2 = await obj.read_chunk(8)\n            c3 = await obj.read_chunk(8)\n        assert c1 + c2 == b\"Hello, world!\"\n        assert c3 == b\"\"\n\n    async def test_read_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, \"),\n                    prepare(b\"World\"),\n                    prepare(b\"!%s--:\" % newline),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(8)\n                assert c1 == b\"Hello, \"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"World\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"!\"\n\n    async def test_read_all_at_once(self) -> None:\n        data = b\"Hello, World!%s--:--%s\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk()\n            assert b\"Hello, World!\" == result\n            result = await obj.read_chunk()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_incomplete_body_chunked(self) -> None:\n        data = b\"Hello, World!%s--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = b\"\"\n            with pytest.raises(AssertionError):\n                for _ in range(4):\n                    result += await obj.read_chunk(7)\n        assert data == result\n\n    async def test_read_boundary_with_incomplete_chunk(self) -> None:\n        with Stream(b\"\") as stream:\n\n            def prepare(data):\n                return data\n\n            with mock.patch.object(\n                stream,\n                \"read\",\n                side_effect=[\n                    prepare(b\"Hello, World\"),\n                    prepare(b\"!%s\" % newline),\n                    prepare(b\"--:\"),\n                    prepare(b\"\"),\n                ],\n            ):\n                obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n                c1 = await obj.read_chunk(12)\n                assert c1 == b\"Hello, World\"\n                c2 = await obj.read_chunk(8)\n                assert c2 == b\"!\"\n                c3 = await obj.read_chunk(8)\n                assert c3 == b\"\"\n\n    async def test_multi_read_chunk(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read_chunk(8)\n            assert b\"Hello,\" == result\n            result = await obj.read_chunk(8)\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_chunk_properly_counts_read_bytes(self) -> None:\n        expected = b\".\" * 10\n        tail = b\"%s--:--\" % newline\n        size = len(expected)\n        with StreamWithShortenRead(expected + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": size},\n                stream,\n            )\n            result = bytearray()\n            while True:\n                chunk = await obj.read_chunk()\n                if not chunk:\n                    break\n                result.extend(chunk)\n        assert size == len(result)\n        assert b\".\" * size == result\n        assert obj.at_eof()\n\n    async def test_read_does_not_read_boundary(self) -> None:\n        data = b\"Hello, world!%s--:\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello, world!\" == result\n            assert b\"--:\" == (await stream.read())\n\n    async def test_multiread(self) -> None:\n        data = b\"Hello,%s--:%s%sworld!%s--:--\" % ((newline,) * 4)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello,\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_multiline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n            result = await obj.read()\n            assert b\"Hello\\n,\\r\\nworld!\" == result\n            result = await obj.read()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_read_respects_content_length(self) -> None:\n        data = b\".\" * 100500\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.read()\n            assert data == result\n            assert obj.at_eof()\n\n    async def test_read_with_content_encoding_gzip(self) -> None:\n        with Stream(\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n            b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"gzip\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_deflate(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_encoding_identity(self) -> None:\n        thing = (\n            b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x0b\\xc9\\xccMU\"\n            b\"(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00$\\xfb\\x9eV\\x0e\\x00\\x00\\x00\"\n        )\n        with Stream(thing + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"identity\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert thing == result\n\n    async def test_read_with_content_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"snappy\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VGltZSB0byBSZWxheCE=%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"base64\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert b\"Time to Relax!\" == result\n\n    async def test_read_with_content_transfer_encoding_quoted_printable(self) -> None:\n        with Stream(\n            b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n            b\" =D0=BC=D0=B8=D1=80!%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        expected = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        assert result == expected\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n                result += obj.decode(chunk)\n        assert b\"Time to Relax!\" == result\n\n    @pytest.mark.parametrize(\"encoding\", (\"binary\", \"8bit\", \"7bit\"))\n    async def test_read_with_content_transfer_encoding_binary(\n        self, encoding: str\n    ) -> None:\n        data = (\n            b\"\\xd0\\x9f\\xd1\\x80\\xd0\\xb8\\xd0\\xb2\\xd0\\xb5\\xd1\\x82,\"\n            b\" \\xd0\\xbc\\xd0\\xb8\\xd1\\x80!\"\n        )\n        with Stream(data + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: encoding},\n                stream,\n            )\n            result = await obj.read(decode=True)\n        assert data == result\n\n    async def test_read_with_content_transfer_encoding_unknown(self) -> None:\n        with Stream(b\"\\x0e4Time to Relax!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TRANSFER_ENCODING: \"unknown\"},\n                stream,\n            )\n            with pytest.raises(RuntimeError):\n                await obj.read(decode=True)\n\n    async def test_read_text(self) -> None:\n        with Stream(b\"Hello, world!%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Hello, world!\" == result\n\n    async def test_read_text_default_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"utf-8\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.text(encoding=\"cp1251\")\n        assert data == result\n\n    async def test_read_text_guess_encoding(self) -> None:\n        data = \"Привет, Мир!\"\n        tail = b\"%s--:--\" % newline\n        with Stream(data.encode(\"cp1251\") + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"text/plain;charset=cp1251\"},\n                stream,\n            )\n            result = await obj.text()\n        assert data == result\n\n    async def test_read_text_compressed(self) -> None:\n        data = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\" b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"text/plain\"},\n                stream,\n            )\n            result = await obj.text()\n        assert \"Time to Relax!\" == result\n\n    async def test_read_text_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(BOUNDARY, {CONTENT_TYPE: \"text/plain\"}, stream)\n            obj._at_eof = True\n            result = await obj.text()\n        assert \"\" == result\n\n    async def test_read_json(self) -> None:\n        with Stream(b'{\"test\": \"passed\"}%s--:--' % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json(encoding=\"cp1251\")\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_guess_encoding(self) -> None:\n        data = '{\"тест\": \"пассед\"}'.encode(\"cp1251\")\n        tail = b\"%s--:--\" % newline\n        with Stream(data + tail) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/json; charset=cp1251\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"тест\": \"пассед\"} == result\n\n    async def test_read_json_compressed(self) -> None:\n        with Stream(\n            b\"\\xabV*I-.Q\\xb2RP*H,.NMQ\\xaa\\x05\\x00\" b\"%s--:--\" % newline\n        ) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_ENCODING: \"deflate\", CONTENT_TYPE: \"application/json\"},\n                stream,\n            )\n            result = await obj.json()\n        assert {\"test\": \"passed\"} == result\n\n    async def test_read_json_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TYPE: \"application/json\"}, stream\n            )\n            obj._at_eof = True\n            result = await obj.json()\n        assert result is None\n\n    async def test_read_form(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_invalid_utf8(self) -> None:\n        invalid_unicode_byte = b\"\\xff\"\n        data = invalid_unicode_byte + b\"%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            with pytest.raises(\n                ValueError, match=\"data cannot be decoded with utf-8 encoding\"\n            ):\n                await obj.form()\n\n    async def test_read_form_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            result = await obj.form(encoding=\"cp1251\")\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_guess_encoding(self) -> None:\n        data = b\"foo=bar&foo=baz&boo=%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded; charset=utf-8\"},\n                stream,\n            )\n            result = await obj.form()\n        assert [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"\")] == result\n\n    async def test_read_form_while_closed(self) -> None:\n        with Stream(b\"\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {CONTENT_TYPE: \"application/x-www-form-urlencoded\"},\n                stream,\n            )\n            obj._at_eof = True\n            result = await obj.form()\n        assert not result\n\n    async def test_readline(self) -> None:\n        data = b\"Hello\\n,\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            result = await obj.readline()\n            assert b\"Hello\\n\" == result\n            result = await obj.readline()\n            assert b\",\\r\\n\" == result\n            result = await obj.readline()\n            assert b\"world!\" == result\n            result = await obj.readline()\n            assert b\"\" == result\n            assert obj.at_eof()\n\n    async def test_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n            await obj.release()\n            assert obj.at_eof()\n            assert remained == stream.content.read()\n\n    async def test_release_respects_content_length(self) -> None:\n        with Stream(b\".\" * 100500 + b\"%s--:--\" % newline) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {\"CONTENT-LENGTH\": 100500},\n                stream,\n            )\n            result = await obj.release()\n            assert result is None\n            assert obj.at_eof()\n\n    async def test_release_release(self) -> None:\n        data = b\"Hello,%s--:\\r\\n\\r\\nworld!%s--:--\" % (newline, newline)\n        remained = b\"--:\\r\\n\\r\\nworld!%s--:--\" % newline\n        with Stream(data) as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY,\n                {},\n                stream,\n            )\n            await obj.release()\n            await obj.release()\n            assert remained == stream.content.read()\n\n    async def test_filename(self) -> None:\n        part = aiohttp.BodyPartReader(\n            BOUNDARY, {CONTENT_DISPOSITION: \"attachment; filename=foo.html\"}, None\n        )\n        assert \"foo.html\" == part.filename\n\n    async def test_reading_long_part(self) -> None:\n        size = 2 * 2**16\n        protocol = mock.Mock(_reading_paused=False)\n        stream = StreamReader(protocol, 2**16, loop=asyncio.get_event_loop())\n        stream.feed_data(b\"0\" * size + b\"\\r\\n--:--\")\n        stream.feed_eof()\n        obj = aiohttp.BodyPartReader(BOUNDARY, {}, stream)\n        data = await obj.read()\n        assert len(data) == size\n\n\nclass TestMultipartReader:\n    def test_from_response(self) -> None:\n        with Stream(b\"--:%s\\r\\nhello%s--:--\" % (newline, newline)) as stream:\n            resp = Response(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = aiohttp.MultipartReader.from_response(resp)\n        assert isinstance(res, MultipartResponseWrapper)\n        assert isinstance(res.stream, aiohttp.MultipartReader)\n\n    def test_bad_boundary(self) -> None:\n        with Stream(b\"\") as stream:\n            resp = Response(\n                {CONTENT_TYPE: \"multipart/related;boundary=\" + \"a\" * 80}, stream\n            )\n            with pytest.raises(ValueError):\n                aiohttp.MultipartReader.from_response(resp)\n\n    def test_dispatch(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_bodypart(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader({CONTENT_TYPE: \"text/plain\"})\n        assert isinstance(res, reader.part_reader_cls)\n\n    def test_dispatch_multipart(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\" b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = reader._get_part_reader(\n                {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n            )\n        assert isinstance(res, reader.__class__)\n\n    def test_dispatch_custom_multipart_reader(self) -> None:\n        class CustomReader(aiohttp.MultipartReader):\n            pass\n\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n            Stream(\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"test\\r\\n\"\n                b\"----:--\\r\\n\"\n                b\"\\r\\n\"\n                b\"passed\\r\\n\"\n                b\"----:----\\r\\n\"\n                b\"--:--\"\n            ),\n        )\n        reader.multipart_reader_cls = CustomReader\n        res = reader._get_part_reader(\n            {CONTENT_TYPE: \"multipart/related;boundary=--:--\"}\n        )\n        assert isinstance(res, CustomReader)\n\n    async def test_emit_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            res = await reader.next()\n        assert isinstance(res, reader.part_reader_cls)\n\n    async def test_invalid_boundary(self) -> None:\n        with Stream(b\"---:%s\\r\\necho%s---:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(ValueError):\n                await reader.next()\n\n    @pytest.mark.skipif(sys.version_info < (3, 10), reason=\"Needs anext()\")\n    async def test_read_boundary_across_chunks(self) -> None:\n        class SplitBoundaryStream:\n            def __init__(self) -> None:\n                self.content = [\n                    b\"--foobar\\r\\n\\r\\n\",\n                    b\"Hello,\\r\\n-\",\n                    b\"-fo\",\n                    b\"ob\",\n                    b\"ar\\r\\n\",\n                    b\"\\r\\nwor\",\n                    b\"ld!\",\n                    b\"\\r\\n--f\",\n                    b\"oobar--\",\n                ]\n\n            async def read(self, size=None) -> bytes:\n                chunk = self.content.pop(0)\n                assert len(chunk) <= size\n                return chunk\n\n            def at_eof(self) -> bool:\n                return not self.content\n\n            async def readline(self) -> bytes:\n                line = b\"\"\n                while self.content and b\"\\n\" not in line:\n                    line += self.content.pop(0)\n                line, *extra = line.split(b\"\\n\", maxsplit=1)\n                if extra and extra[0]:\n                    self.content.insert(0, extra[0])\n                return line + b\"\\n\"\n\n            def unread_data(self, data: bytes) -> None:\n                if self.content:\n                    self.content[0] = data + self.content[0]\n                else:\n                    self.content.append(data)\n\n        stream = SplitBoundaryStream()\n        reader = aiohttp.MultipartReader(\n            {CONTENT_TYPE: 'multipart/related;boundary=\"foobar\"'}, stream\n        )\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"Hello,\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        part = await anext(reader)\n        result = await part.read_chunk(10)\n        assert result == b\"world!\"\n        result = await part.read_chunk(10)\n        assert result == b\"\"\n        assert part.at_eof()\n\n        with pytest.raises(StopAsyncIteration):\n            await anext(reader)\n\n    async def test_release(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Type: multipart/related;boundary=--:--\",\n                    b\"\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"test\",\n                    b\"----:--\",\n                    b\"\",\n                    b\"passed\",\n                    b\"----:----\",\n                    b\"\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/mixed;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_release(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            await reader.release()\n            assert reader.at_eof()\n\n    async def test_release_next(self) -> None:\n        with Stream(b\"--:%s\\r\\necho%s--:--\" % (newline, newline)) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            await reader.release()\n            assert reader.at_eof()\n            res = await reader.next()\n            assert res is None\n\n    async def test_second_next_releases_previous_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_release_without_read_the_last_object(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            second = await reader.next()\n            third = await reader.next()\n\n            assert first.at_eof()\n            assert second.at_eof()\n            assert second.at_eof()\n            assert third is None\n\n    async def test_read_chunk_by_length_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"Content-Length: 4\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"Content-Length: 6\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    read_part += await part.read_chunk(3)\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"test\", b\"passed\"]\n\n    async def test_read_chunk_from_stream_doesnt_breaks_reader(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"--:\",\n                    b\"\",\n                    b\"chunk\",\n                    b\"--:\",\n                    b\"\",\n                    b\"two_chunks\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            body_parts = []\n            while True:\n                read_part = b\"\"\n                part = await reader.next()\n                if part is None:\n                    break\n                while not part.at_eof():\n                    chunk = await part.read_chunk(5)\n                    assert chunk\n                    read_part += chunk\n                body_parts.append(read_part)\n\n        assert body_parts == [b\"chunk\", b\"two_chunks\"]\n\n    async def test_reading_skips_prelude(self) -> None:\n        with Stream(\n            newline.join(\n                [\n                    b\"Multi-part data is not supported.\",\n                    b\"\",\n                    b\"--:\",\n                    b\"\",\n                    b\"test\",\n                    b\"--:\",\n                    b\"\",\n                    b\"passed\",\n                    b\"--:--\",\n                ]\n            )\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/related;boundary=\":\"'},\n                stream,\n            )\n            first = await reader.next()\n            assert isinstance(first, aiohttp.BodyPartReader)\n            second = await reader.next()\n\n            assert first.at_eof()\n            assert not second.at_eof()\n\n    async def test_read_form_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"ascii\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain;charset=UTF-8\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field2\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field3\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            field1 = await reader.next()\n            assert field1.name == \"field1\"\n            assert field1.get_charset(\"default\") == \"ascii\"\n            field2 = await reader.next()\n            assert field2.name == \"field2\"\n            assert field2.get_charset(\"default\") == \"UTF-8\"\n            field3 = await reader.next()\n            assert field3.name == \"field3\"\n            assert field3.get_charset(\"default\") == \"ascii\"\n\n    async def test_read_form_invalid_default_encoding(self) -> None:\n        with Stream(\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"_charset_\"\\r\\n\\r\\n'\n            b\"this-value-is-too-long-to-be-a-charset\"\n            b\"\\r\\n\"\n            b\"--:\\r\\n\"\n            b'Content-Disposition: form-data; name=\"field1\"\\r\\n\\r\\n'\n            b\"foo\"\n            b\"\\r\\n\"\n        ) as stream:\n            reader = aiohttp.MultipartReader(\n                {CONTENT_TYPE: 'multipart/form-data;boundary=\":\"'},\n                stream,\n            )\n            with pytest.raises(RuntimeError, match=\"Invalid default charset\"):\n                await reader.next()\n\n\nasync def test_writer(writer) -> None:\n    assert writer.size == 7\n    assert writer.boundary == \":\"\n\n\nasync def test_writer_serialize_io_chunk(buf, stream, writer) -> None:\n    with io.BytesIO(b\"foobarbaz\") as file_handle:\n        writer.append(file_handle)\n        await writer.write(stream)\n    assert (\n        buf == b\"--:\\r\\nContent-Type: application/octet-stream\"\n        b\"\\r\\nContent-Length: 9\\r\\n\\r\\nfoobarbaz\\r\\n--:--\\r\\n\"\n    )\n\n\nasync def test_writer_serialize_json(buf, stream, writer) -> None:\n    writer.append_json({\"привет\": \"мир\"})\n    await writer.write(stream)\n    assert (\n        b'{\"\\\\u043f\\\\u0440\\\\u0438\\\\u0432\\\\u0435\\\\u0442\":'\n        b' \"\\\\u043c\\\\u0438\\\\u0440\"}' in buf\n    )\n\n\nasync def test_writer_serialize_form(buf, stream, writer) -> None:\n    data = [(\"foo\", \"bar\"), (\"foo\", \"baz\"), (\"boo\", \"zoo\")]\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"foo=bar&foo=baz&boo=zoo\" in buf\n\n\nasync def test_writer_serialize_form_dict(buf, stream, writer) -> None:\n    data = {\"hello\": \"мир\"}\n    writer.append_form(data)\n    await writer.write(stream)\n\n    assert b\"hello=%D0%BC%D0%B8%D1%80\" in buf\n\n\nasync def test_writer_write(buf, stream, writer) -> None:\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n\n    sub_multipart = aiohttp.MultipartWriter(boundary=\"::\")\n    sub_multipart.append(\"nested content\")\n    sub_multipart.headers[\"X-CUSTOM\"] = \"test\"\n    writer.append(sub_multipart)\n    await writer.write(stream)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b'Content-Type: multipart/mixed; boundary=\"::\"\\r\\n'\n        b\"X-CUSTOM: test\\r\\nContent-Length: 93\\r\\n\\r\\n\"\n        b\"--::\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 14\\r\\n\\r\\n\"\n        b\"nested content\\r\\n\"\n        b\"--::--\\r\\n\"\n        b\"\\r\\n\"\n        b\"--:--\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_close_boundary(buf, stream) -> None:\n    writer = aiohttp.MultipartWriter(boundary=\":\")\n    writer.append(\"foo-bar-baz\")\n    writer.append_json({\"test\": \"passed\"})\n    writer.append_form({\"test\": \"passed\"})\n    writer.append_form([(\"one\", 1), (\"two\", 2)])\n    await writer.write(stream, close_boundary=False)\n\n    assert (\n        b\"--:\\r\\n\"\n        b\"Content-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"foo-bar-baz\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/json\\r\\n\"\n        b\"Content-Length: 18\\r\\n\\r\\n\"\n        b'{\"test\": \"passed\"}'\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"test=passed\"\n        b\"\\r\\n\"\n        b\"--:\\r\\n\"\n        b\"Content-Type: application/x-www-form-urlencoded\\r\\n\"\n        b\"Content-Length: 11\\r\\n\\r\\n\"\n        b\"one=1&two=2\"\n        b\"\\r\\n\"\n    ) == bytes(buf)\n\n\nasync def test_writer_write_no_parts(buf, stream, writer) -> None:\n    await writer.write(stream)\n    assert b\"--:--\\r\\n\" == bytes(buf)\n\n\nasync def test_writer_serialize_with_content_encoding_gzip(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"gzip\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: gzip\" == headers\n    )\n\n    decompressor = zlib.decompressobj(wbits=16 + zlib.MAX_WBITS)\n    data = decompressor.decompress(message.split(b\"\\r\\n\")[0])\n    data += decompressor.flush()\n    assert b\"Time to Relax!\" == data\n\n\nasync def test_writer_serialize_with_content_encoding_deflate(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"deflate\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Encoding: deflate\" == headers\n    )\n\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\\r\\n--:--\\r\\n\"\n    assert thing == message\n\n\nasync def test_writer_serialize_with_content_encoding_identity(buf, stream, writer):\n    thing = b\"\\x0b\\xc9\\xccMU(\\xc9W\\x08J\\xcdI\\xacP\\x04\\x00\"\n    writer.append(thing, {CONTENT_ENCODING: \"identity\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: application/octet-stream\\r\\n\"\n        b\"Content-Encoding: identity\\r\\n\"\n        b\"Content-Length: 16\" == headers\n    )\n\n    assert thing == message.split(b\"\\r\\n\")[0]\n\n\ndef test_writer_serialize_with_content_encoding_unknown(buf, stream, writer):\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_ENCODING: \"snappy\"})\n\n\nasync def test_writer_with_content_transfer_encoding_base64(buf, stream, writer):\n    writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"base64\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: base64\" == headers\n    )\n\n    assert b\"VGltZSB0byBSZWxheCE=\" == message.split(b\"\\r\\n\")[0]\n\n\nasync def test_writer_content_transfer_encoding_quote_printable(buf, stream, writer):\n    writer.append(\"Привет, мир!\", {CONTENT_TRANSFER_ENCODING: \"quoted-printable\"})\n    await writer.write(stream)\n    headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n    assert (\n        b\"--:\\r\\nContent-Type: text/plain; charset=utf-8\\r\\n\"\n        b\"Content-Transfer-Encoding: quoted-printable\" == headers\n    )\n\n    assert (\n        b\"=D0=9F=D1=80=D0=B8=D0=B2=D0=B5=D1=82,\"\n        b\" =D0=BC=D0=B8=D1=80!\" == message.split(b\"\\r\\n\")[0]\n    )\n\n\ndef test_writer_content_transfer_encoding_unknown(buf, stream, writer) -> None:\n    with pytest.raises(RuntimeError):\n        writer.append(\"Time to Relax!\", {CONTENT_TRANSFER_ENCODING: \"unknown\"})\n\n\nclass TestMultipartWriter:\n    def test_default_subtype(self, writer) -> None:\n        mimetype = parse_mimetype(writer.headers.get(CONTENT_TYPE))\n\n        assert \"multipart\" == mimetype.type\n        assert \"mixed\" == mimetype.subtype\n\n    def test_unquoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=\"abc123\")\n        expected = {CONTENT_TYPE: \"multipart/mixed; boundary=abc123\"}\n        assert expected == writer.headers\n\n    def test_quoted_boundary(self) -> None:\n        writer = aiohttp.MultipartWriter(boundary=R\"\\\"\")\n        expected = {CONTENT_TYPE: R'multipart/mixed; boundary=\"\\\\\\\"\"'}\n        assert expected == writer.headers\n\n    def test_bad_boundary(self) -> None:\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"тест\")\n        with pytest.raises(ValueError):\n            aiohttp.MultipartWriter(boundary=\"test\\n\")\n\n    def test_default_headers(self, writer) -> None:\n        expected = {CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'}\n        assert expected == writer.headers\n\n    def test_iter_parts(self, writer) -> None:\n        writer.append(\"foo\")\n        writer.append(\"bar\")\n        writer.append(\"baz\")\n        assert 3 == len(list(writer))\n\n    def test_append(self, writer) -> None:\n        assert 0 == len(writer)\n        writer.append(\"hello, world!\")\n        assert 1 == len(writer)\n        assert isinstance(writer._parts[0][0], payload.Payload)\n\n    def test_append_with_headers(self, writer) -> None:\n        writer.append(\"hello, world!\", {\"x-foo\": \"bar\"})\n        assert 1 == len(writer)\n        assert \"x-foo\" in writer._parts[0][0].headers\n        assert writer._parts[0][0].headers[\"x-foo\"] == \"bar\"\n\n    def test_append_json(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"application/json\"\n\n    def test_append_part(self, writer) -> None:\n        part = payload.get_payload(\"test\", headers={CONTENT_TYPE: \"text/plain\"})\n        writer.append(part, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_json_overrides_content_type(self, writer) -> None:\n        writer.append_json({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_form(self, writer) -> None:\n        writer.append_form({\"foo\": \"bar\"}, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_append_multipart(self, writer) -> None:\n        subwriter = aiohttp.MultipartWriter(boundary=\":\")\n        subwriter.append_json({\"foo\": \"bar\"})\n        writer.append(subwriter, {CONTENT_TYPE: \"test/passed\"})\n        assert 1 == len(writer)\n        part = writer._parts[0][0]\n        assert part.headers[CONTENT_TYPE] == \"test/passed\"\n\n    def test_set_content_disposition_after_append(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        part = writer.append(\"some-data\")\n        part.set_content_disposition(\"form-data\", name=\"method\")\n        assert 'name=\"method\"' in part.headers[CONTENT_DISPOSITION]\n\n    def test_automatic_content_disposition(self):\n        writer = aiohttp.MultipartWriter(\"form-data\")\n        writer.append_json(())\n        part = payload.StringPayload(\"foo\")\n        part.set_content_disposition(\"form-data\", name=\"second\")\n        writer.append_payload(part)\n        writer.append(\"foo\")\n\n        disps = tuple(p[0].headers[CONTENT_DISPOSITION] for p in writer._parts)\n        assert 'name=\"section-0\"' in disps[0]\n        assert 'name=\"second\"' in disps[1]\n        assert 'name=\"section-2\"' in disps[2]\n\n    def test_with(self) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            writer.append(\"foo\")\n            writer.append(b\"bar\")\n            writer.append_json({\"baz\": True})\n        assert 3 == len(writer)\n\n    def test_append_int_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1)\n\n    def test_append_float_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(1.1)\n\n    def test_append_none_not_allowed(self) -> None:\n        with pytest.raises(TypeError):\n            with aiohttp.MultipartWriter(boundary=\":\") as writer:\n                writer.append(None)\n\n    async def test_write_preserves_content_disposition(self, buf, stream) -> None:\n        with aiohttp.MultipartWriter(boundary=\":\") as writer:\n            part = writer.append(b\"foo\", headers={CONTENT_TYPE: \"test/passed\"})\n            part.set_content_disposition(\"form-data\", filename=\"bug\")\n        await writer.write(stream)\n\n        headers, message = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: test/passed\\r\\n\"\n            b\"Content-Length: 3\\r\\n\"\n            b\"Content-Disposition:\"\n            b' form-data; filename=\"bug\"'\n        )\n        assert message == b\"foo\\r\\n--:--\\r\\n\"\n\n    async def test_preserve_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_set_content_disposition_override(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={\n                        CONTENT_DISPOSITION: 'attachments; filename=\"bug.py\"',\n                        CONTENT_TYPE: \"text/python\",\n                    },\n                )\n            await writer.write(stream)\n\n        assert part.headers[CONTENT_TYPE] == \"text/python\"\n        assert part.headers[CONTENT_DISPOSITION] == ('attachments; filename=\"bug.py\"')\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/python\\r\\n\"\n            b'Content-Disposition: attachments; filename=\"bug.py\"'\n        )\n\n    async def test_reset_content_disposition_header(self, buf, stream):\n        # https://github.com/aio-libs/aiohttp/pull/3475#issuecomment-451072381\n        with pathlib.Path(__file__).open(\"rb\") as fobj:\n            with aiohttp.MultipartWriter(\"form-data\", boundary=\":\") as writer:\n                part = writer.append(\n                    fobj,\n                    headers={CONTENT_TYPE: \"text/plain\"},\n                )\n\n            assert CONTENT_DISPOSITION in part.headers\n\n            part.set_content_disposition(\"attachments\", filename=\"bug.py\")\n\n            await writer.write(stream)\n\n        headers, _ = bytes(buf).split(b\"\\r\\n\\r\\n\", 1)\n\n        assert headers == (\n            b\"--:\\r\\n\"\n            b\"Content-Type: text/plain\\r\\n\"\n            b\"Content-Disposition:\"\n            b' attachments; filename=\"bug.py\"'\n        )\n\n\nasync def test_async_for_reader() -> None:\n    data = [{\"test\": \"passed\"}, 42, b\"plain text\", b\"aiohttp\\n\", b\"no epilogue\"]\n    with Stream(\n        b\"\\r\\n\".join(\n            [\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[0]).encode(),\n                b\"--:\",\n                b\"Content-Type: application/json\",\n                b\"\",\n                json.dumps(data[1]).encode(),\n                b\"--:\",\n                b'Content-Type: multipart/related; boundary=\"::\"',\n                b\"\",\n                b\"--::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[2],\n                b\"--::\",\n                b'Content-Disposition: attachment; filename=\"aiohttp\"',\n                b\"Content-Type: text/plain\",\n                b\"Content-Length: 28\",\n                b\"Content-Encoding: gzip\",\n                b\"\",\n                b\"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03K\\xcc\\xcc\\xcf())\"\n                b\"\\xe0\\x02\\x00\\xd6\\x90\\xe2O\\x08\\x00\\x00\\x00\",\n                b\"--::\",\n                b'Content-Type: multipart/related; boundary=\":::\"',\n                b\"\",\n                b\"--:::\",\n                b\"Content-Type: text/plain\",\n                b\"\",\n                data[4],\n                b\"--:::--\",\n                b\"--::--\",\n                b\"\",\n                b\"--:--\",\n                b\"\",\n            ]\n        )\n    ) as stream:\n        reader = aiohttp.MultipartReader(\n            headers={CONTENT_TYPE: 'multipart/mixed; boundary=\":\"'},\n            content=stream,\n        )\n        idata = iter(data)\n\n        async def check(reader):\n            async for part in reader:\n                if isinstance(part, aiohttp.BodyPartReader):\n                    if part.headers[CONTENT_TYPE] == \"application/json\":\n                        assert next(idata) == (await part.json())\n                    else:\n                        assert next(idata) == await part.read(decode=True)\n                else:\n                    await check(part)\n\n        await check(reader)\n\n\nasync def test_async_for_bodypart() -> None:\n    with Stream(b\"foobarbaz\\r\\n--:--\") as stream:\n        part = aiohttp.BodyPartReader(boundary=b\"--:\", headers={}, content=stream)\n        async for data in part:\n            assert data == b\"foobarbaz\"\n",
        "import asyncio\nimport base64\nimport os\nimport socket\nimport ssl\nimport sys\nfrom hashlib import md5, sha1, sha256\nfrom pathlib import Path\nfrom tempfile import TemporaryDirectory\nfrom typing import Any\nfrom unittest import mock\nfrom uuid import uuid4\n\nimport pytest\n\nfrom aiohttp.http import WS_KEY\nfrom aiohttp.test_utils import loop_context\n\ntry:\n    import trustme\n\n    # Check if the CA is available in runtime, MacOS on Py3.10 fails somehow\n    trustme.CA()\n\n    TRUSTME: bool = True\nexcept ImportError:\n    TRUSTME = False\n\npytest_plugins = [\"aiohttp.pytest_plugin\", \"pytester\"]\n\nIS_HPUX = sys.platform.startswith(\"hp-ux\")\nIS_LINUX = sys.platform.startswith(\"linux\")\n\n\n@pytest.fixture\ndef tls_certificate_authority():\n    if not TRUSTME:\n        pytest.xfail(\"trustme is not supported\")\n    return trustme.CA()\n\n\n@pytest.fixture\ndef tls_certificate(tls_certificate_authority):\n    return tls_certificate_authority.issue_cert(\n        \"localhost\",\n        \"xn--prklad-4va.localhost\",\n        \"127.0.0.1\",\n        \"::1\",\n    )\n\n\n@pytest.fixture\ndef ssl_ctx(tls_certificate):\n    ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\n    tls_certificate.configure_cert(ssl_ctx)\n    return ssl_ctx\n\n\n@pytest.fixture\ndef client_ssl_ctx(tls_certificate_authority):\n    ssl_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)\n    tls_certificate_authority.configure_trust(ssl_ctx)\n    return ssl_ctx\n\n\n@pytest.fixture\ndef tls_ca_certificate_pem_path(tls_certificate_authority):\n    with tls_certificate_authority.cert_pem.tempfile() as ca_cert_pem:\n        yield ca_cert_pem\n\n\n@pytest.fixture\ndef tls_certificate_pem_path(tls_certificate):\n    with tls_certificate.private_key_and_cert_chain_pem.tempfile() as cert_pem:\n        yield cert_pem\n\n\n@pytest.fixture\ndef tls_certificate_pem_bytes(tls_certificate):\n    return tls_certificate.cert_chain_pems[0].bytes()\n\n\n@pytest.fixture\ndef tls_certificate_fingerprint_sha256(tls_certificate_pem_bytes):\n    tls_cert_der = ssl.PEM_cert_to_DER_cert(tls_certificate_pem_bytes.decode())\n    return sha256(tls_cert_der).digest()\n\n\n@pytest.fixture\ndef unix_sockname(tmp_path, tmp_path_factory):\n    \"\"\"Generate an fs path to the UNIX domain socket for testing.\n\n    N.B. Different OS kernels have different fs path length limitations\n    for it. For Linux, it's 108, for HP-UX it's 92 (or higher) depending\n    on its version. For for most of the BSDs (Open, Free, macOS) it's\n    mostly 104 but sometimes it can be down to 100.\n\n    Ref: https://github.com/aio-libs/aiohttp/issues/3572\n    \"\"\"\n    if not hasattr(socket, \"AF_UNIX\"):\n        pytest.skip(\"requires UNIX sockets\")\n\n    max_sock_len = 92 if IS_HPUX else 108 if IS_LINUX else 100\n    \"\"\"Amount of bytes allocated for the UNIX socket path by OS kernel.\n\n    Ref: https://unix.stackexchange.com/a/367012/27133\n    \"\"\"\n\n    sock_file_name = \"unix.sock\"\n    unique_prefix = f\"{uuid4()!s}-\"\n    unique_prefix_len = len(unique_prefix.encode())\n\n    root_tmp_dir = Path(\"/tmp\").resolve()\n    os_tmp_dir = Path(os.getenv(\"TMPDIR\", \"/tmp\")).resolve()\n    original_base_tmp_path = Path(\n        str(tmp_path_factory.getbasetemp()),\n    ).resolve()\n\n    original_base_tmp_path_hash = md5(\n        str(original_base_tmp_path).encode(),\n    ).hexdigest()\n\n    def make_tmp_dir(base_tmp_dir):\n        return TemporaryDirectory(\n            dir=str(base_tmp_dir),\n            prefix=\"pt-\",\n            suffix=f\"-{original_base_tmp_path_hash!s}\",\n        )\n\n    def assert_sock_fits(sock_path):\n        sock_path_len = len(sock_path.encode())\n        # exit-check to verify that it's correct and simplify debugging\n        # in the future\n        assert sock_path_len <= max_sock_len, (\n            \"Suggested UNIX socket ({sock_path}) is {sock_path_len} bytes \"\n            \"long but the current kernel only has {max_sock_len} bytes \"\n            \"allocated to hold it so it must be shorter. \"\n            \"See https://github.com/aio-libs/aiohttp/issues/3572 \"\n            \"for more info.\"\n        ).format_map(locals())\n\n    paths = original_base_tmp_path, os_tmp_dir, root_tmp_dir\n    unique_paths = [p for n, p in enumerate(paths) if p not in paths[:n]]\n    paths_num = len(unique_paths)\n\n    for num, tmp_dir_path in enumerate(paths, 1):\n        with make_tmp_dir(tmp_dir_path) as tmpd:\n            tmpd = Path(tmpd).resolve()\n            sock_path = str(tmpd / sock_file_name)\n            sock_path_len = len(sock_path.encode())\n\n            if num >= paths_num:\n                # exit-check to verify that it's correct and simplify\n                # debugging in the future\n                assert_sock_fits(sock_path)\n\n            if sock_path_len <= max_sock_len:\n                if max_sock_len - sock_path_len >= unique_prefix_len:\n                    # If we're lucky to have extra space in the path,\n                    # let's also make it more unique\n                    sock_path = str(tmpd / \"\".join((unique_prefix, sock_file_name)))\n                    # Double-checking it:\n                    assert_sock_fits(sock_path)\n                yield sock_path\n                return\n\n\n@pytest.fixture\ndef pipe_name():\n    name = rf\"\\\\.\\pipe\\{uuid4().hex}\"\n    return name\n\n\n@pytest.fixture\ndef create_mocked_conn(loop: Any):\n    def _proto_factory(conn_closing_result=None, **kwargs):\n        proto = mock.Mock(**kwargs)\n        proto.closed = loop.create_future()\n        proto.closed.set_result(conn_closing_result)\n        return proto\n\n    yield _proto_factory\n\n\n@pytest.fixture\ndef selector_loop():\n    policy = asyncio.WindowsSelectorEventLoopPolicy()\n    asyncio.set_event_loop_policy(policy)\n\n    with loop_context(policy.new_event_loop) as _loop:\n        asyncio.set_event_loop(_loop)\n        yield _loop\n\n\n@pytest.fixture\ndef netrc_contents(\n    tmp_path: Path,\n    monkeypatch: pytest.MonkeyPatch,\n    request: pytest.FixtureRequest,\n):\n    \"\"\"\n    Prepare :file:`.netrc` with given contents.\n\n    Monkey-patches :envvar:`NETRC` to point to created file.\n    \"\"\"\n    netrc_contents = getattr(request, \"param\", None)\n\n    netrc_file_path = tmp_path / \".netrc\"\n    if netrc_contents is not None:\n        netrc_file_path.write_text(netrc_contents)\n\n    monkeypatch.setenv(\"NETRC\", str(netrc_file_path))\n\n    return netrc_file_path\n\n\n@pytest.fixture\ndef start_connection():\n    with mock.patch(\n        \"aiohttp.connector.aiohappyeyeballs.start_connection\",\n        autospec=True,\n        spec_set=True,\n    ) as start_connection_mock:\n        yield start_connection_mock\n\n\n@pytest.fixture\ndef key_data():\n    return os.urandom(16)\n\n\n@pytest.fixture\ndef key(key_data: Any):\n    return base64.b64encode(key_data)\n\n\n@pytest.fixture\ndef ws_key(key: Any):\n    return base64.b64encode(sha1(key + WS_KEY).digest()).decode()\n"
    ],
    "test_file_names": [
        "test_1.py",
        "conftest.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "re-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/requirements/cython.txt\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/hdrs.py\n./tools/gen.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_helpers.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_http_parser.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_http_writer.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_websocket.pyx\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_helpers.pyi\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_cparser.pxd\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/_find_header.pxd\ncython -3 -o aiohttp/_helpers.c aiohttp/_helpers.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_http_parser.c aiohttp/_http_parser.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_http_writer.c aiohttp/_http_writer.pyx -I aiohttp -Werror\ncython -3 -o aiohttp/_websocket.c aiohttp/_websocket.pyx -I aiohttp -Werror\ncd vendor/llhttp; npm ci\n\n> llhttp@9.2.1 prepare\n> npm run clean && npm run build-ts\n\n\n> llhttp@9.2.1 clean\n> rm -rf lib && rm -rf test/tmp\n\n\n> llhttp@9.2.1 build-ts\n> tsc\n\n\nadded 213 packages, and audited 214 packages in 4s\n\n41 packages are looking for funding\n  run `npm fund` for details\n\n5 vulnerabilities (3 moderate, 2 high)\n\nTo address issues that do not require attention, run:\n  npm audit fix\n\nSome issues need review, and may require choosing\na different dependency.\n\nRun `npm audit` for details.\nmake -C vendor/llhttp generate\nmake[1]: Entering directory '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/vendor/llhttp'\nnpx ts-node bin/generate.ts\nmake[1]: Leaving directory '/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/vendor/llhttp'\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/__init__.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/abc.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/base_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/client.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/client_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/client_proto.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/client_reqrep.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/client_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/compression_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/connector.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/cookiejar.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/formdata.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/http.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/http_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/http_parser.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/http_websocket.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/http_writer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/locks.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/multipart.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/payload.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/payload_streamer.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/pytest_plugin.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/resolver.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/streams.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/tcp_helpers.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/test_utils.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/tracing.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/typedefs.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_app.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_exceptions.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_fileresponse.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_log.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_middlewares.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_protocol.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_request.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_response.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_routedef.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_runner.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_server.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_urldispatcher.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/web_ws.py\nre-hash /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/worker.py\nuv pip install -e . -c requirements/runtime-deps.txt\n",
    "setup_res_stderr": "Using CPython 3.9.21\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 1 package in 2ms\nPrepared 1 package in 0.26ms\nInstalled 1 package in 20ms\n + pip==24.3.1\nResolved 2 packages in 11ms\nInstalled 2 packages in 23ms\n + cython==3.0.11\n + multidict==6.0.5\nResolved 96 packages in 45ms\nUninstalled 1 package in 8ms\nInstalled 95 packages in 174ms\n + aiodns==3.2.0\n + aiohappyeyeballs==2.3.5\n + aiohttp-theme==0.1.6\n + aioredis==2.0.1\n + aiosignal==1.3.1\n + alabaster==0.7.13\n + annotated-types==0.5.0\n + async-timeout==4.0.3\n + attrs==24.2.0\n + babel==2.12.1\n + blockdiag==3.0.0\n + brotli==1.1.0\n + build==1.0.3\n + certifi==2023.7.22\n + cffi==1.15.1\n + cfgv==3.3.1\n + charset-normalizer==3.2.0\n + cherry-picker==2.2.0\n + click==8.1.6\n + coverage==7.6.1\n + cryptography==41.0.3\n + distlib==0.3.7\n + docutils==0.20.1\n + exceptiongroup==1.1.2\n + filelock==3.12.2\n + freezegun==1.5.1\n + frozenlist==1.4.1\n + funcparserlib==1.0.1\n + gidgethub==5.3.0\n + gunicorn==23.0.0\n + identify==2.5.26\n + idna==3.4\n + imagesize==1.4.1\n + importlib-metadata==7.0.0\n + importlib-resources==6.1.1\n + incremental==22.10.0\n + iniconfig==2.0.0\n + jinja2==3.1.2\n + markupsafe==2.1.3\n + mypy==1.11.1\n + mypy-extensions==1.0.0\n + nodeenv==1.8.0\n + packaging==23.1\n + pillow==9.5.0\n - pip==24.3.1\n + pip==23.2.1\n + pip-tools==7.4.1\n + platformdirs==3.10.0\n + pluggy==1.5.0\n + pre-commit==3.5.0\n + proxy-py==2.4.5\n + pycares==4.3.0\n + pycparser==2.21\n + pydantic==2.2.0\n + pydantic-core==2.6.0\n + pygments==2.15.1\n + pyjwt==2.8.0\n + pyproject-hooks==1.0.0\n + pytest==8.3.2\n + pytest-cov==5.0.0\n + pytest-mock==3.14.0\n + python-dateutil==2.8.2\n + python-on-whales==0.72.0\n + pyyaml==6.0.1\n + re-assert==1.1.0\n + regex==2023.6.3\n + requests==2.31.0\n + setuptools==68.0.0\n + setuptools-git==1.2\n + six==1.16.0\n + slotscheck==0.19.0\n + snowballstemmer==2.2.0\n + sphinx==7.1.2\n + sphinxcontrib-applehelp==1.0.4\n + sphinxcontrib-blockdiag==3.0.0\n + sphinxcontrib-devhelp==1.0.2\n + sphinxcontrib-htmlhelp==2.0.1\n + sphinxcontrib-jsmath==1.0.1\n + sphinxcontrib-qthelp==1.0.3\n + sphinxcontrib-serializinghtml==1.1.5\n + sphinxcontrib-towncrier==0.4.0a0\n + tomli==2.0.1\n + towncrier==23.11.0\n + tqdm==4.65.0\n + trustme==1.1.0\n + typer==0.9.0\n + typing-extensions==4.11.0\n + uritemplate==4.1.1\n + urllib3==2.0.4\n + uvloop==0.19.0\n + virtualenv==20.24.2\n + wait-for-it==2.2.2\n + webcolors==1.13\n + wheel==0.41.0\n + yarl==1.9.4\n + zipp==3.17.0\nResolved 9 packages in 1.63s\nPrepared 1 package in 16.60s\nInstalled 1 package in 0.64ms\n + aiohttp==3.11.0.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd)\nResolved 24 packages in 13ms\nInstalled 5 packages in 6ms\n + async-generator==1.10\n + brotlipy==0.7.0\n + chardet==5.2.0\n + multdict==0.0.5\n + pytest-asyncio==0.25.0\n",
    "new_commit_res_code": 0,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.2, pluggy-1.5.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd\nconfigfile: setup.cfg\nplugins: cov-5.0.0, asyncio-0.25.0, mock-3.14.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollecting ... collected 111 items\n\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_at_eof PASSED    [  0%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_next PASSED      [  1%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_release PASSED   [  2%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_release_when_stream_at_eof PASSED [  3%]\nr2e_tests/test_1.py::TestPartReader::test_next PASSED                    [  4%]\nr2e_tests/test_1.py::TestPartReader::test_next_next PASSED               [  5%]\nr2e_tests/test_1.py::TestPartReader::test_read PASSED                    [  6%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_at_eof PASSED       [  7%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_without_content_length PASSED [  8%]\nr2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk PASSED   [  9%]\nr2e_tests/test_1.py::TestPartReader::test_read_all_at_once PASSED        [  9%]\nr2e_tests/test_1.py::TestPartReader::test_read_incomplete_body_chunked PASSED [ 10%]\nr2e_tests/test_1.py::TestPartReader::test_read_boundary_with_incomplete_chunk PASSED [ 11%]\nr2e_tests/test_1.py::TestPartReader::test_multi_read_chunk PASSED        [ 12%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_properly_counts_read_bytes PASSED [ 13%]\nr2e_tests/test_1.py::TestPartReader::test_read_does_not_read_boundary PASSED [ 14%]\nr2e_tests/test_1.py::TestPartReader::test_multiread PASSED               [ 15%]\nr2e_tests/test_1.py::TestPartReader::test_read_multiline PASSED          [ 16%]\nr2e_tests/test_1.py::TestPartReader::test_read_respects_content_length PASSED [ 17%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_gzip PASSED [ 18%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_deflate PASSED [ 18%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_identity PASSED [ 19%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_unknown PASSED [ 20%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_base64 PASSED [ 21%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_quoted_printable PASSED [ 22%]\nr2e_tests/test_1.py::TestPartReader::test_decode_with_content_transfer_encoding_base64 PASSED [ 23%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[binary] PASSED [ 24%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[8bit] PASSED [ 25%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[7bit] PASSED [ 26%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_unknown PASSED [ 27%]\nr2e_tests/test_1.py::TestPartReader::test_read_text PASSED               [ 27%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_default_encoding PASSED [ 28%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_encoding PASSED      [ 29%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_guess_encoding PASSED [ 30%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_compressed PASSED    [ 31%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_while_closed PASSED  [ 32%]\nr2e_tests/test_1.py::TestPartReader::test_read_json PASSED               [ 33%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_encoding PASSED      [ 34%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_guess_encoding PASSED [ 35%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_compressed PASSED    [ 36%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_while_closed PASSED  [ 36%]\nr2e_tests/test_1.py::TestPartReader::test_read_form PASSED               [ 37%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_invalid_utf8 PASSED  [ 38%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_encoding PASSED      [ 39%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_guess_encoding PASSED [ 40%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_while_closed PASSED  [ 41%]\nr2e_tests/test_1.py::TestPartReader::test_readline PASSED                [ 42%]\nr2e_tests/test_1.py::TestPartReader::test_release PASSED                 [ 43%]\nr2e_tests/test_1.py::TestPartReader::test_release_respects_content_length PASSED [ 44%]\nr2e_tests/test_1.py::TestPartReader::test_release_release PASSED         [ 45%]\nr2e_tests/test_1.py::TestPartReader::test_filename PASSED                [ 45%]\nr2e_tests/test_1.py::TestPartReader::test_reading_long_part PASSED       [ 46%]\nr2e_tests/test_1.py::TestMultipartReader::test_from_response PASSED      [ 47%]\nr2e_tests/test_1.py::TestMultipartReader::test_bad_boundary PASSED       [ 48%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch PASSED           [ 49%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_bodypart PASSED  [ 50%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_multipart PASSED [ 51%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_custom_multipart_reader PASSED [ 52%]\nr2e_tests/test_1.py::TestMultipartReader::test_emit_next PASSED          [ 53%]\nr2e_tests/test_1.py::TestMultipartReader::test_invalid_boundary PASSED   [ 54%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_boundary_across_chunks SKIPPED [ 54%]\nr2e_tests/test_1.py::TestMultipartReader::test_release PASSED            [ 55%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_release PASSED    [ 56%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_next PASSED       [ 57%]\nr2e_tests/test_1.py::TestMultipartReader::test_second_next_releases_previous_object PASSED [ 58%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_without_read_the_last_object PASSED [ 59%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_chunk_by_length_doesnt_breaks_reader PASSED [ 60%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_chunk_from_stream_doesnt_breaks_reader PASSED [ 61%]\nr2e_tests/test_1.py::TestMultipartReader::test_reading_skips_prelude PASSED [ 62%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_form_default_encoding PASSED [ 63%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_form_invalid_default_encoding PASSED [ 63%]\nr2e_tests/test_1.py::test_writer PASSED                                  [ 64%]\nr2e_tests/test_1.py::test_writer_serialize_io_chunk PASSED               [ 65%]\nr2e_tests/test_1.py::test_writer_serialize_json PASSED                   [ 66%]\nr2e_tests/test_1.py::test_writer_serialize_form PASSED                   [ 67%]\nr2e_tests/test_1.py::test_writer_serialize_form_dict PASSED              [ 68%]\nr2e_tests/test_1.py::test_writer_write PASSED                            [ 69%]\nr2e_tests/test_1.py::test_writer_write_no_close_boundary PASSED          [ 70%]\nr2e_tests/test_1.py::test_writer_write_no_parts PASSED                   [ 71%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_gzip PASSED [ 72%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_deflate PASSED [ 72%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_identity PASSED [ 73%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_unknown PASSED [ 74%]\nr2e_tests/test_1.py::test_writer_with_content_transfer_encoding_base64 PASSED [ 75%]\nr2e_tests/test_1.py::test_writer_content_transfer_encoding_quote_printable PASSED [ 76%]\nr2e_tests/test_1.py::test_writer_content_transfer_encoding_unknown PASSED [ 77%]\nr2e_tests/test_1.py::TestMultipartWriter::test_default_subtype PASSED    [ 78%]\nr2e_tests/test_1.py::TestMultipartWriter::test_unquoted_boundary PASSED  [ 79%]\nr2e_tests/test_1.py::TestMultipartWriter::test_quoted_boundary PASSED    [ 80%]\nr2e_tests/test_1.py::TestMultipartWriter::test_bad_boundary PASSED       [ 81%]\nr2e_tests/test_1.py::TestMultipartWriter::test_default_headers PASSED    [ 81%]\nr2e_tests/test_1.py::TestMultipartWriter::test_iter_parts PASSED         [ 82%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append PASSED             [ 83%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_with_headers PASSED [ 84%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_json PASSED        [ 85%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_part PASSED        [ 86%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_json_overrides_content_type PASSED [ 87%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_form PASSED        [ 88%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_multipart PASSED   [ 89%]\nr2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_after_append PASSED [ 90%]\nr2e_tests/test_1.py::TestMultipartWriter::test_automatic_content_disposition PASSED [ 90%]\nr2e_tests/test_1.py::TestMultipartWriter::test_with PASSED               [ 91%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_int_not_allowed PASSED [ 92%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_float_not_allowed PASSED [ 93%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_none_not_allowed PASSED [ 94%]\nr2e_tests/test_1.py::TestMultipartWriter::test_write_preserves_content_disposition PASSED [ 95%]\nr2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header PASSED [ 96%]\nr2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_override PASSED [ 97%]\nr2e_tests/test_1.py::TestMultipartWriter::test_reset_content_disposition_header PASSED [ 98%]\nr2e_tests/test_1.py::test_async_for_reader PASSED                        [ 99%]\nr2e_tests/test_1.py::test_async_for_bodypart PASSED                      [100%]\n\n==================================== PASSES ====================================\n\n---------- coverage: platform linux, python 3.9.21-final-0 -----------\nName                                     Stmts   Miss Branch BrPart  Cover\n--------------------------------------------------------------------------\naiohttp/__init__.py                         27      8      2      1    69%\naiohttp/abc.py                              97      8      0      0    92%\naiohttp/base_protocol.py                    67     51     22      0    18%\naiohttp/client.py                          545    394    196      3    21%\naiohttp/client_exceptions.py               153     69     20      0    49%\naiohttp/client_proto.py                    165    131     56      0    15%\naiohttp/client_reqrep.py                   693    520    300      0    18%\naiohttp/client_ws.py                       253    207     78      1    14%\naiohttp/compression_utils.py                70     18     14      2    67%\naiohttp/connector.py                       770    631    319      0    13%\naiohttp/cookiejar.py                       255    200    118      0    15%\naiohttp/formdata.py                         97     79     46      0    13%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         499    288    172     10    37%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     502    372    206      8    20%\naiohttp/http_websocket.py                  389    285    152      0    20%\naiohttp/http_writer.py                     118     81     50      1    23%\naiohttp/locks.py                            24     16      4      0    29%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       612     82    262     31    83%\naiohttp/payload.py                         219     52     56      8    72%\naiohttp/payload_streamer.py                 29     10      4      0    70%\naiohttp/pytest_plugin.py                   162     95     42      5    39%\naiohttp/resolver.py                         80     58     26      0    21%\naiohttp/streams.py                         396    222    144     24    38%\naiohttp/tcp_helpers.py                      19     11      6      0    32%\naiohttp/test_utils.py                      316    194     52      5    35%\naiohttp/tracing.py                         191     69     32      0    69%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             118     81     52      0    23%\naiohttp/web_app.py                         282    189     74      0    26%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                163    127     54      1    19%\naiohttp/web_log.py                         102     58     20      0    36%\naiohttp/web_middlewares.py                  55     42     20      0    17%\naiohttp/web_protocol.py                    357    297    163      0    12%\naiohttp/web_request.py                     441    290    134      1    27%\naiohttp/web_response.py                    483    370    218      0    16%\naiohttp/web_routedef.py                    100     44     10      0    55%\naiohttp/web_runner.py                      213    130     36      0    33%\naiohttp/web_server.py                       42     24     12      0    33%\naiohttp/web_urldispatcher.py               741    474    161      0    30%\naiohttp/web_ws.py                          373    302    126      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/conftest.py                          130    130     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              29     29     13      0     0%\ntests/test_classbasedview.py                39     39      0      0     0%\ntests/test_client_connection.py             94     94      2      0     0%\ntests/test_client_exceptions.py            198    198     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2403   2403     84      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               803    803     18      0     0%\ntests/test_client_response.py              464    464      4      0     0%\ntests/test_client_session.py               556    556     29      0     0%\ntests/test_client_ws.py                    486    486      2      0     0%\ntests/test_client_ws_functional.py         733    733     32      0     0%\ntests/test_connector.py                   1676   1676     82      0     0%\ntests/test_cookiejar.py                    350    350     24      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      72     72      6      0     0%\ntests/test_helpers.py                      464    464     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                 1063   1063     64      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       34     34      6      0     0%\ntests/test_locks.py                         39     39      0      0     0%\ntests/test_loop.py                          36     36      0      0     0%\ntests/test_multipart.py                    826    826     32      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       94     94      0      0     0%\ntests/test_proxy.py                        301    301      0      0     0%\ntests/test_proxy_functional.py             459    459     18      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     193    193     20      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      554    554     30      0     0%\ntests/test_streams.py                     1076   1076     38      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   241    241      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  854    854     24      0     0%\ntests/test_web_app.py                      453    453      6      0     0%\ntests/test_web_cli.py                       75     75      0      0     0%\ntests/test_web_exceptions.py               176    176     22      0     0%\ntests/test_web_functional.py              1535   1535     34      0     0%\ntests/test_web_log.py                      116    116      2      0     0%\ntests/test_web_middleware.py               266    266     12      0     0%\ntests/test_web_request.py                  490    490      8      0     0%\ntests/test_web_request_handler.py           42     42      0      0     0%\ntests/test_web_response.py                 863    863      4      0     0%\ntests/test_web_runner.py                   146    146      4      0     0%\ntests/test_web_sendfile.py                  84     84      0      0     0%\ntests/test_web_sendfile_functional.py      655    655     18      0     0%\ntests/test_web_server.py                   162    162      0      0     0%\ntests/test_web_urldispatcher.py            519    519     24      0     0%\ntests/test_web_websocket.py                401    401      8      0     0%\ntests/test_web_websocket_functional.py     727    727     28      0     0%\ntests/test_websocket_handshake.py          152    152     12      0     0%\ntests/test_websocket_parser.py             300    300     12      0     0%\ntests/test_websocket_writer.py              95     95      6      0     0%\ntests/test_worker.py                       191    191      2      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    33927  29995   4317    102    11%\n\n============================= slowest 10 durations =============================\n0.04s call     r2e_tests/test_1.py::TestPartReader::test_read_text_encoding\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_text_guess_encoding\n0.02s call     r2e_tests/test_1.py::TestMultipartWriter::test_write_preserves_content_disposition\n0.02s call     r2e_tests/test_1.py::TestMultipartResponseWrapper::test_next\n0.01s call     r2e_tests/test_1.py::TestMultipartReader::test_emit_next\n0.01s call     r2e_tests/test_1.py::TestPartReader::test_reading_long_part\n0.01s call     r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_gzip\n0.01s call     r2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header\n0.01s call     r2e_tests/test_1.py::TestMultipartReader::test_read_form_default_encoding\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_at_eof\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_next\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_release\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_release_when_stream_at_eof\nPASSED r2e_tests/test_1.py::TestPartReader::test_next\nPASSED r2e_tests/test_1.py::TestPartReader::test_next_next\nPASSED r2e_tests/test_1.py::TestPartReader::test_read\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_at_eof\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_without_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_all_at_once\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_incomplete_body_chunked\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_boundary_with_incomplete_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_multi_read_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_properly_counts_read_bytes\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_does_not_read_boundary\nPASSED r2e_tests/test_1.py::TestPartReader::test_multiread\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_multiline\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_respects_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_gzip\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_deflate\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_identity\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_unknown\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_base64\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_quoted_printable\nPASSED r2e_tests/test_1.py::TestPartReader::test_decode_with_content_transfer_encoding_base64\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[binary]\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[8bit]\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[7bit]\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_unknown\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_default_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_compressed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_compressed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_invalid_utf8\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_readline\nPASSED r2e_tests/test_1.py::TestPartReader::test_release\nPASSED r2e_tests/test_1.py::TestPartReader::test_release_respects_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_release_release\nPASSED r2e_tests/test_1.py::TestPartReader::test_filename\nPASSED r2e_tests/test_1.py::TestPartReader::test_reading_long_part\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_from_response\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_bad_boundary\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_bodypart\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_multipart\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_custom_multipart_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_emit_next\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_invalid_boundary\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_release\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_next\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_second_next_releases_previous_object\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_without_read_the_last_object\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_chunk_by_length_doesnt_breaks_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_chunk_from_stream_doesnt_breaks_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_reading_skips_prelude\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_form_default_encoding\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_form_invalid_default_encoding\nPASSED r2e_tests/test_1.py::test_writer\nPASSED r2e_tests/test_1.py::test_writer_serialize_io_chunk\nPASSED r2e_tests/test_1.py::test_writer_serialize_json\nPASSED r2e_tests/test_1.py::test_writer_serialize_form\nPASSED r2e_tests/test_1.py::test_writer_serialize_form_dict\nPASSED r2e_tests/test_1.py::test_writer_write\nPASSED r2e_tests/test_1.py::test_writer_write_no_close_boundary\nPASSED r2e_tests/test_1.py::test_writer_write_no_parts\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_gzip\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_deflate\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_identity\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_unknown\nPASSED r2e_tests/test_1.py::test_writer_with_content_transfer_encoding_base64\nPASSED r2e_tests/test_1.py::test_writer_content_transfer_encoding_quote_printable\nPASSED r2e_tests/test_1.py::test_writer_content_transfer_encoding_unknown\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_default_subtype\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_unquoted_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_quoted_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_bad_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_default_headers\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_iter_parts\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_with_headers\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_json\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_part\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_json_overrides_content_type\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_form\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_multipart\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_after_append\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_automatic_content_disposition\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_with\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_int_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_float_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_none_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_write_preserves_content_disposition\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_override\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_reset_content_disposition_header\nPASSED r2e_tests/test_1.py::test_async_for_reader\nPASSED r2e_tests/test_1.py::test_async_for_bodypart\nSKIPPED [1] r2e_tests/test_1.py:769: Needs anext()\n======================== 110 passed, 1 skipped in 5.83s ========================\n",
    "new_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.9.21, pytest-8.3.2, pluggy-1.5.0 -- /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/.venv/bin/python\ncachedir: .pytest_cache\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd\nconfigfile: setup.cfg\nplugins: cov-5.0.0, asyncio-0.25.0, mock-3.14.0\nasyncio: mode=strict, asyncio_default_fixture_loop_scope=None\ncollecting ... collected 111 items\n\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_at_eof PASSED    [  0%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_next PASSED      [  1%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_release PASSED   [  2%]\nr2e_tests/test_1.py::TestMultipartResponseWrapper::test_release_when_stream_at_eof PASSED [  3%]\nr2e_tests/test_1.py::TestPartReader::test_next PASSED                    [  4%]\nr2e_tests/test_1.py::TestPartReader::test_next_next PASSED               [  5%]\nr2e_tests/test_1.py::TestPartReader::test_read PASSED                    [  6%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_at_eof PASSED       [  7%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_without_content_length PASSED [  8%]\nr2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk PASSED   [  9%]\nr2e_tests/test_1.py::TestPartReader::test_read_all_at_once PASSED        [  9%]\nr2e_tests/test_1.py::TestPartReader::test_read_incomplete_body_chunked PASSED [ 10%]\nr2e_tests/test_1.py::TestPartReader::test_read_boundary_with_incomplete_chunk PASSED [ 11%]\nr2e_tests/test_1.py::TestPartReader::test_multi_read_chunk PASSED        [ 12%]\nr2e_tests/test_1.py::TestPartReader::test_read_chunk_properly_counts_read_bytes PASSED [ 13%]\nr2e_tests/test_1.py::TestPartReader::test_read_does_not_read_boundary PASSED [ 14%]\nr2e_tests/test_1.py::TestPartReader::test_multiread PASSED               [ 15%]\nr2e_tests/test_1.py::TestPartReader::test_read_multiline PASSED          [ 16%]\nr2e_tests/test_1.py::TestPartReader::test_read_respects_content_length PASSED [ 17%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_gzip PASSED [ 18%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_deflate PASSED [ 18%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_identity PASSED [ 19%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_unknown PASSED [ 20%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_base64 PASSED [ 21%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_quoted_printable PASSED [ 22%]\nr2e_tests/test_1.py::TestPartReader::test_decode_with_content_transfer_encoding_base64 FAILED [ 23%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[binary] FAILED [ 24%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[8bit] PASSED [ 25%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[7bit] PASSED [ 26%]\nr2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_unknown PASSED [ 27%]\nr2e_tests/test_1.py::TestPartReader::test_read_text PASSED               [ 27%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_default_encoding PASSED [ 28%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_encoding PASSED      [ 29%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_guess_encoding PASSED [ 30%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_compressed PASSED    [ 31%]\nr2e_tests/test_1.py::TestPartReader::test_read_text_while_closed PASSED  [ 32%]\nr2e_tests/test_1.py::TestPartReader::test_read_json PASSED               [ 33%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_encoding PASSED      [ 34%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_guess_encoding PASSED [ 35%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_compressed PASSED    [ 36%]\nr2e_tests/test_1.py::TestPartReader::test_read_json_while_closed PASSED  [ 36%]\nr2e_tests/test_1.py::TestPartReader::test_read_form PASSED               [ 37%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_invalid_utf8 PASSED  [ 38%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_encoding PASSED      [ 39%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_guess_encoding PASSED [ 40%]\nr2e_tests/test_1.py::TestPartReader::test_read_form_while_closed PASSED  [ 41%]\nr2e_tests/test_1.py::TestPartReader::test_readline PASSED                [ 42%]\nr2e_tests/test_1.py::TestPartReader::test_release PASSED                 [ 43%]\nr2e_tests/test_1.py::TestPartReader::test_release_respects_content_length PASSED [ 44%]\nr2e_tests/test_1.py::TestPartReader::test_release_release PASSED         [ 45%]\nr2e_tests/test_1.py::TestPartReader::test_filename PASSED                [ 45%]\nr2e_tests/test_1.py::TestPartReader::test_reading_long_part PASSED       [ 46%]\nr2e_tests/test_1.py::TestMultipartReader::test_from_response PASSED      [ 47%]\nr2e_tests/test_1.py::TestMultipartReader::test_bad_boundary PASSED       [ 48%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch PASSED           [ 49%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_bodypart PASSED  [ 50%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_multipart PASSED [ 51%]\nr2e_tests/test_1.py::TestMultipartReader::test_dispatch_custom_multipart_reader PASSED [ 52%]\nr2e_tests/test_1.py::TestMultipartReader::test_emit_next PASSED          [ 53%]\nr2e_tests/test_1.py::TestMultipartReader::test_invalid_boundary PASSED   [ 54%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_boundary_across_chunks SKIPPED [ 54%]\nr2e_tests/test_1.py::TestMultipartReader::test_release PASSED            [ 55%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_release PASSED    [ 56%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_next PASSED       [ 57%]\nr2e_tests/test_1.py::TestMultipartReader::test_second_next_releases_previous_object PASSED [ 58%]\nr2e_tests/test_1.py::TestMultipartReader::test_release_without_read_the_last_object PASSED [ 59%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_chunk_by_length_doesnt_breaks_reader PASSED [ 60%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_chunk_from_stream_doesnt_breaks_reader PASSED [ 61%]\nr2e_tests/test_1.py::TestMultipartReader::test_reading_skips_prelude PASSED [ 62%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_form_default_encoding PASSED [ 63%]\nr2e_tests/test_1.py::TestMultipartReader::test_read_form_invalid_default_encoding PASSED [ 63%]\nr2e_tests/test_1.py::test_writer PASSED                                  [ 64%]\nr2e_tests/test_1.py::test_writer_serialize_io_chunk PASSED               [ 65%]\nr2e_tests/test_1.py::test_writer_serialize_json PASSED                   [ 66%]\nr2e_tests/test_1.py::test_writer_serialize_form PASSED                   [ 67%]\nr2e_tests/test_1.py::test_writer_serialize_form_dict PASSED              [ 68%]\nr2e_tests/test_1.py::test_writer_write PASSED                            [ 69%]\nr2e_tests/test_1.py::test_writer_write_no_close_boundary PASSED          [ 70%]\nr2e_tests/test_1.py::test_writer_write_no_parts PASSED                   [ 71%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_gzip PASSED [ 72%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_deflate PASSED [ 72%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_identity PASSED [ 73%]\nr2e_tests/test_1.py::test_writer_serialize_with_content_encoding_unknown PASSED [ 74%]\nr2e_tests/test_1.py::test_writer_with_content_transfer_encoding_base64 PASSED [ 75%]\nr2e_tests/test_1.py::test_writer_content_transfer_encoding_quote_printable PASSED [ 76%]\nr2e_tests/test_1.py::test_writer_content_transfer_encoding_unknown PASSED [ 77%]\nr2e_tests/test_1.py::TestMultipartWriter::test_default_subtype PASSED    [ 78%]\nr2e_tests/test_1.py::TestMultipartWriter::test_unquoted_boundary PASSED  [ 79%]\nr2e_tests/test_1.py::TestMultipartWriter::test_quoted_boundary PASSED    [ 80%]\nr2e_tests/test_1.py::TestMultipartWriter::test_bad_boundary PASSED       [ 81%]\nr2e_tests/test_1.py::TestMultipartWriter::test_default_headers PASSED    [ 81%]\nr2e_tests/test_1.py::TestMultipartWriter::test_iter_parts PASSED         [ 82%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append PASSED             [ 83%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_with_headers PASSED [ 84%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_json PASSED        [ 85%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_part PASSED        [ 86%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_json_overrides_content_type PASSED [ 87%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_form PASSED        [ 88%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_multipart PASSED   [ 89%]\nr2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_after_append PASSED [ 90%]\nr2e_tests/test_1.py::TestMultipartWriter::test_automatic_content_disposition PASSED [ 90%]\nr2e_tests/test_1.py::TestMultipartWriter::test_with PASSED               [ 91%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_int_not_allowed PASSED [ 92%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_float_not_allowed PASSED [ 93%]\nr2e_tests/test_1.py::TestMultipartWriter::test_append_none_not_allowed PASSED [ 94%]\nr2e_tests/test_1.py::TestMultipartWriter::test_write_preserves_content_disposition PASSED [ 95%]\nr2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header PASSED [ 96%]\nr2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_override PASSED [ 97%]\nr2e_tests/test_1.py::TestMultipartWriter::test_reset_content_disposition_header PASSED [ 98%]\nr2e_tests/test_1.py::test_async_for_reader PASSED                        [ 99%]\nr2e_tests/test_1.py::test_async_for_bodypart PASSED                      [100%]\n\n=================================== FAILURES ===================================\n_______ TestPartReader.test_decode_with_content_transfer_encoding_base64 _______\n\nself = <r2e_tests.test_1.TestPartReader object at 0x7a83ff683eb0>\n\n    async def test_decode_with_content_transfer_encoding_base64(self) -> None:\n        with Stream(b\"VG\\r\\r\\nltZSB0byBSZ\\r\\nWxheCE=\\r\\n--:--\") as stream:\n            obj = aiohttp.BodyPartReader(\n                BOUNDARY, {CONTENT_TRANSFER_ENCODING: \"base64\"}, stream\n            )\n            result = b\"\"\n            while not obj.at_eof():\n                chunk = await obj.read_chunk(size=6)\n>               result += obj.decode(chunk)\n\nchunk      = b'VG\\r\\r\\nl'\nobj        = <aiohttp.multipart.BodyPartReader object at 0x7a83ff667850>\nresult     = b''\nself       = <r2e_tests.test_1.TestPartReader object at 0x7a83ff683eb0>\nstream     = <r2e_tests.test_1.Stream object at 0x7a83ff667790>\n\nr2e_tests/test_1.py:389: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \naiohttp/multipart.py:473: in decode\n    data = self._decode_content_transfer(data)\n        data       = b'VG\\r\\r\\nl'\n        self       = <aiohttp.multipart.BodyPartReader object at 0x7a83ff667850>\naiohttp/multipart.py:495: in _decode_content_transfer\n    return base64.b64decode(data)\n        data       = b'VG\\r\\r\\nl'\n        encoding   = 'base64'\n        self       = <aiohttp.multipart.BodyPartReader object at 0x7a83ff667850>\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\ns = b'VG\\r\\r\\nl', altchars = None, validate = False\n\n    def b64decode(s, altchars=None, validate=False):\n        \"\"\"Decode the Base64 encoded bytes-like object or ASCII string s.\n    \n        Optional altchars must be a bytes-like object or ASCII string of length 2\n        which specifies the alternative alphabet used instead of the '+' and '/'\n        characters.\n    \n        The result is returned as a bytes object.  A binascii.Error is raised if\n        s is incorrectly padded.\n    \n        If validate is False (the default), characters that are neither in the\n        normal base-64 alphabet nor the alternative alphabet are discarded prior\n        to the padding check.  If validate is True, these non-alphabet characters\n        in the input result in a binascii.Error.\n        \"\"\"\n        s = _bytes_from_decode_data(s)\n        if altchars is not None:\n            altchars = _bytes_from_decode_data(altchars)\n            assert len(altchars) == 2, repr(altchars)\n            s = s.translate(bytes.maketrans(altchars, b'+/'))\n        if validate and not re.fullmatch(b'[A-Za-z0-9+/]*={0,2}', s):\n            raise binascii.Error('Non-base64 digit found')\n>       return binascii.a2b_base64(s)\nE       binascii.Error: Incorrect padding\n\naltchars   = None\ns          = b'VG\\r\\r\\nl'\nvalidate   = False\n\n../../../../.local/share/uv/python/cpython-3.9.21-linux-x86_64-gnu/lib/python3.9/base64.py:87: Error\n____ TestPartReader.test_read_with_content_transfer_encoding_binary[binary] ____\n\ncls = <class '_pytest.runner.CallInfo'>\nfunc = <function call_and_report.<locals>.<lambda> at 0x7a83ff67ce50>\nwhen = 'call'\nreraise = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)\n\n    @classmethod\n    def from_call(\n        cls,\n        func: Callable[[], TResult],\n        when: Literal[\"collect\", \"setup\", \"call\", \"teardown\"],\n        reraise: type[BaseException] | tuple[type[BaseException], ...] | None = None,\n    ) -> CallInfo[TResult]:\n        \"\"\"Call func, wrapping the result in a CallInfo.\n    \n        :param func:\n            The function to call. Called without arguments.\n        :type func: Callable[[], _pytest.runner.TResult]\n        :param when:\n            The phase in which the function is called.\n        :param reraise:\n            Exception or exceptions that shall propagate if raised by the\n            function, instead of being wrapped in the CallInfo.\n        \"\"\"\n        excinfo = None\n        start = timing.time()\n        precise_start = timing.perf_counter()\n        try:\n>           result: TResult | None = func()\n\ncls        = <class '_pytest.runner.CallInfo'>\nduration   = 0.020054542997968383\nexcinfo    = <ExceptionInfo PytestUnraisableExceptionWarning('Exception ignored in: <socket.socket fd=-1, family=AddressFamily.AF_U...rning: unclosed <socket.socket fd=14, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>\\n') tblen=12>\nfunc       = <function call_and_report.<locals>.<lambda> at 0x7a83ff67ce50>\nprecise_start = 86471.540733585\nprecise_stop = 86471.560788128\nreraise    = (<class '_pytest.outcomes.Exit'>, <class 'KeyboardInterrupt'>)\nresult     = None\nstart      = 1735788115.1595461\nstop       = 1735788115.179602\nwhen       = 'call'\n\n.venv/lib/python3.9/site-packages/_pytest/runner.py:341: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n.venv/lib/python3.9/site-packages/_pytest/runner.py:242: in <lambda>\n    lambda: runtest_hook(item=item, **kwds), when=when, reraise=reraise\n        item       = <Function test_read_with_content_transfer_encoding_binary[binary]>\n        kwds       = {}\n        runtest_hook = <HookCaller 'pytest_runtest_call'>\n.venv/lib/python3.9/site-packages/pluggy/_hooks.py:513: in __call__\n    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)\n        firstresult = False\n        kwargs     = {'item': <Function test_read_with_content_transfer_encoding_binary[binary]>}\n        self       = <HookCaller 'pytest_runtest_call'>\n.venv/lib/python3.9/site-packages/pluggy/_manager.py:120: in _hookexec\n    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)\n        firstresult = False\n        hook_name  = 'pytest_runtest_call'\n        kwargs     = {'item': <Function test_read_with_content_transfer_encoding_binary[binary]>}\n        methods    = [<HookImpl plugin_name='runner', plugin=<module '_pytest.runner' from '/home/gcpuser/buckets/local_repoeval_bucket/rep...http_2f7c45ebc0e2adee709815fc26264c7940b732fd/.venv/lib/python3.9/site-packages/_pytest/unraisableexception.py'>>, ...]\n        self       = <_pytest.config.PytestPluginManager object at 0x7a8401da2610>\n.venv/lib/python3.9/site-packages/_pytest/threadexception.py:92: in pytest_runtest_call\n    yield from thread_exception_runtest_hook()\n.venv/lib/python3.9/site-packages/_pytest/threadexception.py:68: in thread_exception_runtest_hook\n    yield\n        cm         = <_pytest.threadexception.catch_threading_exception object at 0x7a83ff53bd90>\n.venv/lib/python3.9/site-packages/_pytest/unraisableexception.py:95: in pytest_runtest_call\n    yield from unraisable_exception_runtest_hook()\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\n    def unraisable_exception_runtest_hook() -> Generator[None, None, None]:\n        with catch_unraisable_exception() as cm:\n            try:\n                yield\n            finally:\n                if cm.unraisable:\n                    if cm.unraisable.err_msg is not None:\n                        err_msg = cm.unraisable.err_msg\n                    else:\n                        err_msg = \"Exception ignored in\"\n                    msg = f\"{err_msg}: {cm.unraisable.object!r}\\n\\n\"\n                    msg += \"\".join(\n                        traceback.format_exception(\n                            cm.unraisable.exc_type,\n                            cm.unraisable.exc_value,\n                            cm.unraisable.exc_traceback,\n                        )\n                    )\n>                   warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))\nE                   pytest.PytestUnraisableExceptionWarning: Exception ignored in: <socket.socket fd=-1, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>\nE                   \nE                   Traceback (most recent call last):\nE                     File \"/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/aiohttp/test_utils.py\", line 586, in teardown_test_loop\nE                       gc.collect()\nE                   ResourceWarning: unclosed <socket.socket fd=14, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>\n\ncm         = <_pytest.unraisableexception.catch_unraisable_exception object at 0x7a83ff53bf70>\nerr_msg    = 'Exception ignored in'\nmsg        = 'Exception ignored in: <socket.socket fd=-1, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>\\n\\nTr...nResourceWarning: unclosed <socket.socket fd=14, family=AddressFamily.AF_UNIX, type=SocketKind.SOCK_STREAM, proto=0>\\n'\n\n.venv/lib/python3.9/site-packages/_pytest/unraisableexception.py:85: PytestUnraisableExceptionWarning\n==================================== PASSES ====================================\n\n---------- coverage: platform linux, python 3.9.21-final-0 -----------\nName                                     Stmts   Miss Branch BrPart  Cover\n--------------------------------------------------------------------------\naiohttp/__init__.py                         27      8      2      1    69%\naiohttp/abc.py                              97      8      0      0    92%\naiohttp/base_protocol.py                    67     51     22      0    18%\naiohttp/client.py                          545    394    196      3    21%\naiohttp/client_exceptions.py               153     69     20      0    49%\naiohttp/client_proto.py                    165    131     56      0    15%\naiohttp/client_reqrep.py                   693    520    300      0    18%\naiohttp/client_ws.py                       253    207     78      1    14%\naiohttp/compression_utils.py                70     18     14      2    67%\naiohttp/connector.py                       770    631    319      0    13%\naiohttp/cookiejar.py                       255    200    118      0    15%\naiohttp/formdata.py                         97     79     46      0    13%\naiohttp/hdrs.py                             90      0      0      0   100%\naiohttp/helpers.py                         499    288    172     10    37%\naiohttp/http.py                             11      0      2      0   100%\naiohttp/http_exceptions.py                  50     20      4      0    56%\naiohttp/http_parser.py                     502    372    206      8    20%\naiohttp/http_websocket.py                  389    285    152      0    20%\naiohttp/http_writer.py                     118     81     50      1    23%\naiohttp/locks.py                            24     16      4      0    29%\naiohttp/log.py                               7      0      0      0   100%\naiohttp/multipart.py                       595     80    252     28    83%\naiohttp/payload.py                         219     52     56      8    72%\naiohttp/payload_streamer.py                 29     10      4      0    70%\naiohttp/pytest_plugin.py                   162     94     42      5    40%\naiohttp/resolver.py                         80     58     26      0    21%\naiohttp/streams.py                         396    222    144     24    38%\naiohttp/tcp_helpers.py                      19     11      6      0    32%\naiohttp/test_utils.py                      316    194     52      5    35%\naiohttp/tracing.py                         191     69     32      0    69%\naiohttp/typedefs.py                         23      0      0      0   100%\naiohttp/web.py                             118     81     52      0    23%\naiohttp/web_app.py                         282    189     74      0    26%\naiohttp/web_exceptions.py                  157     25      8      0    80%\naiohttp/web_fileresponse.py                163    127     54      1    19%\naiohttp/web_log.py                         102     58     20      0    36%\naiohttp/web_middlewares.py                  55     42     20      0    17%\naiohttp/web_protocol.py                    357    297    163      0    12%\naiohttp/web_request.py                     441    290    134      1    27%\naiohttp/web_response.py                    483    370    218      0    16%\naiohttp/web_routedef.py                    100     44     10      0    55%\naiohttp/web_runner.py                      213    130     36      0    33%\naiohttp/web_server.py                       42     24     12      0    33%\naiohttp/web_urldispatcher.py               741    474    161      0    30%\naiohttp/web_ws.py                          373    302    126      1    15%\naiohttp/worker.py                          126    126     30      0     0%\ntests/conftest.py                          130    130     16      0     0%\ntests/test_base_protocol.py                198    198      2      0     0%\ntests/test_circular_imports.py              29     29     13      0     0%\ntests/test_classbasedview.py                39     39      0      0     0%\ntests/test_client_connection.py             94     94      2      0     0%\ntests/test_client_exceptions.py            198    198     14      0     0%\ntests/test_client_fingerprint.py            59     59      0      0     0%\ntests/test_client_functional.py           2403   2403     84      0     0%\ntests/test_client_proto.py                  99     99      0      0     0%\ntests/test_client_request.py               803    803     18      0     0%\ntests/test_client_response.py              464    464      4      0     0%\ntests/test_client_session.py               556    556     29      0     0%\ntests/test_client_ws.py                    486    486      2      0     0%\ntests/test_client_ws_functional.py         733    733     32      0     0%\ntests/test_connector.py                   1676   1676     82      0     0%\ntests/test_cookiejar.py                    350    350     24      0     0%\ntests/test_flowcontrol_streams.py          100    100      0      0     0%\ntests/test_formdata.py                      72     72      6      0     0%\ntests/test_helpers.py                      464    464     24      0     0%\ntests/test_http_exceptions.py              109    109     10      0     0%\ntests/test_http_parser.py                 1063   1063     64      0     0%\ntests/test_http_writer.py                  182    182     10      0     0%\ntests/test_imports.py                       34     34      6      0     0%\ntests/test_locks.py                         39     39      0      0     0%\ntests/test_loop.py                          36     36      0      0     0%\ntests/test_multipart.py                    818    818     30      0     0%\ntests/test_multipart_helpers.py            446    446      0      0     0%\ntests/test_payload.py                       94     94      0      0     0%\ntests/test_proxy.py                        301    301      0      0     0%\ntests/test_proxy_functional.py             459    459     18      0     0%\ntests/test_pytest_plugin.py                 27     27      0      0     0%\ntests/test_resolver.py                     193    193     20      0     0%\ntests/test_route_def.py                    210    210      0      0     0%\ntests/test_run_app.py                      554    554     30      0     0%\ntests/test_streams.py                     1076   1076     38      0     0%\ntests/test_tcp_helpers.py                   52     52      2      0     0%\ntests/test_test_utils.py                   241    241      6      0     0%\ntests/test_tracing.py                       48     48      0      0     0%\ntests/test_urldispatch.py                  854    854     24      0     0%\ntests/test_web_app.py                      453    453      6      0     0%\ntests/test_web_cli.py                       75     75      0      0     0%\ntests/test_web_exceptions.py               176    176     22      0     0%\ntests/test_web_functional.py              1535   1535     34      0     0%\ntests/test_web_log.py                      116    116      2      0     0%\ntests/test_web_middleware.py               266    266     12      0     0%\ntests/test_web_request.py                  490    490      8      0     0%\ntests/test_web_request_handler.py           42     42      0      0     0%\ntests/test_web_response.py                 863    863      4      0     0%\ntests/test_web_runner.py                   146    146      4      0     0%\ntests/test_web_sendfile.py                  84     84      0      0     0%\ntests/test_web_sendfile_functional.py      655    655     18      0     0%\ntests/test_web_server.py                   162    162      0      0     0%\ntests/test_web_urldispatcher.py            519    519     24      0     0%\ntests/test_web_websocket.py                401    401      8      0     0%\ntests/test_web_websocket_functional.py     727    727     28      0     0%\ntests/test_websocket_handshake.py          152    152     12      0     0%\ntests/test_websocket_parser.py             300    300     12      0     0%\ntests/test_websocket_writer.py              95     95      6      0     0%\ntests/test_worker.py                       191    191      2      0     0%\n--------------------------------------------------------------------------\nTOTAL                                    33902  29984   4305     99    11%\n\n============================= slowest 10 durations =============================\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk\n0.02s call     r2e_tests/test_1.py::test_writer_write\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_text_default_encoding\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_text_encoding\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_release\n0.02s call     r2e_tests/test_1.py::test_writer_write_no_close_boundary\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_unknown\n0.02s call     r2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header\n0.02s call     r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[7bit]\n0.02s call     r2e_tests/test_1.py::test_writer_content_transfer_encoding_quote_printable\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_at_eof\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_next\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_release\nPASSED r2e_tests/test_1.py::TestMultipartResponseWrapper::test_release_when_stream_at_eof\nPASSED r2e_tests/test_1.py::TestPartReader::test_next\nPASSED r2e_tests/test_1.py::TestPartReader::test_next_next\nPASSED r2e_tests/test_1.py::TestPartReader::test_read\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_at_eof\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_without_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_incomplete_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_all_at_once\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_incomplete_body_chunked\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_boundary_with_incomplete_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_multi_read_chunk\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_chunk_properly_counts_read_bytes\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_does_not_read_boundary\nPASSED r2e_tests/test_1.py::TestPartReader::test_multiread\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_multiline\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_respects_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_gzip\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_deflate\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_identity\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_encoding_unknown\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_base64\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_quoted_printable\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[8bit]\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[7bit]\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_unknown\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_default_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_compressed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_text_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_compressed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_json_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_invalid_utf8\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_guess_encoding\nPASSED r2e_tests/test_1.py::TestPartReader::test_read_form_while_closed\nPASSED r2e_tests/test_1.py::TestPartReader::test_readline\nPASSED r2e_tests/test_1.py::TestPartReader::test_release\nPASSED r2e_tests/test_1.py::TestPartReader::test_release_respects_content_length\nPASSED r2e_tests/test_1.py::TestPartReader::test_release_release\nPASSED r2e_tests/test_1.py::TestPartReader::test_filename\nPASSED r2e_tests/test_1.py::TestPartReader::test_reading_long_part\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_from_response\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_bad_boundary\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_bodypart\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_multipart\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_dispatch_custom_multipart_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_emit_next\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_invalid_boundary\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_release\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_next\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_second_next_releases_previous_object\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_release_without_read_the_last_object\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_chunk_by_length_doesnt_breaks_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_chunk_from_stream_doesnt_breaks_reader\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_reading_skips_prelude\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_form_default_encoding\nPASSED r2e_tests/test_1.py::TestMultipartReader::test_read_form_invalid_default_encoding\nPASSED r2e_tests/test_1.py::test_writer\nPASSED r2e_tests/test_1.py::test_writer_serialize_io_chunk\nPASSED r2e_tests/test_1.py::test_writer_serialize_json\nPASSED r2e_tests/test_1.py::test_writer_serialize_form\nPASSED r2e_tests/test_1.py::test_writer_serialize_form_dict\nPASSED r2e_tests/test_1.py::test_writer_write\nPASSED r2e_tests/test_1.py::test_writer_write_no_close_boundary\nPASSED r2e_tests/test_1.py::test_writer_write_no_parts\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_gzip\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_deflate\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_identity\nPASSED r2e_tests/test_1.py::test_writer_serialize_with_content_encoding_unknown\nPASSED r2e_tests/test_1.py::test_writer_with_content_transfer_encoding_base64\nPASSED r2e_tests/test_1.py::test_writer_content_transfer_encoding_quote_printable\nPASSED r2e_tests/test_1.py::test_writer_content_transfer_encoding_unknown\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_default_subtype\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_unquoted_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_quoted_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_bad_boundary\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_default_headers\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_iter_parts\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_with_headers\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_json\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_part\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_json_overrides_content_type\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_form\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_multipart\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_after_append\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_automatic_content_disposition\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_with\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_int_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_float_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_append_none_not_allowed\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_write_preserves_content_disposition\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_preserve_content_disposition_header\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_set_content_disposition_override\nPASSED r2e_tests/test_1.py::TestMultipartWriter::test_reset_content_disposition_header\nPASSED r2e_tests/test_1.py::test_async_for_reader\nPASSED r2e_tests/test_1.py::test_async_for_bodypart\nSKIPPED [1] r2e_tests/test_1.py:769: Needs anext()\nFAILED r2e_tests/test_1.py::TestPartReader::test_decode_with_content_transfer_encoding_base64\nFAILED r2e_tests/test_1.py::TestPartReader::test_read_with_content_transfer_encoding_binary[binary]\n=================== 2 failed, 108 passed, 1 skipped in 6.29s ===================\n",
    "old_commit_res_stderr": "/home/gcpuser/buckets/local_repoeval_bucket/repos/aiohttp_2f7c45ebc0e2adee709815fc26264c7940b732fd/.venv/lib/python3.9/site-packages/pytest_asyncio/plugin.py:207: PytestDeprecationWarning: The configuration option \"asyncio_default_fixture_loop_scope\" is unset.\nThe event loop scope for asynchronous fixtures will default to the fixture caching scope. Future versions of pytest-asyncio will default the loop scope for asynchronous fixtures to function scope. Set the default fixture loop scope explicitly in order to avoid unexpected behavior in the future. Valid fixture loop scopes are: \"function\", \"class\", \"module\", \"package\", \"session\"\n\n  warnings.warn(PytestDeprecationWarning(_DEFAULT_FIXTURE_LOOP_SCOPE_UNSET))\n"
}
CHANGES/3867.bugfix.rst aiohttp/multipart.py tests/test_multipart.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
**Analysis:**

- **Key Parts from Commit Details and Test Results:**
  - **Commit Message:** "Fix decoding base64 chunk for BodyPartReader"
  - **Changes:** Added logic to handle base64-encoded chunks correctly by ensuring proper padding and chunk sizes.
  - **Test Results Before Commit:** 
    - `test_decode_with_content_transfer_encoding_base64` failed with `binascii.Error: Incorrect padding`.
    - `test_read_with_content_transfer_encoding_binary` also failed.
  - **Test Results After Commit:** Both tests pass successfully.

- **Main Problem Highlighted by Test Results:**
  - The `BodyPartReader` was unable to correctly decode base64-encoded chunks, leading to padding errors and test failures.

- **Expected Behavior:**
  - The `BodyPartReader` should correctly decode base64-encoded data without encountering padding errors, ensuring that the entire content is accurately read and processed.

- **Actual Behavior:**
  - Decoding base64 chunks resulted in padding errors (`binascii.Error: Incorrect padding`) due to improper handling of chunk sizes and padding alignment.

- **Issue Description:**
  - The `BodyPartReader` in the `aiohttp` library fails to decode base64-encoded chunks correctly. When processing chunks that do not align with the base64 encoding requirements (multiples of 4 bytes), it leads to padding errors, causing the decoding process to fail.

---

[ISSUE]
**Title:** BodyPartReader Fails to Decode Base64 Chunks Correctly, Causing Padding Errors

**Description:**
When processing base64-encoded data, the `BodyPartReader` encounters padding errors due to incorrect handling of chunk sizes. This results in failed decoding attempts and prevents the proper reading of the content.

**Example Buggy Code:**
```python
async def test_decode_with_content_transfer_encoding_base64(self) -> None:
    with Stream(b"VG\r\r\nltZSB0byBSZ\r\nWxheCE=\r\n--:--") as stream:
        obj = aiohttp.BodyPartReader(
            BOUNDARY, {CONTENT_TRANSFER_ENCODING: "base64"}, stream
        )
        result = b""
        while not obj.at_eof():
            chunk = await obj.read_chunk(size=6)
            result += obj.decode(chunk)
    # Expected: b"Time to Relax!"
    # Actual: Raises binascii.Error: Incorrect padding
```

**Expected Behavior:**
The `BodyPartReader` should correctly decode the base64-encoded chunks without raising padding errors, resulting in the accurate reconstruction of the original data (`b"Time to Relax!"`).

**Actual Behavior:**
Decoding the provided base64 chunks raises a `binascii.Error: Incorrect padding`, indicating that the decoder is unable to handle chunks that do not align with the expected base64 padding requirements.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/multipart.py
import base64
import binascii
import json
import re
import uuid
import warnings
import zlib
from collections import deque
from types import TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    AsyncIterator,
    Deque,
    Dict,
    Iterator,
    List,
    Mapping,
    Optional,
    Sequence,
    Tuple,
    Type,
    Union,
    cast,
)
from urllib.parse import parse_qsl, unquote, urlencode

from multidict import CIMultiDict, CIMultiDictProxy

from .compression_utils import ZLibCompressor, ZLibDecompressor
from .hdrs import (
    CONTENT_DISPOSITION,
    CONTENT_ENCODING,
    CONTENT_LENGTH,
    CONTENT_TRANSFER_ENCODING,
    CONTENT_TYPE,
)
from .helpers import CHAR, TOKEN, parse_mimetype, reify
from .http import HeadersParser
from .payload import (
    JsonPayload,
    LookupError,
    Order,
    Payload,
    StringPayload,
    get_payload,
    payload_type,
)
from .streams import StreamReader

__all__ = (
    "MultipartReader",
    "MultipartWriter",
    "BodyPartReader",
    "BadContentDispositionHeader",
    "BadContentDispositionParam",
    "parse_content_disposition",
    "content_disposition_filename",
)


if TYPE_CHECKING:
    from .client_reqrep import ClientResponse


class BadContentDispositionHeader(RuntimeWarning):
    pass


class BadContentDispositionParam(RuntimeWarning):
    pass


def parse_content_disposition(
    header: Optional[str],
) -> Tuple[Optional[str], Dict[str, str]]:
    def is_token(string: str) -> bool:
        return bool(string) and TOKEN >= set(string)

    def is_quoted(string: str) -> bool:
        return string[0] == string[-1] == '"'

    def is_rfc5987(string: str) -> bool:
        return is_token(string) and string.count("'") == 2

    def is_extended_param(string: str) -> bool:
        return string.endswith("*")

    def is_continuous_param(string: str) -> bool:
        pos = string.find("*") + 1
        if not pos:
            return False
        substring = string[pos:-1] if string.endswith("*") else string[pos:]
        return substring.isdigit()

    def unescape(text: str, *, chars: str = "".join(map(re.escape, CHAR))) -> str:
        return re.sub(f"\\\\([{chars}])", "\\1", text)

    if not header:
        return None, {}

    disptype, *parts = header.split(";")
    if not is_token(disptype):
        warnings.warn(BadContentDispositionHeader(header))
        return None, {}

    params: Dict[str, str] = {}
    while parts:
        item = parts.pop(0)

        if "=" not in item:
            warnings.warn(BadContentDispositionHeader(header))
            return None, {}

        key, value = item.split("=", 1)
        key = key.lower().strip()
        value = value.lstrip()

        if key in params:
            warnings.warn(BadContentDispositionHeader(header))
            return None, {}

        if not is_token(key):
            warnings.warn(BadContentDispositionParam(item))
            continue

        elif is_continuous_param(key):
            if is_quoted(value):
                value = unescape(value[1:-1])
            elif not is_token(value):
                warnings.warn(BadContentDispositionParam(item))
                continue

        elif is_extended_param(key):
            if is_rfc5987(value):
                encoding, _, value = value.split("'", 2)
                encoding = encoding or "utf-8"
            else:
                warnings.warn(BadContentDispositionParam(item))
                continue

            try:
                value = unquote(value, encoding, "strict")
            except UnicodeDecodeError:  # pragma: nocover
                warnings.warn(BadContentDispositionParam(item))
                continue

        else:
            failed = True
            if is_quoted(value):
                failed = False
                value = unescape(value[1:-1].lstrip("\\/"))
            elif is_token(value):
                failed = False
            elif parts:
                # maybe just ; in filename, in any case this is just
                # one case fix, for proper fix we need to redesign parser
                _value = f"{value};{parts[0]}"
                if is_quoted(_value):
                    parts.pop(0)
                    value = unescape(_value[1:-1].lstrip("\\/"))
                    failed = False

            if failed:
                warnings.warn(BadContentDispositionHeader(header))
                return None, {}

        params[key] = value

    return disptype.lower(), params


def content_disposition_filename(
    params: Mapping[str, str], name: str = "filename"
) -> Optional[str]:
    name_suf = "%s*" % name
    if not params:
        return None
    elif name_suf in params:
        return params[name_suf]
    elif name in params:
        return params[name]
    else:
        parts = []
        fnparams = sorted(
            (key, value) for key, value in params.items() if key.startswith(name_suf)
        )
        for num, (key, value) in enumerate(fnparams):
            _, tail = key.split("*", 1)
            if tail.endswith("*"):
                tail = tail[:-1]
            if tail == str(num):
                parts.append(value)
            else:
                break
        if not parts:
            return None
        value = "".join(parts)
        if "'" in value:
            encoding, _, value = value.split("'", 2)
            encoding = encoding or "utf-8"
            return unquote(value, encoding, "strict")
        return value


class MultipartResponseWrapper:
    """Wrapper around the MultipartReader.

    It takes care about
    underlying connection and close it when it needs in.
    """

    def __init__(
        self,
        resp: "ClientResponse",
        stream: "MultipartReader",
    ) -> None:
        self.resp = resp
        self.stream = stream

    def __aiter__(self) -> "MultipartResponseWrapper":
        return self

    async def __anext__(
        self,
    ) -> Union["MultipartReader", "BodyPartReader"]:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    def at_eof(self) -> bool:
        """Returns True when all response data had been read."""
        return self.resp.content.at_eof()

    async def next(
        self,
    ) -> Optional[Union["MultipartReader", "BodyPartReader"]]:
        """Emits next multipart reader object."""
        item = await self.stream.next()
        if self.stream.at_eof():
            await self.release()
        return item

    async def release(self) -> None:
        """Release the connection gracefully.

        All remaining content is read to the void.
        """
        await self.resp.release()


class BodyPartReader:
    """Multipart reader for single body part."""

    chunk_size = 8192

    def __init__(
        self,
        boundary: bytes,
        headers: "CIMultiDictProxy[str]",
        content: StreamReader,
        *,
        subtype: str = "mixed",
        default_charset: Optional[str] = None,
    ) -> None:
        self.headers = headers
        self._boundary = boundary
        self._boundary_len = len(boundary) + 2  # Boundary + \r\n
        self._content = content
        self._default_charset = default_charset
        self._at_eof = False
        self._is_form_data = subtype == "form-data"
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)
        self._length = int(length) if length is not None else None
        self._read_bytes = 0
        self._unread: Deque[bytes] = deque()
        self._prev_chunk: Optional[bytes] = None
        self._content_eof = 0
        self._cache: Dict[str, Any] = {}

    def __aiter__(self) -> AsyncIterator["BodyPartReader"]:
        return self  # type: ignore[return-value]

    async def __anext__(self) -> bytes:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    async def next(self) -> Optional[bytes]:
        item = await self.read()
        if not item:
            return None
        return item

    async def read(self, *, decode: bool = False) -> bytes:
        """Reads body part data.

        decode: Decodes data following by encoding
                method from Content-Encoding header. If it missed
                data remains untouched
        """
        if self._at_eof:
            return b""
        data = bytearray()
        while not self._at_eof:
            data.extend(await self.read_chunk(self.chunk_size))
        if decode:
            return self.decode(data)
        return data

    async def read_chunk(self, size: int = chunk_size) -> bytes:
        """Reads body part content chunk of the specified size.

        size: chunk size
        """
        if self._at_eof:
            return b""
        if self._length:
            chunk = await self._read_chunk_from_length(size)
        else:
            chunk = await self._read_chunk_from_stream(size)

        self._read_bytes += len(chunk)
        if self._read_bytes == self._length:
            self._at_eof = True
        if self._at_eof:
            clrf = await self._content.readline()
            assert (
                b"\r\n" == clrf
            ), "reader did not read all the data or it is malformed"
        return chunk

    async def _read_chunk_from_length(self, size: int) -> bytes:
        # 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)
        chunk = await self._content.read(chunk_size)
        if self._content.at_eof():
            self._at_eof = True
        return chunk

    async def _read_chunk_from_stream(self, size: int) -> bytes:
        # Reads content chunk of body part with unknown length.
        # The Content-Length header for body part is not necessary.
        assert (
            size >= self._boundary_len
        ), "Chunk size must be greater or equal than boundary length + 2"
        first_chunk = self._prev_chunk is None
        if first_chunk:
            self._prev_chunk = await self._content.read(size)

        chunk = b""
        # content.read() may return less than size, so we need to loop to ensure
        # we have enough data to detect the boundary.
        while len(chunk) < self._boundary_len:
            chunk += await self._content.read(size)
            self._content_eof += int(self._content.at_eof())
            assert self._content_eof < 3, "Reading after EOF"
            if self._content_eof:
                break
        if len(chunk) > size:
            self._content.unread_data(chunk[size:])
            chunk = chunk[:size]

        assert self._prev_chunk is not None
        window = self._prev_chunk + chunk
        sub = b"\r\n" + self._boundary
        if first_chunk:
            idx = window.find(sub)
        else:
            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))
        if idx >= 0:
            # pushing boundary back to content
            with warnings.catch_warnings():
                warnings.filterwarnings("ignore", category=DeprecationWarning)
                self._content.unread_data(window[idx:])
            if size > idx:
                self._prev_chunk = self._prev_chunk[:idx]
            chunk = window[len(self._prev_chunk) : idx]
            if not chunk:
                self._at_eof = True
        result = self._prev_chunk
        self._prev_chunk = chunk
        return result

    async def readline(self) -> bytes:
        """Reads body part by line by line."""
        if self._at_eof:
            return b""

        if self._unread:
            line = self._unread.popleft()
        else:
            line = await self._content.readline()

        if line.startswith(self._boundary):
            # the very last boundary may not come with \r\n,
            # so set single rules for everyone
            sline = line.rstrip(b"\r\n")
            boundary = self._boundary
            last_boundary = self._boundary + b"--"
            # ensure that we read exactly the boundary, not something alike
            if sline == boundary or sline == last_boundary:
                self._at_eof = True
                self._unread.append(line)
                return b""
        else:
            next_line = await self._content.readline()
            if next_line.startswith(self._boundary):
                line = line[:-2]  # strip CRLF but only once
            self._unread.append(next_line)

        return line

    async def release(self) -> None:
        """Like read(), but reads all the data to the void."""
        if self._at_eof:
            return
        while not self._at_eof:
            await self.read_chunk(self.chunk_size)

    async def text(self, *, encoding: Optional[str] = None) -> str:
        """Like read(), but assumes that body part contains text data."""
        data = await self.read(decode=True)
        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm
        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send
        encoding = encoding or self.get_charset(default="utf-8")
        return data.decode(encoding)

    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:
        """Like read(), but assumes that body parts contains JSON data."""
        data = await self.read(decode=True)
        if not data:
            return None
        encoding = encoding or self.get_charset(default="utf-8")
        return cast(Dict[str, Any], json.loads(data.decode(encoding)))

    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:
        """Like read(), but assumes that body parts contain form urlencoded data."""
        data = await self.read(decode=True)
        if not data:
            return []
        if encoding is not None:
            real_encoding = encoding
        else:
            real_encoding = self.get_charset(default="utf-8")
        try:
            decoded_data = data.rstrip().decode(real_encoding)
        except UnicodeDecodeError:
            raise ValueError("data cannot be decoded with %s encoding" % real_encoding)

        return parse_qsl(
            decoded_data,
            keep_blank_values=True,
            encoding=real_encoding,
        )

    def at_eof(self) -> bool:
        """Returns True if the boundary was reached or False otherwise."""
        return self._at_eof

    def decode(self, data: bytes) -> bytes:
        """Decodes data.

        Decoding is done according the specified Content-Encoding
        or Content-Transfer-Encoding headers value.
        """
        if CONTENT_TRANSFER_ENCODING in self.headers:
            data = self._decode_content_transfer(data)
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
        if not self._is_form_data and CONTENT_ENCODING in self.headers:
            return self._decode_content(data)
        return data

    def _decode_content(self, data: bytes) -> bytes:
        encoding = self.headers.get(CONTENT_ENCODING, "").lower()
        if encoding == "identity":
            return data
        if encoding in {"deflate", "gzip"}:
            return ZLibDecompressor(
                encoding=encoding,
                suppress_deflate_header=True,
            ).decompress_sync(data)

        raise RuntimeError(f"unknown content encoding: {encoding}")

    def _decode_content_transfer(self, data: bytes) -> bytes:
        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower()

        if encoding == "base64":
            return base64.b64decode(data)
        elif encoding == "quoted-printable":
            return binascii.a2b_qp(data)
        elif encoding in ("binary", "8bit", "7bit"):
            return data
        else:
            raise RuntimeError(
                "unknown content transfer encoding: {}" "".format(encoding)
            )

    def get_charset(self, default: str) -> str:
        """Returns charset parameter from Content-Type header or default."""
        ctype = self.headers.get(CONTENT_TYPE, "")
        mimetype = parse_mimetype(ctype)
        return mimetype.parameters.get("charset", self._default_charset or default)

    @reify
    def name(self) -> Optional[str]:
        """Returns name specified in Content-Disposition header.

        If the header is missing or malformed, returns None.
        """
        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))
        return content_disposition_filename(params, "name")

    @reify
    def filename(self) -> Optional[str]:
        """Returns filename specified in Content-Disposition header.

        Returns None if the header is missing or malformed.
        """
        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))
        return content_disposition_filename(params, "filename")


@payload_type(BodyPartReader, order=Order.try_first)
class BodyPartReaderPayload(Payload):
    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:
        super().__init__(value, *args, **kwargs)

        params: Dict[str, str] = {}
        if value.name is not None:
            params["name"] = value.name
        if value.filename is not None:
            params["filename"] = value.filename

        if params:
            self.set_content_disposition("attachment", True, **params)

    async def write(self, writer: Any) -> None:
        field = self._value
        chunk = await field.read_chunk(size=2**16)
        while chunk:
            await writer.write(field.decode(chunk))
            chunk = await field.read_chunk(size=2**16)


class MultipartReader:
    """Multipart body reader."""

    #: Response wrapper, used when multipart readers constructs from response.
    response_wrapper_cls = MultipartResponseWrapper
    #: Multipart reader class, used to handle multipart/* body parts.
    #: None points to type(self)
    multipart_reader_cls = None
    #: Body part reader class for non multipart/* content types.
    part_reader_cls = BodyPartReader

    def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None:
        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])
        assert self._mimetype.type == "multipart", "multipart/* content type expected"
        if "boundary" not in self._mimetype.parameters:
            raise ValueError(
                "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE]
            )

        self.headers = headers
        self._boundary = ("--" + self._get_boundary()).encode()
        self._content = content
        self._default_charset: Optional[str] = None
        self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None
        self._at_eof = False
        self._at_bof = True
        self._unread: List[bytes] = []

    def __aiter__(
        self,
    ) -> AsyncIterator["BodyPartReader"]:
        return self  # type: ignore[return-value]

    async def __anext__(
        self,
    ) -> Optional[Union["MultipartReader", BodyPartReader]]:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    @classmethod
    def from_response(
        cls,
        response: "ClientResponse",
    ) -> MultipartResponseWrapper:
        """Constructs reader instance from HTTP response.

        :param response: :class:`~aiohttp.client.ClientResponse` instance
        """
        obj = cls.response_wrapper_cls(
            response, cls(response.headers, response.content)
        )
        return obj

    def at_eof(self) -> bool:
        """Returns True if the final boundary was reached, false otherwise."""
        return self._at_eof

    async def next(
        self,
    ) -> Optional[Union["MultipartReader", BodyPartReader]]:
        """Emits the next multipart body part."""
        # So, if we're at BOF, we need to skip till the boundary.
        if self._at_eof:
            return None
        await self._maybe_release_last_part()
        if self._at_bof:
            await self._read_until_first_boundary()
            self._at_bof = False
        else:
            await self._read_boundary()
        if self._at_eof:  # we just read the last boundary, nothing to do there
            return None

        part = await self.fetch_next_part()
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6
        if (
            self._last_part is None
            and self._mimetype.subtype == "form-data"
            and isinstance(part, BodyPartReader)
        ):
            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))
            if params.get("name") == "_charset_":
                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json
                # is 19 characters, so 32 should be more than enough for any valid encoding.
                charset = await part.read_chunk(32)
                if len(charset) > 31:
                    raise RuntimeError("Invalid default charset")
                self._default_charset = charset.strip().decode()
                part = await self.fetch_next_part()
        self._last_part = part
        return self._last_part

    async def release(self) -> None:
        """Reads all the body parts to the void till the final boundary."""
        while not self._at_eof:
            item = await self.next()
            if item is None:
                break
            await item.release()

    async def fetch_next_part(
        self,
    ) -> Union["MultipartReader", BodyPartReader]:
        """Returns the next body part reader."""
        headers = await self._read_headers()
        return self._get_part_reader(headers)

    def _get_part_reader(
        self,
        headers: "CIMultiDictProxy[str]",
    ) -> Union["MultipartReader", BodyPartReader]:
        """Dispatches the response by the `Content-Type` header.

        Returns a suitable reader instance.

        :param dict headers: Response headers
        """
        ctype = headers.get(CONTENT_TYPE, "")
        mimetype = parse_mimetype(ctype)

        if mimetype.type == "multipart":
            if self.multipart_reader_cls is None:
                return type(self)(headers, self._content)
            return self.multipart_reader_cls(headers, self._content)
        else:
            return self.part_reader_cls(
                self._boundary,
                headers,
                self._content,
                subtype=self._mimetype.subtype,
                default_charset=self._default_charset,
            )

    def _get_boundary(self) -> str:
        boundary = self._mimetype.parameters["boundary"]
        if len(boundary) > 70:
            raise ValueError("boundary %r is too long (70 chars max)" % boundary)

        return boundary

    async def _readline(self) -> bytes:
        if self._unread:
            return self._unread.pop()
        return await self._content.readline()

    async def _read_until_first_boundary(self) -> None:
        while True:
            chunk = await self._readline()
            if chunk == b"":
                raise ValueError(
                    "Could not find starting boundary %r" % (self._boundary)
                )
            chunk = chunk.rstrip()
            if chunk == self._boundary:
                return
            elif chunk == self._boundary + b"--":
                self._at_eof = True
                return

    async def _read_boundary(self) -> None:
        chunk = (await self._readline()).rstrip()
        if chunk == self._boundary:
            pass
        elif chunk == self._boundary + b"--":
            self._at_eof = True
            epilogue = await self._readline()
            next_line = await self._readline()

            # the epilogue is expected and then either the end of input or the
            # parent multipart boundary, if the parent boundary is found then
            # it should be marked as unread and handed to the parent for
            # processing
            if next_line[:2] == b"--":
                self._unread.append(next_line)
            # otherwise the request is likely missing an epilogue and both
            # lines should be passed to the parent for processing
            # (this handles the old behavior gracefully)
            else:
                self._unread.extend([next_line, epilogue])
        else:
            raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}")

    async def _read_headers(self) -> "CIMultiDictProxy[str]":
        lines = [b""]
        while True:
            chunk = await self._content.readline()
            chunk = chunk.strip()
            lines.append(chunk)
            if not chunk:
                break
        parser = HeadersParser()
        headers, raw_headers = parser.parse_headers(lines)
        return headers

    async def _maybe_release_last_part(self) -> None:
        """Ensures that the last read body part is read completely."""
        if self._last_part is not None:
            if not self._last_part.at_eof():
                await self._last_part.release()
            self._unread.extend(self._last_part._unread)
            self._last_part = None


_Part = Tuple[Payload, str, str]


class MultipartWriter(Payload):
    """Multipart body writer."""

    def __init__(self, subtype: str = "mixed", boundary: Optional[str] = None) -> None:
        boundary = boundary if boundary is not None else uuid.uuid4().hex
        # The underlying Payload API demands a str (utf-8), not bytes,
        # so we need to ensure we don't lose anything during conversion.
        # As a result, require the boundary to be ASCII only.
        # In both situations.

        try:
            self._boundary = boundary.encode("ascii")
        except UnicodeEncodeError:
            raise ValueError("boundary should contain ASCII only chars") from None
        ctype = f"multipart/{subtype}; boundary={self._boundary_value}"

        super().__init__(None, content_type=ctype)

        self._parts: List[_Part] = []
        self._is_form_data = subtype == "form-data"

    def __enter__(self) -> "MultipartWriter":
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> None:
        pass

    def __iter__(self) -> Iterator[_Part]:
        return iter(self._parts)

    def __len__(self) -> int:
        return len(self._parts)

    def __bool__(self) -> bool:
        return True

    _valid_tchar_regex = re.compile(rb"\A[!#$%&'*+\-.^_`|~\w]+\Z")
    _invalid_qdtext_char_regex = re.compile(rb"[\x00-\x08\x0A-\x1F\x7F]")

    @property
    def _boundary_value(self) -> str:
        """Wrap boundary parameter value in quotes, if necessary.

        Reads self.boundary and returns a unicode string.
        """
        # Refer to RFCs 7231, 7230, 5234.
        #
        # parameter      = token "=" ( token / quoted-string )
        # token          = 1*tchar
        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE
        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
        # obs-text       = %x80-FF
        # quoted-pair    = "\" ( HTAB / SP / VCHAR / obs-text )
        # tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
        #                  / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
        #                  / DIGIT / ALPHA
        #                  ; any VCHAR, except delimiters
        # VCHAR           = %x21-7E
        value = self._boundary
        if re.match(self._valid_tchar_regex, value):
            return value.decode("ascii")  # cannot fail

        if re.search(self._invalid_qdtext_char_regex, value):
            raise ValueError("boundary value contains invalid characters")

        # escape %x5C and %x22
        quoted_value_content = value.replace(b"\\", b"\\\\")
        quoted_value_content = quoted_value_content.replace(b'"', b'\\"')

        return '"' + quoted_value_content.decode("ascii") + '"'

    @property
    def boundary(self) -> str:
        return self._boundary.decode("ascii")

    def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload:
        if headers is None:
            headers = CIMultiDict()

        if isinstance(obj, Payload):
            obj.headers.update(headers)
            return self.append_payload(obj)
        else:
            try:
                payload = get_payload(obj, headers=headers)
            except LookupError:
                raise TypeError("Cannot create payload from %r" % obj)
            else:
                return self.append_payload(payload)

    def append_payload(self, payload: Payload) -> Payload:
        """Adds a new body part to multipart writer."""
        encoding: Optional[str] = None
        te_encoding: Optional[str] = None
        if self._is_form_data:
            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7
            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
            assert (
                not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING}
                & payload.headers.keys()
            )
            # Set default Content-Disposition in case user doesn't create one
            if CONTENT_DISPOSITION not in payload.headers:
                name = f"section-{len(self._parts)}"
                payload.set_content_disposition("form-data", name=name)
        else:
            # compression
            encoding = payload.headers.get(CONTENT_ENCODING, "").lower()
            if encoding and encoding not in ("deflate", "gzip", "identity"):
                raise RuntimeError(f"unknown content encoding: {encoding}")
            if encoding == "identity":
                encoding = None

            # te encoding
            te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower()
            if te_encoding not in ("", "base64", "quoted-printable", "binary"):
                raise RuntimeError(f"unknown content transfer encoding: {te_encoding}")
            if te_encoding == "binary":
                te_encoding = None

            # size
            size = payload.size
            if size is not None and not (encoding or te_encoding):
                payload.headers[CONTENT_LENGTH] = str(size)

        self._parts.append((payload, encoding, te_encoding))  # type: ignore[arg-type]
        return payload

    def append_json(
        self, obj: Any, headers: Optional[Mapping[str, str]] = None
    ) -> Payload:
        """Helper to append JSON part."""
        if headers is None:
            headers = CIMultiDict()

        return self.append_payload(JsonPayload(obj, headers=headers))

    def append_form(
        self,
        obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]],
        headers: Optional[Mapping[str, str]] = None,
    ) -> Payload:
        """Helper to append form urlencoded part."""
        assert isinstance(obj, (Sequence, Mapping))

        if headers is None:
            headers = CIMultiDict()

        if isinstance(obj, Mapping):
            obj = list(obj.items())
        data = urlencode(obj, doseq=True)

        return self.append_payload(
            StringPayload(
                data, headers=headers, content_type="application/x-www-form-urlencoded"
            )
        )

    @property
    def size(self) -> Optional[int]:
        """Size of the payload."""
        total = 0
        for part, encoding, te_encoding in self._parts:
            if encoding or te_encoding or part.size is None:
                return None

            total += int(
                2
                + len(self._boundary)
                + 2
                + part.size  # b'--'+self._boundary+b'\r\n'
                + len(part._binary_headers)
                + 2  # b'\r\n'
            )

        total += 2 + len(self._boundary) + 4  # b'--'+self._boundary+b'--\r\n'
        return total

    async def write(self, writer: Any, close_boundary: bool = True) -> None:
        """Write body."""
        for part, encoding, te_encoding in self._parts:
            if self._is_form_data:
                # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2
                assert CONTENT_DISPOSITION in part.headers
                assert "name=" in part.headers[CONTENT_DISPOSITION]

            await writer.write(b"--" + self._boundary + b"\r\n")
            await writer.write(part._binary_headers)

            if encoding or te_encoding:
                w = MultipartPayloadWriter(writer)
                if encoding:
                    w.enable_compression(encoding)
                if te_encoding:
                    w.enable_encoding(te_encoding)
                await part.write(w)  # type: ignore[arg-type]
                await w.write_eof()
            else:
                await part.write(writer)

            await writer.write(b"\r\n")

        if close_boundary:
            await writer.write(b"--" + self._boundary + b"--\r\n")


class MultipartPayloadWriter:
    def __init__(self, writer: Any) -> None:
        self._writer = writer
        self._encoding: Optional[str] = None
        self._compress: Optional[ZLibCompressor] = None
        self._encoding_buffer: Optional[bytearray] = None

    def enable_encoding(self, encoding: str) -> None:
        if encoding == "base64":
            self._encoding = encoding
            self._encoding_buffer = bytearray()
        elif encoding == "quoted-printable":
            self._encoding = "quoted-printable"

    def enable_compression(
        self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY
    ) -> None:
        self._compress = ZLibCompressor(
            encoding=encoding,
            suppress_deflate_header=True,
            strategy=strategy,
        )

    async def write_eof(self) -> None:
        if self._compress is not None:
            chunk = self._compress.flush()
            if chunk:
                self._compress = None
                await self.write(chunk)

        if self._encoding == "base64":
            if self._encoding_buffer:
                await self._writer.write(base64.b64encode(self._encoding_buffer))

    async def write(self, chunk: bytes) -> None:
        if self._compress is not None:
            if chunk:
                chunk = await self._compress.compress(chunk)
                if not chunk:
                    return

        if self._encoding == "base64":
            buf = self._encoding_buffer
            assert buf is not None
            buf.extend(chunk)

            if buf:
                div, mod = divmod(len(buf), 3)
                enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :])
                if enc_chunk:
                    b64chunk = base64.b64encode(enc_chunk)
                    await self._writer.write(b64chunk)
        elif self._encoding == "quoted-printable":
            await self._writer.write(binascii.b2a_qp(chunk))
        else:
            await self._writer.write(chunk)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
**Analysis:**

- **Key Parts from Commit Details and Test Results:**
  - **Commit Message:** "Fix decoding base64 chunk for BodyPartReader"
  - **Changes:** Added logic to handle base64-encoded chunks correctly by ensuring proper padding and chunk sizes.
  - **Test Results Before Commit:** 
    - `test_decode_with_content_transfer_encoding_base64` failed with `binascii.Error: Incorrect padding`.
    - `test_read_with_content_transfer_encoding_binary` also failed.
  - **Test Results After Commit:** Both tests pass successfully.

- **Main Problem Highlighted by Test Results:**
  - The `BodyPartReader` was unable to correctly decode base64-encoded chunks, leading to padding errors and test failures.

- **Expected Behavior:**
  - The `BodyPartReader` should correctly decode base64-encoded data without encountering padding errors, ensuring that the entire content is accurately read and processed.

- **Actual Behavior:**
  - Decoding base64 chunks resulted in padding errors (`binascii.Error: Incorrect padding`) due to improper handling of chunk sizes and padding alignment.

- **Issue Description:**
  - The `BodyPartReader` in the `aiohttp` library fails to decode base64-encoded chunks correctly. When processing chunks that do not align with the base64 encoding requirements (multiples of 4 bytes), it leads to padding errors, causing the decoding process to fail.

---

[ISSUE]
**Title:** BodyPartReader Fails to Decode Base64 Chunks Correctly, Causing Padding Errors

**Description:**
When processing base64-encoded data, the `BodyPartReader` encounters padding errors due to incorrect handling of chunk sizes. This results in failed decoding attempts and prevents the proper reading of the content.

**Example Buggy Code:**
```python
async def test_decode_with_content_transfer_encoding_base64(self) -> None:
    with Stream(b"VG\r\r\nltZSB0byBSZ\r\nWxheCE=\r\n--:--") as stream:
        obj = aiohttp.BodyPartReader(
            BOUNDARY, {CONTENT_TRANSFER_ENCODING: "base64"}, stream
        )
        result = b""
        while not obj.at_eof():
            chunk = await obj.read_chunk(size=6)
            result += obj.decode(chunk)
    # Expected: b"Time to Relax!"
    # Actual: Raises binascii.Error: Incorrect padding
```

**Expected Behavior:**
The `BodyPartReader` should correctly decode the base64-encoded chunks without raising padding errors, resulting in the accurate reconstruction of the original data (`b"Time to Relax!"`).

**Actual Behavior:**
Decoding the provided base64 chunks raises a `binascii.Error: Incorrect padding`, indicating that the decoder is unable to handle chunks that do not align with the expected base64 padding requirements.

[/ISSUE]
{
    "TestMultipartResponseWrapper.test_at_eof": "PASSED",
    "TestMultipartResponseWrapper.test_next": "PASSED",
    "TestMultipartResponseWrapper.test_release": "PASSED",
    "TestMultipartResponseWrapper.test_release_when_stream_at_eof": "PASSED",
    "TestPartReader.test_next": "PASSED",
    "TestPartReader.test_next_next": "PASSED",
    "TestPartReader.test_read": "PASSED",
    "TestPartReader.test_read_chunk_at_eof": "PASSED",
    "TestPartReader.test_read_chunk_without_content_length": "PASSED",
    "TestPartReader.test_read_incomplete_chunk": "PASSED",
    "TestPartReader.test_read_all_at_once": "PASSED",
    "TestPartReader.test_read_incomplete_body_chunked": "PASSED",
    "TestPartReader.test_read_boundary_with_incomplete_chunk": "PASSED",
    "TestPartReader.test_multi_read_chunk": "PASSED",
    "TestPartReader.test_read_chunk_properly_counts_read_bytes": "PASSED",
    "TestPartReader.test_read_does_not_read_boundary": "PASSED",
    "TestPartReader.test_multiread": "PASSED",
    "TestPartReader.test_read_multiline": "PASSED",
    "TestPartReader.test_read_respects_content_length": "PASSED",
    "TestPartReader.test_read_with_content_encoding_gzip": "PASSED",
    "TestPartReader.test_read_with_content_encoding_deflate": "PASSED",
    "TestPartReader.test_read_with_content_encoding_identity": "PASSED",
    "TestPartReader.test_read_with_content_encoding_unknown": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_base64": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_quoted_printable": "PASSED",
    "TestPartReader.test_decode_with_content_transfer_encoding_base64": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_binary[binary]": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_binary[8bit]": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_binary[7bit]": "PASSED",
    "TestPartReader.test_read_with_content_transfer_encoding_unknown": "PASSED",
    "TestPartReader.test_read_text": "PASSED",
    "TestPartReader.test_read_text_default_encoding": "PASSED",
    "TestPartReader.test_read_text_encoding": "PASSED",
    "TestPartReader.test_read_text_guess_encoding": "PASSED",
    "TestPartReader.test_read_text_compressed": "PASSED",
    "TestPartReader.test_read_text_while_closed": "PASSED",
    "TestPartReader.test_read_json": "PASSED",
    "TestPartReader.test_read_json_encoding": "PASSED",
    "TestPartReader.test_read_json_guess_encoding": "PASSED",
    "TestPartReader.test_read_json_compressed": "PASSED",
    "TestPartReader.test_read_json_while_closed": "PASSED",
    "TestPartReader.test_read_form": "PASSED",
    "TestPartReader.test_read_form_invalid_utf8": "PASSED",
    "TestPartReader.test_read_form_encoding": "PASSED",
    "TestPartReader.test_read_form_guess_encoding": "PASSED",
    "TestPartReader.test_read_form_while_closed": "PASSED",
    "TestPartReader.test_readline": "PASSED",
    "TestPartReader.test_release": "PASSED",
    "TestPartReader.test_release_respects_content_length": "PASSED",
    "TestPartReader.test_release_release": "PASSED",
    "TestPartReader.test_filename": "PASSED",
    "TestPartReader.test_reading_long_part": "PASSED",
    "TestMultipartReader.test_from_response": "PASSED",
    "TestMultipartReader.test_bad_boundary": "PASSED",
    "TestMultipartReader.test_dispatch": "PASSED",
    "TestMultipartReader.test_dispatch_bodypart": "PASSED",
    "TestMultipartReader.test_dispatch_multipart": "PASSED",
    "TestMultipartReader.test_dispatch_custom_multipart_reader": "PASSED",
    "TestMultipartReader.test_emit_next": "PASSED",
    "TestMultipartReader.test_invalid_boundary": "PASSED",
    "TestMultipartReader.test_release": "PASSED",
    "TestMultipartReader.test_release_release": "PASSED",
    "TestMultipartReader.test_release_next": "PASSED",
    "TestMultipartReader.test_second_next_releases_previous_object": "PASSED",
    "TestMultipartReader.test_release_without_read_the_last_object": "PASSED",
    "TestMultipartReader.test_read_chunk_by_length_doesnt_breaks_reader": "PASSED",
    "TestMultipartReader.test_read_chunk_from_stream_doesnt_breaks_reader": "PASSED",
    "TestMultipartReader.test_reading_skips_prelude": "PASSED",
    "TestMultipartReader.test_read_form_default_encoding": "PASSED",
    "TestMultipartReader.test_read_form_invalid_default_encoding": "PASSED",
    "test_writer": "PASSED",
    "test_writer_serialize_io_chunk": "PASSED",
    "test_writer_serialize_json": "PASSED",
    "test_writer_serialize_form": "PASSED",
    "test_writer_serialize_form_dict": "PASSED",
    "test_writer_write": "PASSED",
    "test_writer_write_no_close_boundary": "PASSED",
    "test_writer_write_no_parts": "PASSED",
    "test_writer_serialize_with_content_encoding_gzip": "PASSED",
    "test_writer_serialize_with_content_encoding_deflate": "PASSED",
    "test_writer_serialize_with_content_encoding_identity": "PASSED",
    "test_writer_serialize_with_content_encoding_unknown": "PASSED",
    "test_writer_with_content_transfer_encoding_base64": "PASSED",
    "test_writer_content_transfer_encoding_quote_printable": "PASSED",
    "test_writer_content_transfer_encoding_unknown": "PASSED",
    "TestMultipartWriter.test_default_subtype": "PASSED",
    "TestMultipartWriter.test_unquoted_boundary": "PASSED",
    "TestMultipartWriter.test_quoted_boundary": "PASSED",
    "TestMultipartWriter.test_bad_boundary": "PASSED",
    "TestMultipartWriter.test_default_headers": "PASSED",
    "TestMultipartWriter.test_iter_parts": "PASSED",
    "TestMultipartWriter.test_append": "PASSED",
    "TestMultipartWriter.test_append_with_headers": "PASSED",
    "TestMultipartWriter.test_append_json": "PASSED",
    "TestMultipartWriter.test_append_part": "PASSED",
    "TestMultipartWriter.test_append_json_overrides_content_type": "PASSED",
    "TestMultipartWriter.test_append_form": "PASSED",
    "TestMultipartWriter.test_append_multipart": "PASSED",
    "TestMultipartWriter.test_set_content_disposition_after_append": "PASSED",
    "TestMultipartWriter.test_automatic_content_disposition": "PASSED",
    "TestMultipartWriter.test_with": "PASSED",
    "TestMultipartWriter.test_append_int_not_allowed": "PASSED",
    "TestMultipartWriter.test_append_float_not_allowed": "PASSED",
    "TestMultipartWriter.test_append_none_not_allowed": "PASSED",
    "TestMultipartWriter.test_write_preserves_content_disposition": "PASSED",
    "TestMultipartWriter.test_preserve_content_disposition_header": "PASSED",
    "TestMultipartWriter.test_set_content_disposition_override": "PASSED",
    "TestMultipartWriter.test_reset_content_disposition_header": "PASSED",
    "test_async_for_reader": "PASSED",
    "test_async_for_bodypart": "PASSED"
}
diff --git a/aiohttp/multipart.py b/aiohttp/multipart.py
index 26780e30..da016039 100644
--- a/aiohttp/multipart.py
+++ b/aiohttp/multipart.py
@@ -323,6 +323,31 @@ class BodyPartReader:
         else:
             chunk = await self._read_chunk_from_stream(size)
 
+        # For the case of base64 data, we must read a fragment of size with a
+        # remainder of 0 by dividing by 4 for string without symbols \n or \r
+        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING)
+        if encoding and encoding.lower() == "base64":
+            stripped_chunk = b"".join(chunk.split())
+            remainder = len(stripped_chunk) % 4
+
+            while remainder != 0 and not self.at_eof():
+                over_chunk_size = 4 - remainder
+                over_chunk = b""
+
+                if self._prev_chunk:
+                    over_chunk = self._prev_chunk[:over_chunk_size]
+                    self._prev_chunk = self._prev_chunk[len(over_chunk) :]
+
+                if len(over_chunk) != over_chunk_size:
+                    over_chunk += await self._content.read(4 - len(over_chunk))
+
+                if not over_chunk:
+                    self._at_eof = True
+
+                stripped_chunk += b"".join(over_chunk.split())
+                chunk += over_chunk
+                remainder = len(stripped_chunk) % 4
+
         self._read_bytes += len(chunk)
         if self._read_bytes == self._length:
             self._at_eof = True

{"aiohttp/multipart.py": "import base64\nimport binascii\nimport json\nimport re\nimport uuid\nimport warnings\nimport zlib\nfrom collections import deque\nfrom types import TracebackType\nfrom typing import (\n    TYPE_CHECKING,\n    Any,\n    AsyncIterator,\n    Deque,\n    Dict,\n    Iterator,\n    List,\n    Mapping,\n    Optional,\n    Sequence,\n    Tuple,\n    Type,\n    Union,\n    cast,\n)\nfrom urllib.parse import parse_qsl, unquote, urlencode\n\nfrom multidict import CIMultiDict, CIMultiDictProxy\n\nfrom .compression_utils import ZLibCompressor, ZLibDecompressor\nfrom .hdrs import (\n    CONTENT_DISPOSITION,\n    CONTENT_ENCODING,\n    CONTENT_LENGTH,\n    CONTENT_TRANSFER_ENCODING,\n    CONTENT_TYPE,\n)\nfrom .helpers import CHAR, TOKEN, parse_mimetype, reify\nfrom .http import HeadersParser\nfrom .payload import (\n    JsonPayload,\n    LookupError,\n    Order,\n    Payload,\n    StringPayload,\n    get_payload,\n    payload_type,\n)\nfrom .streams import StreamReader\n\n__all__ = (\n    \"MultipartReader\",\n    \"MultipartWriter\",\n    \"BodyPartReader\",\n    \"BadContentDispositionHeader\",\n    \"BadContentDispositionParam\",\n    \"parse_content_disposition\",\n    \"content_disposition_filename\",\n)\n\n\nif TYPE_CHECKING:\n    from .client_reqrep import ClientResponse\n\n\nclass BadContentDispositionHeader(RuntimeWarning):\n    pass\n\n\nclass BadContentDispositionParam(RuntimeWarning):\n    pass\n\n\ndef parse_content_disposition(\n    header: Optional[str],\n) -> Tuple[Optional[str], Dict[str, str]]:\n    def is_token(string: str) -> bool:\n        return bool(string) and TOKEN >= set(string)\n\n    def is_quoted(string: str) -> bool:\n        return string[0] == string[-1] == '\"'\n\n    def is_rfc5987(string: str) -> bool:\n        return is_token(string) and string.count(\"'\") == 2\n\n    def is_extended_param(string: str) -> bool:\n        return string.endswith(\"*\")\n\n    def is_continuous_param(string: str) -> bool:\n        pos = string.find(\"*\") + 1\n        if not pos:\n            return False\n        substring = string[pos:-1] if string.endswith(\"*\") else string[pos:]\n        return substring.isdigit()\n\n    def unescape(text: str, *, chars: str = \"\".join(map(re.escape, CHAR))) -> str:\n        return re.sub(f\"\\\\\\\\([{chars}])\", \"\\\\1\", text)\n\n    if not header:\n        return None, {}\n\n    disptype, *parts = header.split(\";\")\n    if not is_token(disptype):\n        warnings.warn(BadContentDispositionHeader(header))\n        return None, {}\n\n    params: Dict[str, str] = {}\n    while parts:\n        item = parts.pop(0)\n\n        if \"=\" not in item:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        key, value = item.split(\"=\", 1)\n        key = key.lower().strip()\n        value = value.lstrip()\n\n        if key in params:\n            warnings.warn(BadContentDispositionHeader(header))\n            return None, {}\n\n        if not is_token(key):\n            warnings.warn(BadContentDispositionParam(item))\n            continue\n\n        elif is_continuous_param(key):\n            if is_quoted(value):\n                value = unescape(value[1:-1])\n            elif not is_token(value):\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        elif is_extended_param(key):\n            if is_rfc5987(value):\n                encoding, _, value = value.split(\"'\", 2)\n                encoding = encoding or \"utf-8\"\n            else:\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n            try:\n                value = unquote(value, encoding, \"strict\")\n            except UnicodeDecodeError:  # pragma: nocover\n                warnings.warn(BadContentDispositionParam(item))\n                continue\n\n        else:\n            failed = True\n            if is_quoted(value):\n                failed = False\n                value = unescape(value[1:-1].lstrip(\"\\\\/\"))\n            elif is_token(value):\n                failed = False\n            elif parts:\n                # maybe just ; in filename, in any case this is just\n                # one case fix, for proper fix we need to redesign parser\n                _value = f\"{value};{parts[0]}\"\n                if is_quoted(_value):\n                    parts.pop(0)\n                    value = unescape(_value[1:-1].lstrip(\"\\\\/\"))\n                    failed = False\n\n            if failed:\n                warnings.warn(BadContentDispositionHeader(header))\n                return None, {}\n\n        params[key] = value\n\n    return disptype.lower(), params\n\n\ndef content_disposition_filename(\n    params: Mapping[str, str], name: str = \"filename\"\n) -> Optional[str]:\n    name_suf = \"%s*\" % name\n    if not params:\n        return None\n    elif name_suf in params:\n        return params[name_suf]\n    elif name in params:\n        return params[name]\n    else:\n        parts = []\n        fnparams = sorted(\n            (key, value) for key, value in params.items() if key.startswith(name_suf)\n        )\n        for num, (key, value) in enumerate(fnparams):\n            _, tail = key.split(\"*\", 1)\n            if tail.endswith(\"*\"):\n                tail = tail[:-1]\n            if tail == str(num):\n                parts.append(value)\n            else:\n                break\n        if not parts:\n            return None\n        value = \"\".join(parts)\n        if \"'\" in value:\n            encoding, _, value = value.split(\"'\", 2)\n            encoding = encoding or \"utf-8\"\n            return unquote(value, encoding, \"strict\")\n        return value\n\n\nclass MultipartResponseWrapper:\n    \"\"\"Wrapper around the MultipartReader.\n\n    It takes care about\n    underlying connection and close it when it needs in.\n    \"\"\"\n\n    def __init__(\n        self,\n        resp: \"ClientResponse\",\n        stream: \"MultipartReader\",\n    ) -> None:\n        self.resp = resp\n        self.stream = stream\n\n    def __aiter__(self) -> \"MultipartResponseWrapper\":\n        return self\n\n    async def __anext__(\n        self,\n    ) -> Union[\"MultipartReader\", \"BodyPartReader\"]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True when all response data had been read.\"\"\"\n        return self.resp.content.at_eof()\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", \"BodyPartReader\"]]:\n        \"\"\"Emits next multipart reader object.\"\"\"\n        item = await self.stream.next()\n        if self.stream.at_eof():\n            await self.release()\n        return item\n\n    async def release(self) -> None:\n        \"\"\"Release the connection gracefully.\n\n        All remaining content is read to the void.\n        \"\"\"\n        await self.resp.release()\n\n\nclass BodyPartReader:\n    \"\"\"Multipart reader for single body part.\"\"\"\n\n    chunk_size = 8192\n\n    def __init__(\n        self,\n        boundary: bytes,\n        headers: \"CIMultiDictProxy[str]\",\n        content: StreamReader,\n        *,\n        subtype: str = \"mixed\",\n        default_charset: Optional[str] = None,\n    ) -> None:\n        self.headers = headers\n        self._boundary = boundary\n        self._boundary_len = len(boundary) + 2  # Boundary + \\r\\n\n        self._content = content\n        self._default_charset = default_charset\n        self._at_eof = False\n        self._is_form_data = subtype == \"form-data\"\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)\n        self._length = int(length) if length is not None else None\n        self._read_bytes = 0\n        self._unread: Deque[bytes] = deque()\n        self._prev_chunk: Optional[bytes] = None\n        self._content_eof = 0\n        self._cache: Dict[str, Any] = {}\n\n    def __aiter__(self) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(self) -> bytes:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    async def next(self) -> Optional[bytes]:\n        item = await self.read()\n        if not item:\n            return None\n        return item\n\n    async def read(self, *, decode: bool = False) -> bytes:\n        \"\"\"Reads body part data.\n\n        decode: Decodes data following by encoding\n                method from Content-Encoding header. If it missed\n                data remains untouched\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        data = bytearray()\n        while not self._at_eof:\n            data.extend(await self.read_chunk(self.chunk_size))\n        if decode:\n            return self.decode(data)\n        return data\n\n    async def read_chunk(self, size: int = chunk_size) -> bytes:\n        \"\"\"Reads body part content chunk of the specified size.\n\n        size: chunk size\n        \"\"\"\n        if self._at_eof:\n            return b\"\"\n        if self._length:\n            chunk = await self._read_chunk_from_length(size)\n        else:\n            chunk = await self._read_chunk_from_stream(size)\n\n        self._read_bytes += len(chunk)\n        if self._read_bytes == self._length:\n            self._at_eof = True\n        if self._at_eof:\n            clrf = await self._content.readline()\n            assert (\n                b\"\\r\\n\" == clrf\n            ), \"reader did not read all the data or it is malformed\"\n        return chunk\n\n    async def _read_chunk_from_length(self, size: int) -> bytes:\n        # Reads body part content chunk of the specified size.\n        # The body part must has Content-Length header with proper value.\n        assert self._length is not None, \"Content-Length required for chunked read\"\n        chunk_size = min(size, self._length - self._read_bytes)\n        chunk = await self._content.read(chunk_size)\n        if self._content.at_eof():\n            self._at_eof = True\n        return chunk\n\n    async def _read_chunk_from_stream(self, size: int) -> bytes:\n        # Reads content chunk of body part with unknown length.\n        # The Content-Length header for body part is not necessary.\n        assert (\n            size >= self._boundary_len\n        ), \"Chunk size must be greater or equal than boundary length + 2\"\n        first_chunk = self._prev_chunk is None\n        if first_chunk:\n            self._prev_chunk = await self._content.read(size)\n\n        chunk = b\"\"\n        # content.read() may return less than size, so we need to loop to ensure\n        # we have enough data to detect the boundary.\n        while len(chunk) < self._boundary_len:\n            chunk += await self._content.read(size)\n            self._content_eof += int(self._content.at_eof())\n            assert self._content_eof < 3, \"Reading after EOF\"\n            if self._content_eof:\n                break\n        if len(chunk) > size:\n            self._content.unread_data(chunk[size:])\n            chunk = chunk[:size]\n\n        assert self._prev_chunk is not None\n        window = self._prev_chunk + chunk\n        sub = b\"\\r\\n\" + self._boundary\n        if first_chunk:\n            idx = window.find(sub)\n        else:\n            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))\n        if idx >= 0:\n            # pushing boundary back to content\n            with warnings.catch_warnings():\n                warnings.filterwarnings(\"ignore\", category=DeprecationWarning)\n                self._content.unread_data(window[idx:])\n            if size > idx:\n                self._prev_chunk = self._prev_chunk[:idx]\n            chunk = window[len(self._prev_chunk) : idx]\n            if not chunk:\n                self._at_eof = True\n        result = self._prev_chunk\n        self._prev_chunk = chunk\n        return result\n\n    async def readline(self) -> bytes:\n        \"\"\"Reads body part by line by line.\"\"\"\n        if self._at_eof:\n            return b\"\"\n\n        if self._unread:\n            line = self._unread.popleft()\n        else:\n            line = await self._content.readline()\n\n        if line.startswith(self._boundary):\n            # the very last boundary may not come with \\r\\n,\n            # so set single rules for everyone\n            sline = line.rstrip(b\"\\r\\n\")\n            boundary = self._boundary\n            last_boundary = self._boundary + b\"--\"\n            # ensure that we read exactly the boundary, not something alike\n            if sline == boundary or sline == last_boundary:\n                self._at_eof = True\n                self._unread.append(line)\n                return b\"\"\n        else:\n            next_line = await self._content.readline()\n            if next_line.startswith(self._boundary):\n                line = line[:-2]  # strip CRLF but only once\n            self._unread.append(next_line)\n\n        return line\n\n    async def release(self) -> None:\n        \"\"\"Like read(), but reads all the data to the void.\"\"\"\n        if self._at_eof:\n            return\n        while not self._at_eof:\n            await self.read_chunk(self.chunk_size)\n\n    async def text(self, *, encoding: Optional[str] = None) -> str:\n        \"\"\"Like read(), but assumes that body part contains text data.\"\"\"\n        data = await self.read(decode=True)\n        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm\n        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return data.decode(encoding)\n\n    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:\n        \"\"\"Like read(), but assumes that body parts contains JSON data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return None\n        encoding = encoding or self.get_charset(default=\"utf-8\")\n        return cast(Dict[str, Any], json.loads(data.decode(encoding)))\n\n    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:\n        \"\"\"Like read(), but assumes that body parts contain form urlencoded data.\"\"\"\n        data = await self.read(decode=True)\n        if not data:\n            return []\n        if encoding is not None:\n            real_encoding = encoding\n        else:\n            real_encoding = self.get_charset(default=\"utf-8\")\n        try:\n            decoded_data = data.rstrip().decode(real_encoding)\n        except UnicodeDecodeError:\n            raise ValueError(\"data cannot be decoded with %s encoding\" % real_encoding)\n\n        return parse_qsl(\n            decoded_data,\n            keep_blank_values=True,\n            encoding=real_encoding,\n        )\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the boundary was reached or False otherwise.\"\"\"\n        return self._at_eof\n\n    def decode(self, data: bytes) -> bytes:\n        \"\"\"Decodes data.\n\n        Decoding is done according the specified Content-Encoding\n        or Content-Transfer-Encoding headers value.\n        \"\"\"\n        if CONTENT_TRANSFER_ENCODING in self.headers:\n            data = self._decode_content_transfer(data)\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n        if not self._is_form_data and CONTENT_ENCODING in self.headers:\n            return self._decode_content(data)\n        return data\n\n    def _decode_content(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_ENCODING, \"\").lower()\n        if encoding == \"identity\":\n            return data\n        if encoding in {\"deflate\", \"gzip\"}:\n            return ZLibDecompressor(\n                encoding=encoding,\n                suppress_deflate_header=True,\n            ).decompress_sync(data)\n\n        raise RuntimeError(f\"unknown content encoding: {encoding}\")\n\n    def _decode_content_transfer(self, data: bytes) -> bytes:\n        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n\n        if encoding == \"base64\":\n            return base64.b64decode(data)\n        elif encoding == \"quoted-printable\":\n            return binascii.a2b_qp(data)\n        elif encoding in (\"binary\", \"8bit\", \"7bit\"):\n            return data\n        else:\n            raise RuntimeError(\n                \"unknown content transfer encoding: {}\" \"\".format(encoding)\n            )\n\n    def get_charset(self, default: str) -> str:\n        \"\"\"Returns charset parameter from Content-Type header or default.\"\"\"\n        ctype = self.headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n        return mimetype.parameters.get(\"charset\", self._default_charset or default)\n\n    @reify\n    def name(self) -> Optional[str]:\n        \"\"\"Returns name specified in Content-Disposition header.\n\n        If the header is missing or malformed, returns None.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"name\")\n\n    @reify\n    def filename(self) -> Optional[str]:\n        \"\"\"Returns filename specified in Content-Disposition header.\n\n        Returns None if the header is missing or malformed.\n        \"\"\"\n        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))\n        return content_disposition_filename(params, \"filename\")\n\n\n@payload_type(BodyPartReader, order=Order.try_first)\nclass BodyPartReaderPayload(Payload):\n    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:\n        super().__init__(value, *args, **kwargs)\n\n        params: Dict[str, str] = {}\n        if value.name is not None:\n            params[\"name\"] = value.name\n        if value.filename is not None:\n            params[\"filename\"] = value.filename\n\n        if params:\n            self.set_content_disposition(\"attachment\", True, **params)\n\n    async def write(self, writer: Any) -> None:\n        field = self._value\n        chunk = await field.read_chunk(size=2**16)\n        while chunk:\n            await writer.write(field.decode(chunk))\n            chunk = await field.read_chunk(size=2**16)\n\n\nclass MultipartReader:\n    \"\"\"Multipart body reader.\"\"\"\n\n    #: Response wrapper, used when multipart readers constructs from response.\n    response_wrapper_cls = MultipartResponseWrapper\n    #: Multipart reader class, used to handle multipart/* body parts.\n    #: None points to type(self)\n    multipart_reader_cls = None\n    #: Body part reader class for non multipart/* content types.\n    part_reader_cls = BodyPartReader\n\n    def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None:\n        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])\n        assert self._mimetype.type == \"multipart\", \"multipart/* content type expected\"\n        if \"boundary\" not in self._mimetype.parameters:\n            raise ValueError(\n                \"boundary missed for Content-Type: %s\" % headers[CONTENT_TYPE]\n            )\n\n        self.headers = headers\n        self._boundary = (\"--\" + self._get_boundary()).encode()\n        self._content = content\n        self._default_charset: Optional[str] = None\n        self._last_part: Optional[Union[\"MultipartReader\", BodyPartReader]] = None\n        self._at_eof = False\n        self._at_bof = True\n        self._unread: List[bytes] = []\n\n    def __aiter__(\n        self,\n    ) -> AsyncIterator[\"BodyPartReader\"]:\n        return self  # type: ignore[return-value]\n\n    async def __anext__(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        part = await self.next()\n        if part is None:\n            raise StopAsyncIteration\n        return part\n\n    @classmethod\n    def from_response(\n        cls,\n        response: \"ClientResponse\",\n    ) -> MultipartResponseWrapper:\n        \"\"\"Constructs reader instance from HTTP response.\n\n        :param response: :class:`~aiohttp.client.ClientResponse` instance\n        \"\"\"\n        obj = cls.response_wrapper_cls(\n            response, cls(response.headers, response.content)\n        )\n        return obj\n\n    def at_eof(self) -> bool:\n        \"\"\"Returns True if the final boundary was reached, false otherwise.\"\"\"\n        return self._at_eof\n\n    async def next(\n        self,\n    ) -> Optional[Union[\"MultipartReader\", BodyPartReader]]:\n        \"\"\"Emits the next multipart body part.\"\"\"\n        # So, if we're at BOF, we need to skip till the boundary.\n        if self._at_eof:\n            return None\n        await self._maybe_release_last_part()\n        if self._at_bof:\n            await self._read_until_first_boundary()\n            self._at_bof = False\n        else:\n            await self._read_boundary()\n        if self._at_eof:  # we just read the last boundary, nothing to do there\n            return None\n\n        part = await self.fetch_next_part()\n        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6\n        if (\n            self._last_part is None\n            and self._mimetype.subtype == \"form-data\"\n            and isinstance(part, BodyPartReader)\n        ):\n            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))\n            if params.get(\"name\") == \"_charset_\":\n                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json\n                # is 19 characters, so 32 should be more than enough for any valid encoding.\n                charset = await part.read_chunk(32)\n                if len(charset) > 31:\n                    raise RuntimeError(\"Invalid default charset\")\n                self._default_charset = charset.strip().decode()\n                part = await self.fetch_next_part()\n        self._last_part = part\n        return self._last_part\n\n    async def release(self) -> None:\n        \"\"\"Reads all the body parts to the void till the final boundary.\"\"\"\n        while not self._at_eof:\n            item = await self.next()\n            if item is None:\n                break\n            await item.release()\n\n    async def fetch_next_part(\n        self,\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Returns the next body part reader.\"\"\"\n        headers = await self._read_headers()\n        return self._get_part_reader(headers)\n\n    def _get_part_reader(\n        self,\n        headers: \"CIMultiDictProxy[str]\",\n    ) -> Union[\"MultipartReader\", BodyPartReader]:\n        \"\"\"Dispatches the response by the `Content-Type` header.\n\n        Returns a suitable reader instance.\n\n        :param dict headers: Response headers\n        \"\"\"\n        ctype = headers.get(CONTENT_TYPE, \"\")\n        mimetype = parse_mimetype(ctype)\n\n        if mimetype.type == \"multipart\":\n            if self.multipart_reader_cls is None:\n                return type(self)(headers, self._content)\n            return self.multipart_reader_cls(headers, self._content)\n        else:\n            return self.part_reader_cls(\n                self._boundary,\n                headers,\n                self._content,\n                subtype=self._mimetype.subtype,\n                default_charset=self._default_charset,\n            )\n\n    def _get_boundary(self) -> str:\n        boundary = self._mimetype.parameters[\"boundary\"]\n        if len(boundary) > 70:\n            raise ValueError(\"boundary %r is too long (70 chars max)\" % boundary)\n\n        return boundary\n\n    async def _readline(self) -> bytes:\n        if self._unread:\n            return self._unread.pop()\n        return await self._content.readline()\n\n    async def _read_until_first_boundary(self) -> None:\n        while True:\n            chunk = await self._readline()\n            if chunk == b\"\":\n                raise ValueError(\n                    \"Could not find starting boundary %r\" % (self._boundary)\n                )\n            chunk = chunk.rstrip()\n            if chunk == self._boundary:\n                return\n            elif chunk == self._boundary + b\"--\":\n                self._at_eof = True\n                return\n\n    async def _read_boundary(self) -> None:\n        chunk = (await self._readline()).rstrip()\n        if chunk == self._boundary:\n            pass\n        elif chunk == self._boundary + b\"--\":\n            self._at_eof = True\n            epilogue = await self._readline()\n            next_line = await self._readline()\n\n            # the epilogue is expected and then either the end of input or the\n            # parent multipart boundary, if the parent boundary is found then\n            # it should be marked as unread and handed to the parent for\n            # processing\n            if next_line[:2] == b\"--\":\n                self._unread.append(next_line)\n            # otherwise the request is likely missing an epilogue and both\n            # lines should be passed to the parent for processing\n            # (this handles the old behavior gracefully)\n            else:\n                self._unread.extend([next_line, epilogue])\n        else:\n            raise ValueError(f\"Invalid boundary {chunk!r}, expected {self._boundary!r}\")\n\n    async def _read_headers(self) -> \"CIMultiDictProxy[str]\":\n        lines = [b\"\"]\n        while True:\n            chunk = await self._content.readline()\n            chunk = chunk.strip()\n            lines.append(chunk)\n            if not chunk:\n                break\n        parser = HeadersParser()\n        headers, raw_headers = parser.parse_headers(lines)\n        return headers\n\n    async def _maybe_release_last_part(self) -> None:\n        \"\"\"Ensures that the last read body part is read completely.\"\"\"\n        if self._last_part is not None:\n            if not self._last_part.at_eof():\n                await self._last_part.release()\n            self._unread.extend(self._last_part._unread)\n            self._last_part = None\n\n\n_Part = Tuple[Payload, str, str]\n\n\nclass MultipartWriter(Payload):\n    \"\"\"Multipart body writer.\"\"\"\n\n    def __init__(self, subtype: str = \"mixed\", boundary: Optional[str] = None) -> None:\n        boundary = boundary if boundary is not None else uuid.uuid4().hex\n        # The underlying Payload API demands a str (utf-8), not bytes,\n        # so we need to ensure we don't lose anything during conversion.\n        # As a result, require the boundary to be ASCII only.\n        # In both situations.\n\n        try:\n            self._boundary = boundary.encode(\"ascii\")\n        except UnicodeEncodeError:\n            raise ValueError(\"boundary should contain ASCII only chars\") from None\n        ctype = f\"multipart/{subtype}; boundary={self._boundary_value}\"\n\n        super().__init__(None, content_type=ctype)\n\n        self._parts: List[_Part] = []\n        self._is_form_data = subtype == \"form-data\"\n\n    def __enter__(self) -> \"MultipartWriter\":\n        return self\n\n    def __exit__(\n        self,\n        exc_type: Optional[Type[BaseException]],\n        exc_val: Optional[BaseException],\n        exc_tb: Optional[TracebackType],\n    ) -> None:\n        pass\n\n    def __iter__(self) -> Iterator[_Part]:\n        return iter(self._parts)\n\n    def __len__(self) -> int:\n        return len(self._parts)\n\n    def __bool__(self) -> bool:\n        return True\n\n    _valid_tchar_regex = re.compile(rb\"\\A[!#$%&'*+\\-.^_`|~\\w]+\\Z\")\n    _invalid_qdtext_char_regex = re.compile(rb\"[\\x00-\\x08\\x0A-\\x1F\\x7F]\")\n\n    @property\n    def _boundary_value(self) -> str:\n        \"\"\"Wrap boundary parameter value in quotes, if necessary.\n\n        Reads self.boundary and returns a unicode string.\n        \"\"\"\n        # Refer to RFCs 7231, 7230, 5234.\n        #\n        # parameter      = token \"=\" ( token / quoted-string )\n        # token          = 1*tchar\n        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE\n        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text\n        # obs-text       = %x80-FF\n        # quoted-pair    = \"\\\" ( HTAB / SP / VCHAR / obs-text )\n        # tchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n        #                  / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n        #                  / DIGIT / ALPHA\n        #                  ; any VCHAR, except delimiters\n        # VCHAR           = %x21-7E\n        value = self._boundary\n        if re.match(self._valid_tchar_regex, value):\n            return value.decode(\"ascii\")  # cannot fail\n\n        if re.search(self._invalid_qdtext_char_regex, value):\n            raise ValueError(\"boundary value contains invalid characters\")\n\n        # escape %x5C and %x22\n        quoted_value_content = value.replace(b\"\\\\\", b\"\\\\\\\\\")\n        quoted_value_content = quoted_value_content.replace(b'\"', b'\\\\\"')\n\n        return '\"' + quoted_value_content.decode(\"ascii\") + '\"'\n\n    @property\n    def boundary(self) -> str:\n        return self._boundary.decode(\"ascii\")\n\n    def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload:\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Payload):\n            obj.headers.update(headers)\n            return self.append_payload(obj)\n        else:\n            try:\n                payload = get_payload(obj, headers=headers)\n            except LookupError:\n                raise TypeError(\"Cannot create payload from %r\" % obj)\n            else:\n                return self.append_payload(payload)\n\n    def append_payload(self, payload: Payload) -> Payload:\n        \"\"\"Adds a new body part to multipart writer.\"\"\"\n        encoding: Optional[str] = None\n        te_encoding: Optional[str] = None\n        if self._is_form_data:\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7\n            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8\n            assert (\n                not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING}\n                & payload.headers.keys()\n            )\n            # Set default Content-Disposition in case user doesn't create one\n            if CONTENT_DISPOSITION not in payload.headers:\n                name = f\"section-{len(self._parts)}\"\n                payload.set_content_disposition(\"form-data\", name=name)\n        else:\n            # compression\n            encoding = payload.headers.get(CONTENT_ENCODING, \"\").lower()\n            if encoding and encoding not in (\"deflate\", \"gzip\", \"identity\"):\n                raise RuntimeError(f\"unknown content encoding: {encoding}\")\n            if encoding == \"identity\":\n                encoding = None\n\n            # te encoding\n            te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, \"\").lower()\n            if te_encoding not in (\"\", \"base64\", \"quoted-printable\", \"binary\"):\n                raise RuntimeError(f\"unknown content transfer encoding: {te_encoding}\")\n            if te_encoding == \"binary\":\n                te_encoding = None\n\n            # size\n            size = payload.size\n            if size is not None and not (encoding or te_encoding):\n                payload.headers[CONTENT_LENGTH] = str(size)\n\n        self._parts.append((payload, encoding, te_encoding))  # type: ignore[arg-type]\n        return payload\n\n    def append_json(\n        self, obj: Any, headers: Optional[Mapping[str, str]] = None\n    ) -> Payload:\n        \"\"\"Helper to append JSON part.\"\"\"\n        if headers is None:\n            headers = CIMultiDict()\n\n        return self.append_payload(JsonPayload(obj, headers=headers))\n\n    def append_form(\n        self,\n        obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]],\n        headers: Optional[Mapping[str, str]] = None,\n    ) -> Payload:\n        \"\"\"Helper to append form urlencoded part.\"\"\"\n        assert isinstance(obj, (Sequence, Mapping))\n\n        if headers is None:\n            headers = CIMultiDict()\n\n        if isinstance(obj, Mapping):\n            obj = list(obj.items())\n        data = urlencode(obj, doseq=True)\n\n        return self.append_payload(\n            StringPayload(\n                data, headers=headers, content_type=\"application/x-www-form-urlencoded\"\n            )\n        )\n\n    @property\n    def size(self) -> Optional[int]:\n        \"\"\"Size of the payload.\"\"\"\n        total = 0\n        for part, encoding, te_encoding in self._parts:\n            if encoding or te_encoding or part.size is None:\n                return None\n\n            total += int(\n                2\n                + len(self._boundary)\n                + 2\n                + part.size  # b'--'+self._boundary+b'\\r\\n'\n                + len(part._binary_headers)\n                + 2  # b'\\r\\n'\n            )\n\n        total += 2 + len(self._boundary) + 4  # b'--'+self._boundary+b'--\\r\\n'\n        return total\n\n    async def write(self, writer: Any, close_boundary: bool = True) -> None:\n        \"\"\"Write body.\"\"\"\n        for part, encoding, te_encoding in self._parts:\n            if self._is_form_data:\n                # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2\n                assert CONTENT_DISPOSITION in part.headers\n                assert \"name=\" in part.headers[CONTENT_DISPOSITION]\n\n            await writer.write(b\"--\" + self._boundary + b\"\\r\\n\")\n            await writer.write(part._binary_headers)\n\n            if encoding or te_encoding:\n                w = MultipartPayloadWriter(writer)\n                if encoding:\n                    w.enable_compression(encoding)\n                if te_encoding:\n                    w.enable_encoding(te_encoding)\n                await part.write(w)  # type: ignore[arg-type]\n                await w.write_eof()\n            else:\n                await part.write(writer)\n\n            await writer.write(b\"\\r\\n\")\n\n        if close_boundary:\n            await writer.write(b\"--\" + self._boundary + b\"--\\r\\n\")\n\n\nclass MultipartPayloadWriter:\n    def __init__(self, writer: Any) -> None:\n        self._writer = writer\n        self._encoding: Optional[str] = None\n        self._compress: Optional[ZLibCompressor] = None\n        self._encoding_buffer: Optional[bytearray] = None\n\n    def enable_encoding(self, encoding: str) -> None:\n        if encoding == \"base64\":\n            self._encoding = encoding\n            self._encoding_buffer = bytearray()\n        elif encoding == \"quoted-printable\":\n            self._encoding = \"quoted-printable\"\n\n    def enable_compression(\n        self, encoding: str = \"deflate\", strategy: int = zlib.Z_DEFAULT_STRATEGY\n    ) -> None:\n        self._compress = ZLibCompressor(\n            encoding=encoding,\n            suppress_deflate_header=True,\n            strategy=strategy,\n        )\n\n    async def write_eof(self) -> None:\n        if self._compress is not None:\n            chunk = self._compress.flush()\n            if chunk:\n                self._compress = None\n                await self.write(chunk)\n\n        if self._encoding == \"base64\":\n            if self._encoding_buffer:\n                await self._writer.write(base64.b64encode(self._encoding_buffer))\n\n    async def write(self, chunk: bytes) -> None:\n        if self._compress is not None:\n            if chunk:\n                chunk = await self._compress.compress(chunk)\n                if not chunk:\n                    return\n\n        if self._encoding == \"base64\":\n            buf = self._encoding_buffer\n            assert buf is not None\n            buf.extend(chunk)\n\n            if buf:\n                div, mod = divmod(len(buf), 3)\n                enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :])\n                if enc_chunk:\n                    b64chunk = base64.b64encode(enc_chunk)\n                    await self._writer.write(b64chunk)\n        elif self._encoding == \"quoted-printable\":\n            await self._writer.write(binascii.b2a_qp(chunk))\n        else:\n            await self._writer.write(chunk)\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
**Analysis:**

- **Key Parts from Commit Details and Test Results:**
  - **Commit Message:** "Fix decoding base64 chunk for BodyPartReader"
  - **Changes:** Added logic to handle base64-encoded chunks correctly by ensuring proper padding and chunk sizes.
  - **Test Results Before Commit:** 
    - `test_decode_with_content_transfer_encoding_base64` failed with `binascii.Error: Incorrect padding`.
    - `test_read_with_content_transfer_encoding_binary` also failed.
  - **Test Results After Commit:** Both tests pass successfully.

- **Main Problem Highlighted by Test Results:**
  - The `BodyPartReader` was unable to correctly decode base64-encoded chunks, leading to padding errors and test failures.

- **Expected Behavior:**
  - The `BodyPartReader` should correctly decode base64-encoded data without encountering padding errors, ensuring that the entire content is accurately read and processed.

- **Actual Behavior:**
  - Decoding base64 chunks resulted in padding errors (`binascii.Error: Incorrect padding`) due to improper handling of chunk sizes and padding alignment.

- **Issue Description:**
  - The `BodyPartReader` in the `aiohttp` library fails to decode base64-encoded chunks correctly. When processing chunks that do not align with the base64 encoding requirements (multiples of 4 bytes), it leads to padding errors, causing the decoding process to fail.

---

[ISSUE]
**Title:** BodyPartReader Fails to Decode Base64 Chunks Correctly, Causing Padding Errors

**Description:**
When processing base64-encoded data, the `BodyPartReader` encounters padding errors due to incorrect handling of chunk sizes. This results in failed decoding attempts and prevents the proper reading of the content.

**Example Buggy Code:**
```python
async def test_decode_with_content_transfer_encoding_base64(self) -> None:
    with Stream(b"VG\r\r\nltZSB0byBSZ\r\nWxheCE=\r\n--:--") as stream:
        obj = aiohttp.BodyPartReader(
            BOUNDARY, {CONTENT_TRANSFER_ENCODING: "base64"}, stream
        )
        result = b""
        while not obj.at_eof():
            chunk = await obj.read_chunk(size=6)
            result += obj.decode(chunk)
    # Expected: b"Time to Relax!"
    # Actual: Raises binascii.Error: Incorrect padding
```

**Expected Behavior:**
The `BodyPartReader` should correctly decode the base64-encoded chunks without raising padding errors, resulting in the accurate reconstruction of the original data (`b"Time to Relax!"`).

**Actual Behavior:**
Decoding the provided base64 chunks raises a `binascii.Error: Incorrect padding`, indicating that the decoder is unable to handle chunks that do not align with the expected base64 padding requirements.

[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### aiohttp/multipart.py
import base64
import binascii
import json
import re
import uuid
import warnings
import zlib
from collections import deque
from types import TracebackType
from typing import (
    TYPE_CHECKING,
    Any,
    AsyncIterator,
    Deque,
    Dict,
    Iterator,
    List,
    Mapping,
    Optional,
    Sequence,
    Tuple,
    Type,
    Union,
    cast,
)
from urllib.parse import parse_qsl, unquote, urlencode

from multidict import CIMultiDict, CIMultiDictProxy

from .compression_utils import ZLibCompressor, ZLibDecompressor
from .hdrs import (
    CONTENT_DISPOSITION,
    CONTENT_ENCODING,
    CONTENT_LENGTH,
    CONTENT_TRANSFER_ENCODING,
    CONTENT_TYPE,
)
from .helpers import CHAR, TOKEN, parse_mimetype, reify
from .http import HeadersParser
from .payload import (
    JsonPayload,
    LookupError,
    Order,
    Payload,
    StringPayload,
    get_payload,
    payload_type,
)
from .streams import StreamReader

__all__ = (
    "MultipartReader",
    "MultipartWriter",
    "BodyPartReader",
    "BadContentDispositionHeader",
    "BadContentDispositionParam",
    "parse_content_disposition",
    "content_disposition_filename",
)


if TYPE_CHECKING:
    from .client_reqrep import ClientResponse


class BadContentDispositionHeader(RuntimeWarning):
    pass


class BadContentDispositionParam(RuntimeWarning):
    pass


def parse_content_disposition(
    header: Optional[str],
) -> Tuple[Optional[str], Dict[str, str]]:
    def is_token(string: str) -> bool:
        return bool(string) and TOKEN >= set(string)

    def is_quoted(string: str) -> bool:
        return string[0] == string[-1] == '"'

    def is_rfc5987(string: str) -> bool:
        return is_token(string) and string.count("'") == 2

    def is_extended_param(string: str) -> bool:
        return string.endswith("*")

    def is_continuous_param(string: str) -> bool:
        pos = string.find("*") + 1
        if not pos:
            return False
        substring = string[pos:-1] if string.endswith("*") else string[pos:]
        return substring.isdigit()

    def unescape(text: str, *, chars: str = "".join(map(re.escape, CHAR))) -> str:
        return re.sub(f"\\\\([{chars}])", "\\1", text)

    if not header:
        return None, {}

    disptype, *parts = header.split(";")
    if not is_token(disptype):
        warnings.warn(BadContentDispositionHeader(header))
        return None, {}

    params: Dict[str, str] = {}
    while parts:
        item = parts.pop(0)

        if "=" not in item:
            warnings.warn(BadContentDispositionHeader(header))
            return None, {}

        key, value = item.split("=", 1)
        key = key.lower().strip()
        value = value.lstrip()

        if key in params:
            warnings.warn(BadContentDispositionHeader(header))
            return None, {}

        if not is_token(key):
            warnings.warn(BadContentDispositionParam(item))
            continue

        elif is_continuous_param(key):
            if is_quoted(value):
                value = unescape(value[1:-1])
            elif not is_token(value):
                warnings.warn(BadContentDispositionParam(item))
                continue

        elif is_extended_param(key):
            if is_rfc5987(value):
                encoding, _, value = value.split("'", 2)
                encoding = encoding or "utf-8"
            else:
                warnings.warn(BadContentDispositionParam(item))
                continue

            try:
                value = unquote(value, encoding, "strict")
            except UnicodeDecodeError:  # pragma: nocover
                warnings.warn(BadContentDispositionParam(item))
                continue

        else:
            failed = True
            if is_quoted(value):
                failed = False
                value = unescape(value[1:-1].lstrip("\\/"))
            elif is_token(value):
                failed = False
            elif parts:
                # maybe just ; in filename, in any case this is just
                # one case fix, for proper fix we need to redesign parser
                _value = f"{value};{parts[0]}"
                if is_quoted(_value):
                    parts.pop(0)
                    value = unescape(_value[1:-1].lstrip("\\/"))
                    failed = False

            if failed:
                warnings.warn(BadContentDispositionHeader(header))
                return None, {}

        params[key] = value

    return disptype.lower(), params


def content_disposition_filename(
    params: Mapping[str, str], name: str = "filename"
) -> Optional[str]:
    name_suf = "%s*" % name
    if not params:
        return None
    elif name_suf in params:
        return params[name_suf]
    elif name in params:
        return params[name]
    else:
        parts = []
        fnparams = sorted(
            (key, value) for key, value in params.items() if key.startswith(name_suf)
        )
        for num, (key, value) in enumerate(fnparams):
            _, tail = key.split("*", 1)
            if tail.endswith("*"):
                tail = tail[:-1]
            if tail == str(num):
                parts.append(value)
            else:
                break
        if not parts:
            return None
        value = "".join(parts)
        if "'" in value:
            encoding, _, value = value.split("'", 2)
            encoding = encoding or "utf-8"
            return unquote(value, encoding, "strict")
        return value


class MultipartResponseWrapper:
    """Wrapper around the MultipartReader.

    It takes care about
    underlying connection and close it when it needs in.
    """

    def __init__(
        self,
        resp: "ClientResponse",
        stream: "MultipartReader",
    ) -> None:
        self.resp = resp
        self.stream = stream

    def __aiter__(self) -> "MultipartResponseWrapper":
        return self

    async def __anext__(
        self,
    ) -> Union["MultipartReader", "BodyPartReader"]:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    def at_eof(self) -> bool:
        """Returns True when all response data had been read."""
        return self.resp.content.at_eof()

    async def next(
        self,
    ) -> Optional[Union["MultipartReader", "BodyPartReader"]]:
        """Emits next multipart reader object."""
        item = await self.stream.next()
        if self.stream.at_eof():
            await self.release()
        return item

    async def release(self) -> None:
        """Release the connection gracefully.

        All remaining content is read to the void.
        """
        await self.resp.release()


class BodyPartReader:
    """Multipart reader for single body part."""

    chunk_size = 8192

    def __init__(
        self,
        boundary: bytes,
        headers: "CIMultiDictProxy[str]",
        content: StreamReader,
        *,
        subtype: str = "mixed",
        default_charset: Optional[str] = None,
    ) -> None:
        self.headers = headers
        self._boundary = boundary
        self._boundary_len = len(boundary) + 2  # Boundary + \r\n
        self._content = content
        self._default_charset = default_charset
        self._at_eof = False
        self._is_form_data = subtype == "form-data"
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
        length = None if self._is_form_data else self.headers.get(CONTENT_LENGTH, None)
        self._length = int(length) if length is not None else None
        self._read_bytes = 0
        self._unread: Deque[bytes] = deque()
        self._prev_chunk: Optional[bytes] = None
        self._content_eof = 0
        self._cache: Dict[str, Any] = {}

    def __aiter__(self) -> AsyncIterator["BodyPartReader"]:
        return self  # type: ignore[return-value]

    async def __anext__(self) -> bytes:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    async def next(self) -> Optional[bytes]:
        item = await self.read()
        if not item:
            return None
        return item

    async def read(self, *, decode: bool = False) -> bytes:
        """Reads body part data.

        decode: Decodes data following by encoding
                method from Content-Encoding header. If it missed
                data remains untouched
        """
        if self._at_eof:
            return b""
        data = bytearray()
        while not self._at_eof:
            data.extend(await self.read_chunk(self.chunk_size))
        if decode:
            return self.decode(data)
        return data

    async def read_chunk(self, size: int = chunk_size) -> bytes:
        """Reads body part content chunk of the specified size.

        size: chunk size
        """
        if self._at_eof:
            return b""
        if self._length:
            chunk = await self._read_chunk_from_length(size)
        else:
            chunk = await self._read_chunk_from_stream(size)

        self._read_bytes += len(chunk)
        if self._read_bytes == self._length:
            self._at_eof = True
        if self._at_eof:
            clrf = await self._content.readline()
            assert (
                b"\r\n" == clrf
            ), "reader did not read all the data or it is malformed"
        return chunk

    async def _read_chunk_from_length(self, size: int) -> bytes:
        # 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)
        chunk = await self._content.read(chunk_size)
        if self._content.at_eof():
            self._at_eof = True
        return chunk

    async def _read_chunk_from_stream(self, size: int) -> bytes:
        # Reads content chunk of body part with unknown length.
        # The Content-Length header for body part is not necessary.
        assert (
            size >= self._boundary_len
        ), "Chunk size must be greater or equal than boundary length + 2"
        first_chunk = self._prev_chunk is None
        if first_chunk:
            self._prev_chunk = await self._content.read(size)

        chunk = b""
        # content.read() may return less than size, so we need to loop to ensure
        # we have enough data to detect the boundary.
        while len(chunk) < self._boundary_len:
            chunk += await self._content.read(size)
            self._content_eof += int(self._content.at_eof())
            assert self._content_eof < 3, "Reading after EOF"
            if self._content_eof:
                break
        if len(chunk) > size:
            self._content.unread_data(chunk[size:])
            chunk = chunk[:size]

        assert self._prev_chunk is not None
        window = self._prev_chunk + chunk
        sub = b"\r\n" + self._boundary
        if first_chunk:
            idx = window.find(sub)
        else:
            idx = window.find(sub, max(0, len(self._prev_chunk) - len(sub)))
        if idx >= 0:
            # pushing boundary back to content
            with warnings.catch_warnings():
                warnings.filterwarnings("ignore", category=DeprecationWarning)
                self._content.unread_data(window[idx:])
            if size > idx:
                self._prev_chunk = self._prev_chunk[:idx]
            chunk = window[len(self._prev_chunk) : idx]
            if not chunk:
                self._at_eof = True
        result = self._prev_chunk
        self._prev_chunk = chunk
        return result

    async def readline(self) -> bytes:
        """Reads body part by line by line."""
        if self._at_eof:
            return b""

        if self._unread:
            line = self._unread.popleft()
        else:
            line = await self._content.readline()

        if line.startswith(self._boundary):
            # the very last boundary may not come with \r\n,
            # so set single rules for everyone
            sline = line.rstrip(b"\r\n")
            boundary = self._boundary
            last_boundary = self._boundary + b"--"
            # ensure that we read exactly the boundary, not something alike
            if sline == boundary or sline == last_boundary:
                self._at_eof = True
                self._unread.append(line)
                return b""
        else:
            next_line = await self._content.readline()
            if next_line.startswith(self._boundary):
                line = line[:-2]  # strip CRLF but only once
            self._unread.append(next_line)

        return line

    async def release(self) -> None:
        """Like read(), but reads all the data to the void."""
        if self._at_eof:
            return
        while not self._at_eof:
            await self.read_chunk(self.chunk_size)

    async def text(self, *, encoding: Optional[str] = None) -> str:
        """Like read(), but assumes that body part contains text data."""
        data = await self.read(decode=True)
        # see https://www.w3.org/TR/html5/forms.html#multipart/form-data-encoding-algorithm
        # and https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-send
        encoding = encoding or self.get_charset(default="utf-8")
        return data.decode(encoding)

    async def json(self, *, encoding: Optional[str] = None) -> Optional[Dict[str, Any]]:
        """Like read(), but assumes that body parts contains JSON data."""
        data = await self.read(decode=True)
        if not data:
            return None
        encoding = encoding or self.get_charset(default="utf-8")
        return cast(Dict[str, Any], json.loads(data.decode(encoding)))

    async def form(self, *, encoding: Optional[str] = None) -> List[Tuple[str, str]]:
        """Like read(), but assumes that body parts contain form urlencoded data."""
        data = await self.read(decode=True)
        if not data:
            return []
        if encoding is not None:
            real_encoding = encoding
        else:
            real_encoding = self.get_charset(default="utf-8")
        try:
            decoded_data = data.rstrip().decode(real_encoding)
        except UnicodeDecodeError:
            raise ValueError("data cannot be decoded with %s encoding" % real_encoding)

        return parse_qsl(
            decoded_data,
            keep_blank_values=True,
            encoding=real_encoding,
        )

    def at_eof(self) -> bool:
        """Returns True if the boundary was reached or False otherwise."""
        return self._at_eof

    def decode(self, data: bytes) -> bytes:
        """Decodes data.

        Decoding is done according the specified Content-Encoding
        or Content-Transfer-Encoding headers value.
        """
        if CONTENT_TRANSFER_ENCODING in self.headers:
            data = self._decode_content_transfer(data)
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
        if not self._is_form_data and CONTENT_ENCODING in self.headers:
            return self._decode_content(data)
        return data

    def _decode_content(self, data: bytes) -> bytes:
        encoding = self.headers.get(CONTENT_ENCODING, "").lower()
        if encoding == "identity":
            return data
        if encoding in {"deflate", "gzip"}:
            return ZLibDecompressor(
                encoding=encoding,
                suppress_deflate_header=True,
            ).decompress_sync(data)

        raise RuntimeError(f"unknown content encoding: {encoding}")

    def _decode_content_transfer(self, data: bytes) -> bytes:
        encoding = self.headers.get(CONTENT_TRANSFER_ENCODING, "").lower()

        if encoding == "base64":
            return base64.b64decode(data)
        elif encoding == "quoted-printable":
            return binascii.a2b_qp(data)
        elif encoding in ("binary", "8bit", "7bit"):
            return data
        else:
            raise RuntimeError(
                "unknown content transfer encoding: {}" "".format(encoding)
            )

    def get_charset(self, default: str) -> str:
        """Returns charset parameter from Content-Type header or default."""
        ctype = self.headers.get(CONTENT_TYPE, "")
        mimetype = parse_mimetype(ctype)
        return mimetype.parameters.get("charset", self._default_charset or default)

    @reify
    def name(self) -> Optional[str]:
        """Returns name specified in Content-Disposition header.

        If the header is missing or malformed, returns None.
        """
        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))
        return content_disposition_filename(params, "name")

    @reify
    def filename(self) -> Optional[str]:
        """Returns filename specified in Content-Disposition header.

        Returns None if the header is missing or malformed.
        """
        _, params = parse_content_disposition(self.headers.get(CONTENT_DISPOSITION))
        return content_disposition_filename(params, "filename")


@payload_type(BodyPartReader, order=Order.try_first)
class BodyPartReaderPayload(Payload):
    def __init__(self, value: BodyPartReader, *args: Any, **kwargs: Any) -> None:
        super().__init__(value, *args, **kwargs)

        params: Dict[str, str] = {}
        if value.name is not None:
            params["name"] = value.name
        if value.filename is not None:
            params["filename"] = value.filename

        if params:
            self.set_content_disposition("attachment", True, **params)

    async def write(self, writer: Any) -> None:
        field = self._value
        chunk = await field.read_chunk(size=2**16)
        while chunk:
            await writer.write(field.decode(chunk))
            chunk = await field.read_chunk(size=2**16)


class MultipartReader:
    """Multipart body reader."""

    #: Response wrapper, used when multipart readers constructs from response.
    response_wrapper_cls = MultipartResponseWrapper
    #: Multipart reader class, used to handle multipart/* body parts.
    #: None points to type(self)
    multipart_reader_cls = None
    #: Body part reader class for non multipart/* content types.
    part_reader_cls = BodyPartReader

    def __init__(self, headers: Mapping[str, str], content: StreamReader) -> None:
        self._mimetype = parse_mimetype(headers[CONTENT_TYPE])
        assert self._mimetype.type == "multipart", "multipart/* content type expected"
        if "boundary" not in self._mimetype.parameters:
            raise ValueError(
                "boundary missed for Content-Type: %s" % headers[CONTENT_TYPE]
            )

        self.headers = headers
        self._boundary = ("--" + self._get_boundary()).encode()
        self._content = content
        self._default_charset: Optional[str] = None
        self._last_part: Optional[Union["MultipartReader", BodyPartReader]] = None
        self._at_eof = False
        self._at_bof = True
        self._unread: List[bytes] = []

    def __aiter__(
        self,
    ) -> AsyncIterator["BodyPartReader"]:
        return self  # type: ignore[return-value]

    async def __anext__(
        self,
    ) -> Optional[Union["MultipartReader", BodyPartReader]]:
        part = await self.next()
        if part is None:
            raise StopAsyncIteration
        return part

    @classmethod
    def from_response(
        cls,
        response: "ClientResponse",
    ) -> MultipartResponseWrapper:
        """Constructs reader instance from HTTP response.

        :param response: :class:`~aiohttp.client.ClientResponse` instance
        """
        obj = cls.response_wrapper_cls(
            response, cls(response.headers, response.content)
        )
        return obj

    def at_eof(self) -> bool:
        """Returns True if the final boundary was reached, false otherwise."""
        return self._at_eof

    async def next(
        self,
    ) -> Optional[Union["MultipartReader", BodyPartReader]]:
        """Emits the next multipart body part."""
        # So, if we're at BOF, we need to skip till the boundary.
        if self._at_eof:
            return None
        await self._maybe_release_last_part()
        if self._at_bof:
            await self._read_until_first_boundary()
            self._at_bof = False
        else:
            await self._read_boundary()
        if self._at_eof:  # we just read the last boundary, nothing to do there
            return None

        part = await self.fetch_next_part()
        # https://datatracker.ietf.org/doc/html/rfc7578#section-4.6
        if (
            self._last_part is None
            and self._mimetype.subtype == "form-data"
            and isinstance(part, BodyPartReader)
        ):
            _, params = parse_content_disposition(part.headers.get(CONTENT_DISPOSITION))
            if params.get("name") == "_charset_":
                # Longest encoding in https://encoding.spec.whatwg.org/encodings.json
                # is 19 characters, so 32 should be more than enough for any valid encoding.
                charset = await part.read_chunk(32)
                if len(charset) > 31:
                    raise RuntimeError("Invalid default charset")
                self._default_charset = charset.strip().decode()
                part = await self.fetch_next_part()
        self._last_part = part
        return self._last_part

    async def release(self) -> None:
        """Reads all the body parts to the void till the final boundary."""
        while not self._at_eof:
            item = await self.next()
            if item is None:
                break
            await item.release()

    async def fetch_next_part(
        self,
    ) -> Union["MultipartReader", BodyPartReader]:
        """Returns the next body part reader."""
        headers = await self._read_headers()
        return self._get_part_reader(headers)

    def _get_part_reader(
        self,
        headers: "CIMultiDictProxy[str]",
    ) -> Union["MultipartReader", BodyPartReader]:
        """Dispatches the response by the `Content-Type` header.

        Returns a suitable reader instance.

        :param dict headers: Response headers
        """
        ctype = headers.get(CONTENT_TYPE, "")
        mimetype = parse_mimetype(ctype)

        if mimetype.type == "multipart":
            if self.multipart_reader_cls is None:
                return type(self)(headers, self._content)
            return self.multipart_reader_cls(headers, self._content)
        else:
            return self.part_reader_cls(
                self._boundary,
                headers,
                self._content,
                subtype=self._mimetype.subtype,
                default_charset=self._default_charset,
            )

    def _get_boundary(self) -> str:
        boundary = self._mimetype.parameters["boundary"]
        if len(boundary) > 70:
            raise ValueError("boundary %r is too long (70 chars max)" % boundary)

        return boundary

    async def _readline(self) -> bytes:
        if self._unread:
            return self._unread.pop()
        return await self._content.readline()

    async def _read_until_first_boundary(self) -> None:
        while True:
            chunk = await self._readline()
            if chunk == b"":
                raise ValueError(
                    "Could not find starting boundary %r" % (self._boundary)
                )
            chunk = chunk.rstrip()
            if chunk == self._boundary:
                return
            elif chunk == self._boundary + b"--":
                self._at_eof = True
                return

    async def _read_boundary(self) -> None:
        chunk = (await self._readline()).rstrip()
        if chunk == self._boundary:
            pass
        elif chunk == self._boundary + b"--":
            self._at_eof = True
            epilogue = await self._readline()
            next_line = await self._readline()

            # the epilogue is expected and then either the end of input or the
            # parent multipart boundary, if the parent boundary is found then
            # it should be marked as unread and handed to the parent for
            # processing
            if next_line[:2] == b"--":
                self._unread.append(next_line)
            # otherwise the request is likely missing an epilogue and both
            # lines should be passed to the parent for processing
            # (this handles the old behavior gracefully)
            else:
                self._unread.extend([next_line, epilogue])
        else:
            raise ValueError(f"Invalid boundary {chunk!r}, expected {self._boundary!r}")

    async def _read_headers(self) -> "CIMultiDictProxy[str]":
        lines = [b""]
        while True:
            chunk = await self._content.readline()
            chunk = chunk.strip()
            lines.append(chunk)
            if not chunk:
                break
        parser = HeadersParser()
        headers, raw_headers = parser.parse_headers(lines)
        return headers

    async def _maybe_release_last_part(self) -> None:
        """Ensures that the last read body part is read completely."""
        if self._last_part is not None:
            if not self._last_part.at_eof():
                await self._last_part.release()
            self._unread.extend(self._last_part._unread)
            self._last_part = None


_Part = Tuple[Payload, str, str]


class MultipartWriter(Payload):
    """Multipart body writer."""

    def __init__(self, subtype: str = "mixed", boundary: Optional[str] = None) -> None:
        boundary = boundary if boundary is not None else uuid.uuid4().hex
        # The underlying Payload API demands a str (utf-8), not bytes,
        # so we need to ensure we don't lose anything during conversion.
        # As a result, require the boundary to be ASCII only.
        # In both situations.

        try:
            self._boundary = boundary.encode("ascii")
        except UnicodeEncodeError:
            raise ValueError("boundary should contain ASCII only chars") from None
        ctype = f"multipart/{subtype}; boundary={self._boundary_value}"

        super().__init__(None, content_type=ctype)

        self._parts: List[_Part] = []
        self._is_form_data = subtype == "form-data"

    def __enter__(self) -> "MultipartWriter":
        return self

    def __exit__(
        self,
        exc_type: Optional[Type[BaseException]],
        exc_val: Optional[BaseException],
        exc_tb: Optional[TracebackType],
    ) -> None:
        pass

    def __iter__(self) -> Iterator[_Part]:
        return iter(self._parts)

    def __len__(self) -> int:
        return len(self._parts)

    def __bool__(self) -> bool:
        return True

    _valid_tchar_regex = re.compile(rb"\A[!#$%&'*+\-.^_`|~\w]+\Z")
    _invalid_qdtext_char_regex = re.compile(rb"[\x00-\x08\x0A-\x1F\x7F]")

    @property
    def _boundary_value(self) -> str:
        """Wrap boundary parameter value in quotes, if necessary.

        Reads self.boundary and returns a unicode string.
        """
        # Refer to RFCs 7231, 7230, 5234.
        #
        # parameter      = token "=" ( token / quoted-string )
        # token          = 1*tchar
        # quoted-string  = DQUOTE *( qdtext / quoted-pair ) DQUOTE
        # qdtext         = HTAB / SP / %x21 / %x23-5B / %x5D-7E / obs-text
        # obs-text       = %x80-FF
        # quoted-pair    = "\" ( HTAB / SP / VCHAR / obs-text )
        # tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
        #                  / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
        #                  / DIGIT / ALPHA
        #                  ; any VCHAR, except delimiters
        # VCHAR           = %x21-7E
        value = self._boundary
        if re.match(self._valid_tchar_regex, value):
            return value.decode("ascii")  # cannot fail

        if re.search(self._invalid_qdtext_char_regex, value):
            raise ValueError("boundary value contains invalid characters")

        # escape %x5C and %x22
        quoted_value_content = value.replace(b"\\", b"\\\\")
        quoted_value_content = quoted_value_content.replace(b'"', b'\\"')

        return '"' + quoted_value_content.decode("ascii") + '"'

    @property
    def boundary(self) -> str:
        return self._boundary.decode("ascii")

    def append(self, obj: Any, headers: Optional[Mapping[str, str]] = None) -> Payload:
        if headers is None:
            headers = CIMultiDict()

        if isinstance(obj, Payload):
            obj.headers.update(headers)
            return self.append_payload(obj)
        else:
            try:
                payload = get_payload(obj, headers=headers)
            except LookupError:
                raise TypeError("Cannot create payload from %r" % obj)
            else:
                return self.append_payload(payload)

    def append_payload(self, payload: Payload) -> Payload:
        """Adds a new body part to multipart writer."""
        encoding: Optional[str] = None
        te_encoding: Optional[str] = None
        if self._is_form_data:
            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.7
            # https://datatracker.ietf.org/doc/html/rfc7578#section-4.8
            assert (
                not {CONTENT_ENCODING, CONTENT_LENGTH, CONTENT_TRANSFER_ENCODING}
                & payload.headers.keys()
            )
            # Set default Content-Disposition in case user doesn't create one
            if CONTENT_DISPOSITION not in payload.headers:
                name = f"section-{len(self._parts)}"
                payload.set_content_disposition("form-data", name=name)
        else:
            # compression
            encoding = payload.headers.get(CONTENT_ENCODING, "").lower()
            if encoding and encoding not in ("deflate", "gzip", "identity"):
                raise RuntimeError(f"unknown content encoding: {encoding}")
            if encoding == "identity":
                encoding = None

            # te encoding
            te_encoding = payload.headers.get(CONTENT_TRANSFER_ENCODING, "").lower()
            if te_encoding not in ("", "base64", "quoted-printable", "binary"):
                raise RuntimeError(f"unknown content transfer encoding: {te_encoding}")
            if te_encoding == "binary":
                te_encoding = None

            # size
            size = payload.size
            if size is not None and not (encoding or te_encoding):
                payload.headers[CONTENT_LENGTH] = str(size)

        self._parts.append((payload, encoding, te_encoding))  # type: ignore[arg-type]
        return payload

    def append_json(
        self, obj: Any, headers: Optional[Mapping[str, str]] = None
    ) -> Payload:
        """Helper to append JSON part."""
        if headers is None:
            headers = CIMultiDict()

        return self.append_payload(JsonPayload(obj, headers=headers))

    def append_form(
        self,
        obj: Union[Sequence[Tuple[str, str]], Mapping[str, str]],
        headers: Optional[Mapping[str, str]] = None,
    ) -> Payload:
        """Helper to append form urlencoded part."""
        assert isinstance(obj, (Sequence, Mapping))

        if headers is None:
            headers = CIMultiDict()

        if isinstance(obj, Mapping):
            obj = list(obj.items())
        data = urlencode(obj, doseq=True)

        return self.append_payload(
            StringPayload(
                data, headers=headers, content_type="application/x-www-form-urlencoded"
            )
        )

    @property
    def size(self) -> Optional[int]:
        """Size of the payload."""
        total = 0
        for part, encoding, te_encoding in self._parts:
            if encoding or te_encoding or part.size is None:
                return None

            total += int(
                2
                + len(self._boundary)
                + 2
                + part.size  # b'--'+self._boundary+b'\r\n'
                + len(part._binary_headers)
                + 2  # b'\r\n'
            )

        total += 2 + len(self._boundary) + 4  # b'--'+self._boundary+b'--\r\n'
        return total

    async def write(self, writer: Any, close_boundary: bool = True) -> None:
        """Write body."""
        for part, encoding, te_encoding in self._parts:
            if self._is_form_data:
                # https://datatracker.ietf.org/doc/html/rfc7578#section-4.2
                assert CONTENT_DISPOSITION in part.headers
                assert "name=" in part.headers[CONTENT_DISPOSITION]

            await writer.write(b"--" + self._boundary + b"\r\n")
            await writer.write(part._binary_headers)

            if encoding or te_encoding:
                w = MultipartPayloadWriter(writer)
                if encoding:
                    w.enable_compression(encoding)
                if te_encoding:
                    w.enable_encoding(te_encoding)
                await part.write(w)  # type: ignore[arg-type]
                await w.write_eof()
            else:
                await part.write(writer)

            await writer.write(b"\r\n")

        if close_boundary:
            await writer.write(b"--" + self._boundary + b"--\r\n")


class MultipartPayloadWriter:
    def __init__(self, writer: Any) -> None:
        self._writer = writer
        self._encoding: Optional[str] = None
        self._compress: Optional[ZLibCompressor] = None
        self._encoding_buffer: Optional[bytearray] = None

    def enable_encoding(self, encoding: str) -> None:
        if encoding == "base64":
            self._encoding = encoding
            self._encoding_buffer = bytearray()
        elif encoding == "quoted-printable":
            self._encoding = "quoted-printable"

    def enable_compression(
        self, encoding: str = "deflate", strategy: int = zlib.Z_DEFAULT_STRATEGY
    ) -> None:
        self._compress = ZLibCompressor(
            encoding=encoding,
            suppress_deflate_header=True,
            strategy=strategy,
        )

    async def write_eof(self) -> None:
        if self._compress is not None:
            chunk = self._compress.flush()
            if chunk:
                self._compress = None
                await self.write(chunk)

        if self._encoding == "base64":
            if self._encoding_buffer:
                await self._writer.write(base64.b64encode(self._encoding_buffer))

    async def write(self, chunk: bytes) -> None:
        if self._compress is not None:
            if chunk:
                chunk = await self._compress.compress(chunk)
                if not chunk:
                    return

        if self._encoding == "base64":
            buf = self._encoding_buffer
            assert buf is not None
            buf.extend(chunk)

            if buf:
                div, mod = divmod(len(buf), 3)
                enc_chunk, self._encoding_buffer = (buf[: div * 3], buf[div * 3 :])
                if enc_chunk:
                    b64chunk = base64.b64encode(enc_chunk)
                    await self._writer.write(b64chunk)
        elif self._encoding == "quoted-printable":
            await self._writer.write(binascii.b2a_qp(chunk))
        else:
            await self._writer.write(chunk)

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user