From caa3061c3b35266101251a3865f482b6fb089ebf Mon Sep 17 00:00:00 2001 From: pgjones Date: Sat, 30 Sep 2023 16:02:39 +0100 Subject: [PATCH] Bump to Werkzeug 3.0.0 and Flask 3.0.0 These are the latest releases and are required for Quart to base on Flask. --- pyproject.toml | 4 ++-- src/quart/asgi.py | 4 ++-- src/quart/formparser.py | 25 +++++++++---------------- src/quart/wrappers/request.py | 4 +--- src/quart/wrappers/response.py | 6 +++--- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 686d03d..61aa695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ python = ">=3.8" aiofiles = "*" blinker = ">=1.6" click = ">=8.0.0" -flask = { git = "https://github.com/pallets/flask.git", branch = "main" } +flask = ">=3.0.0" hypercorn = ">=0.11.2" importlib_metadata = { version = "*", python = "<3.10" } itsdangerous = "*" @@ -38,7 +38,7 @@ markupsafe = "*" pydata_sphinx_theme = { version = "*", optional = true } python-dotenv = { version = "*", optional = true } typing_extensions = { version = "*", python = "<3.10" } -werkzeug = ">=2.2.0" +werkzeug = ">=3.0.0" [tool.poetry.dev-dependencies] hypothesis = "*" diff --git a/src/quart/asgi.py b/src/quart/asgi.py index a58bf48..856b55a 100644 --- a/src/quart/asgi.py +++ b/src/quart/asgi.py @@ -122,7 +122,7 @@ async def _send_response(self, send: ASGISendCallable, response: ResponseTypes) if isinstance(response, WerkzeugResponse): for data in response.response: - body = data.encode(response._charset) if isinstance(data, str) else data + body = data.encode() if isinstance(data, str) else data await send( cast( HTTPResponseBodyEvent, @@ -132,7 +132,7 @@ async def _send_response(self, send: ASGISendCallable, response: ResponseTypes) else: async with response.response as response_body: async for data in response_body: - body = data.encode(response._charset) if isinstance(data, str) else data + body = data.encode() if isinstance(data, str) else data await send( cast( HTTPResponseBodyEvent, diff --git a/src/quart/formparser.py b/src/quart/formparser.py index 00da84f..eab878a 100644 --- a/src/quart/formparser.py +++ b/src/quart/formparser.py @@ -41,16 +41,12 @@ class FormDataParser: def __init__( self, stream_factory: StreamFactory = default_stream_factory, - charset: str = "utf-8", - errors: str = "replace", max_form_memory_size: int | None = None, max_content_length: int | None = None, cls: type[MultiDict] | None = MultiDict, silent: bool = True, ) -> None: self.stream_factory = stream_factory - self.charset = charset - self.errors = errors self.cls = cls self.silent = silent @@ -87,8 +83,6 @@ async def _parse_multipart( ) -> tuple[MultiDict, MultiDict]: parser = MultiPartParser( self.stream_factory, - self.charset, - self.errors, cls=self.cls, file_storage_cls=self.file_storage_class, ) @@ -109,8 +103,6 @@ async def _parse_urlencoded( form = parse_qsl( (await body).decode(), keep_blank_values=True, - encoding=self.charset, - errors=self.errors, ) return self.cls(form), self.cls() @@ -125,15 +117,11 @@ class MultiPartParser: def __init__( self, stream_factory: StreamFactory = default_stream_factory, - charset: str = "utf-8", - errors: str = "replace", max_form_memory_size: int | None = None, cls: type[MultiDict] = MultiDict, buffer_size: int = 64 * 1024, file_storage_cls: type[FileStorage] = FileStorage, ) -> None: - self.charset = charset - self.errors = errors self.max_form_memory_size = max_form_memory_size self.stream_factory = stream_factory self.cls = cls @@ -147,10 +135,15 @@ def get_part_charset(self, headers: Headers) -> str: content_type = headers.get("content-type") if content_type: - mimetype, ct_params = parse_options_header(content_type) - return ct_params.get("charset", self.charset) + parameters = parse_options_header(content_type)[1] + ct_charset = parameters.get("charset", "").lower() - return self.charset + # A safe list of encodings. Modern clients should only send ASCII or UTF-8. + # This list will not be extended further. + if ct_charset in {"ascii", "us-ascii", "utf-8", "iso-8859-1"}: + return ct_charset + + return "utf-8" def start_file_streaming(self, event: File, total_content_length: int) -> IO[bytes]: content_type = event.headers.get("content-type") @@ -197,7 +190,7 @@ async def parse( if not event.more_data: if isinstance(current_part, Field): value = b"".join(container).decode( - self.get_part_charset(current_part.headers), self.errors + self.get_part_charset(current_part.headers), "replace" ) fields.append((current_part.name, value)) else: diff --git a/src/quart/wrappers/request.py b/src/quart/wrappers/request.py index 6686107..63615db 100644 --- a/src/quart/wrappers/request.py +++ b/src/quart/wrappers/request.py @@ -226,7 +226,7 @@ async def get_data( self.body.clear() if as_text: - return raw_data.decode(self._charset, self._encoding_errors) + return raw_data.decode() else: return raw_data @@ -271,8 +271,6 @@ async def files(self) -> MultiDict: def make_form_data_parser(self) -> FormDataParser: return self.form_data_parser_class( - charset=self._charset, - errors=self._encoding_errors, max_content_length=self.max_content_length, cls=self.parameter_storage_class, ) diff --git a/src/quart/wrappers/response.py b/src/quart/wrappers/response.py index 31a7d16..4257e73 100644 --- a/src/quart/wrappers/response.py +++ b/src/quart/wrappers/response.py @@ -317,7 +317,7 @@ async def get_data(self, as_text: bool = False) -> AnyStr: async with self.response as body: async for data in body: if as_text: - result += data.decode(self._charset) + result += data.decode() else: result += data return result # type: ignore @@ -328,7 +328,7 @@ def set_data(self, data: AnyStr) -> None: This will encode using the :attr:`charset`. """ if isinstance(data, str): - bytes_data = data.encode(self._charset) + bytes_data = data.encode() else: bytes_data = data self.response = self.data_body_class(bytes_data) @@ -461,7 +461,7 @@ async def iter_encode(self) -> AsyncGenerator[bytes, None]: async with self.response as response_body: async for item in response_body: if isinstance(item, str): - yield item.encode(self._charset) + yield item.encode() else: yield item