diff options
author | David Lord <davidism@gmail.com> | 2023-05-08 15:35:34 -0700 |
---|---|---|
committer | David Lord <davidism@gmail.com> | 2023-05-08 15:35:34 -0700 |
commit | be78c3ff24dd01df8079a415debbd876052c096f (patch) | |
tree | c83aaec6df36833f509fd9c80f77a8429f699ac8 | |
parent | 825633eb783f49b0450b0e6866bc55985b154531 (diff) | |
parent | ab61d0dab5ffbf846f6ddf4e1386ca340012250e (diff) | |
download | werkzeug-be78c3ff24dd01df8079a415debbd876052c096f.tar.gz |
Merge branch '2.3.x'
-rw-r--r-- | CHANGES.rst | 7 | ||||
-rw-r--r-- | src/werkzeug/__init__.py | 2 | ||||
-rw-r--r-- | src/werkzeug/datastructures/auth.py | 26 | ||||
-rw-r--r-- | src/werkzeug/datastructures/headers.py | 12 | ||||
-rw-r--r-- | src/werkzeug/formparser.py | 35 | ||||
-rw-r--r-- | src/werkzeug/http.py | 40 | ||||
-rw-r--r-- | src/werkzeug/routing/converters.py | 2 | ||||
-rw-r--r-- | src/werkzeug/routing/map.py | 6 | ||||
-rw-r--r-- | src/werkzeug/sansio/http.py | 8 | ||||
-rw-r--r-- | src/werkzeug/sansio/request.py | 18 | ||||
-rw-r--r-- | src/werkzeug/sansio/response.py | 2 | ||||
-rw-r--r-- | src/werkzeug/security.py | 8 | ||||
-rw-r--r-- | src/werkzeug/test.py | 18 | ||||
-rw-r--r-- | src/werkzeug/urls.py | 137 | ||||
-rw-r--r-- | src/werkzeug/utils.py | 8 | ||||
-rw-r--r-- | src/werkzeug/wrappers/response.py | 5 | ||||
-rw-r--r-- | src/werkzeug/wsgi.py | 24 | ||||
-rw-r--r-- | tests/test_formparser.py | 4 | ||||
-rw-r--r-- | tests/test_urls.py | 15 | ||||
-rw-r--r-- | tests/test_utils.py | 60 | ||||
-rw-r--r-- | tests/test_wsgi.py | 10 |
21 files changed, 228 insertions, 219 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 2d83ee59..72b27a26 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,10 +3,15 @@ Version 2.3.4 ------------- -Unreleased +Released 2023-05-08 - ``Authorization.from_header`` and ``WWWAuthenticate.from_header`` detects tokens that end with base64 padding (``=``). :issue:`2685` +- Remove usage of ``warnings.catch_warnings``. :issue:`2690` +- Remove ``max_form_parts`` restriction from standard form data parsing and only use + if for multipart content. :pr:`2694` +- ``Response`` will avoid converting the ``Location`` header in some cases to preserve + invalid URL schemes like ``itms-services``. :issue:`2691` Version 2.3.3 diff --git a/src/werkzeug/__init__.py b/src/werkzeug/__init__.py index b3208b2f..828edcf2 100644 --- a/src/werkzeug/__init__.py +++ b/src/werkzeug/__init__.py @@ -3,4 +3,4 @@ from .test import Client as Client from .wrappers import Request as Request from .wrappers import Response as Response -__version__ = "2.3.4.dev" +__version__ = "2.3.4" diff --git a/src/werkzeug/datastructures/auth.py b/src/werkzeug/datastructures/auth.py index 0d216516..a3403259 100644 --- a/src/werkzeug/datastructures/auth.py +++ b/src/werkzeug/datastructures/auth.py @@ -150,10 +150,10 @@ def auth_property(name: str, doc: str | None = None) -> property: special_realm = auth_property('special_realm') .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. + Will be removed in Werkzeug 3.0. """ warnings.warn( - "'auth_property' is deprecated and will be removed in Werkzeug 2.4.", + "'auth_property' is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -202,7 +202,7 @@ class WWWAuthenticate: if auth_type is None: warnings.warn( "An auth type must be given as the first parameter. Assuming 'basic' is" - " deprecated and will be removed in Werkzeug 2.4.", + " deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -264,10 +264,10 @@ class WWWAuthenticate: """Clear any existing data and set a ``Basic`` challenge. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Create and assign an instance instead. + Will be removed in Werkzeug 3.0. Create and assign an instance instead. """ warnings.warn( - "The 'set_basic' method is deprecated and will be removed in Werkzeug 2.4." + "The 'set_basic' method is deprecated and will be removed in Werkzeug 3.0." " Create and assign an instance instead." ) self._type = "basic" @@ -291,10 +291,10 @@ class WWWAuthenticate: """Clear any existing data and set a ``Digest`` challenge. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Create and assign an instance instead. + Will be removed in Werkzeug 3.0. Create and assign an instance instead. """ warnings.warn( - "The 'set_digest' method is deprecated and will be removed in Werkzeug 2.4." + "The 'set_digest' method is deprecated and will be removed in Werkzeug 3.0." " Create and assign an instance instead." ) self._type = "digest" @@ -415,11 +415,11 @@ class WWWAuthenticate: """The ``qop`` parameter as a set. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. It will become the same as other + Will be removed in Werkzeug 3.0. It will become the same as other parameters, returning a string. """ warnings.warn( - "The 'qop' property is deprecated and will be removed in Werkzeug 2.4." + "The 'qop' property is deprecated and will be removed in Werkzeug 3.0." " It will become the same as other parameters, returning a string.", DeprecationWarning, stacklevel=2, @@ -441,11 +441,11 @@ class WWWAuthenticate: """The ``stale`` parameter as a boolean. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. It will become the same as other + Will be removed in Werkzeug 3.0. It will become the same as other parameters, returning a string. """ warnings.warn( - "The 'stale' property is deprecated and will be removed in Werkzeug 2.4." + "The 'stale' property is deprecated and will be removed in Werkzeug 3.0." " It will become the same as other parameters, returning a string.", DeprecationWarning, stacklevel=2, @@ -467,7 +467,7 @@ class WWWAuthenticate: if isinstance(value, bool): warnings.warn( "Setting the 'stale' property to a boolean is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -483,7 +483,7 @@ def _deprecated_dict_method(f): # type: ignore[no-untyped-def] def wrapper(*args, **kwargs): # type: ignore[no-untyped-def] warnings.warn( "Treating 'Authorization' and 'WWWAuthenticate' as a dict is deprecated and" - " will be removed in Werkzeug 2.4. Use the 'parameters' attribute instead.", + " will be removed in Werkzeug 3.0. Use the 'parameters' attribute instead.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/datastructures/headers.py b/src/werkzeug/datastructures/headers.py index 1f13d1c7..dc060c41 100644 --- a/src/werkzeug/datastructures/headers.py +++ b/src/werkzeug/datastructures/headers.py @@ -103,7 +103,7 @@ class Headers: .. versionchanged:: 2.3 The ``as_bytes`` parameter is deprecated and will be removed - in Werkzeug 2.4. + in Werkzeug 3.0. .. versionchanged:: 0.9 The ``as_bytes`` parameter was added. @@ -111,7 +111,7 @@ class Headers: if as_bytes is not None: warnings.warn( "The 'as_bytes' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -143,7 +143,7 @@ class Headers: .. versionchanged:: 2.3 The ``as_bytes`` parameter is deprecated and will be removed - in Werkzeug 2.4. + in Werkzeug 3.0. .. versionchanged:: 0.9 The ``as_bytes`` parameter was added. @@ -151,7 +151,7 @@ class Headers: if as_bytes is not None: warnings.warn( "The 'as_bytes' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -480,7 +480,7 @@ def _str_header_key(key: t.Any) -> str: if not isinstance(key, str): warnings.warn( "Header keys must be strings. Passing other types is deprecated and will" - " not be supported in Werkzeug 2.4.", + " not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -500,7 +500,7 @@ def _str_header_value(value: t.Any) -> str: if isinstance(value, bytes): warnings.warn( "Passing bytes as a header value is deprecated and will not be supported in" - " Werkzeug 2.4.", + " Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/formparser.py b/src/werkzeug/formparser.py index 074ac542..dcedd339 100644 --- a/src/werkzeug/formparser.py +++ b/src/werkzeug/formparser.py @@ -105,8 +105,8 @@ def parse_form_data( :param cls: an optional dict class to use. If this is not specified or `None` the default :class:`MultiDict` is used. :param silent: If set to False parsing errors will not be caught. - :param max_form_parts: The maximum number of parts to be parsed. If this is - exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised. + :param max_form_parts: The maximum number of multipart parts to be parsed. If this + is exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised. :return: A tuple in the form ``(stream, form, files)``. .. versionchanged:: 2.3 @@ -114,7 +114,7 @@ def parse_form_data( .. versionchanged:: 2.3 The ``charset`` and ``errors`` parameters are deprecated and will be removed in - Werkzeug 2.4. + Werkzeug 3.0. .. versionadded:: 0.5.1 Added the ``silent`` parameter. @@ -157,16 +157,16 @@ class FormDataParser: :param cls: an optional dict class to use. If this is not specified or `None` the default :class:`MultiDict` is used. :param silent: If set to False parsing errors will not be caught. - :param max_form_parts: The maximum number of parts to be parsed. If this is - exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised. + :param max_form_parts: The maximum number of multipart parts to be parsed. If this + is exceeded, a :exc:`~exceptions.RequestEntityTooLarge` exception is raised. .. versionchanged:: 2.3 The ``charset`` and ``errors`` parameters are deprecated and will be removed in - Werkzeug 2.4. + Werkzeug 3.0. .. versionchanged:: 2.3 The ``parse_functions`` attribute and ``get_parse_func`` methods are deprecated - and will be removed in Werkzeug 2.4. + and will be removed in Werkzeug 3.0. .. versionchanged:: 2.2.3 Added the ``max_form_parts`` parameter. @@ -194,7 +194,7 @@ class FormDataParser: if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -206,7 +206,7 @@ class FormDataParser: if errors is not None: warnings.warn( "The 'errors' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -234,7 +234,7 @@ class FormDataParser: ): warnings.warn( "The 'get_parse_func' method is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -246,7 +246,7 @@ class FormDataParser: elif mimetype == "application/x-url-encoded": warnings.warn( "The 'application/x-url-encoded' mimetype is invalid, and will not be" - " treated as 'application/x-www-form-urlencoded' in Werkzeug 2.4.", + " treated as 'application/x-www-form-urlencoded' in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -254,7 +254,7 @@ class FormDataParser: elif mimetype in self.parse_functions: warnings.warn( "The 'parse_functions' attribute is deprecated and will be removed in" - " Werkzeug 2.4. Override 'parse' instead.", + " Werkzeug 3.0. Override 'parse' instead.", DeprecationWarning, stacklevel=2, ) @@ -297,7 +297,7 @@ class FormDataParser: .. versionchanged:: 2.3 The ``application/x-url-encoded`` content type is deprecated and will not be - treated as ``application/x-www-form-urlencoded`` in Werkzeug 2.4. + treated as ``application/x-www-form-urlencoded`` in Werkzeug 3.0. """ if mimetype == "multipart/form-data": parse_func = self._parse_multipart @@ -306,7 +306,7 @@ class FormDataParser: elif mimetype == "application/x-url-encoded": warnings.warn( "The 'application/x-url-encoded' mimetype is invalid, and will not be" - " treated as 'application/x-www-form-urlencoded' in Werkzeug 2.4.", + " treated as 'application/x-www-form-urlencoded' in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -314,7 +314,7 @@ class FormDataParser: elif mimetype in self.parse_functions: warnings.warn( "The 'parse_functions' attribute is deprecated and will be removed in" - " Werkzeug 2.4. Override 'parse' instead.", + " Werkzeug 3.0. Override 'parse' instead.", DeprecationWarning, stacklevel=2, ) @@ -378,7 +378,6 @@ class FormDataParser: keep_blank_values=True, encoding=self.charset, errors="werkzeug.url_quote", - max_num_fields=self.max_form_parts, ) except ValueError as e: raise RequestEntityTooLarge() from e @@ -408,7 +407,7 @@ class MultiPartParser: if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -420,7 +419,7 @@ class MultiPartParser: if errors is not None: warnings.warn( "The 'errors' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/http.py b/src/werkzeug/http.py index d38ca9a5..08b5c538 100644 --- a/src/werkzeug/http.py +++ b/src/werkzeug/http.py @@ -153,16 +153,16 @@ def quote_header_value( The value is quoted if it is the empty string. .. versionchanged:: 2.3 - Passing bytes is deprecated and will not be supported in Werkzeug 2.4. + Passing bytes is deprecated and will not be supported in Werkzeug 3.0. .. versionchanged:: 2.3 - The ``extra_chars`` parameter is deprecated and will be removed in Werkzeug 2.4. + The ``extra_chars`` parameter is deprecated and will be removed in Werkzeug 3.0. .. versionadded:: 0.5 """ if isinstance(value, bytes): warnings.warn( - "Passing bytes is deprecated and will not be supported in Werkzeug 2.4.", + "Passing bytes is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -171,7 +171,7 @@ def quote_header_value( if extra_chars is not None: warnings.warn( "The 'extra_chars' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -203,12 +203,12 @@ def unquote_header_value(value: str, is_filename: bool | None = None) -> str: :param value: The header value to unquote. .. versionchanged:: 2.3 - The ``is_filename`` parameter is deprecated and will be removed in Werkzeug 2.4. + The ``is_filename`` parameter is deprecated and will be removed in Werkzeug 3.0. """ if is_filename is not None: warnings.warn( "The 'is_filename' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -298,7 +298,7 @@ def dump_header( :param iterable: The items to create a header from. .. versionchanged:: 2.3 - The ``allow_token`` parameter is deprecated and will be removed in Werkzeug 2.4. + The ``allow_token`` parameter is deprecated and will be removed in Werkzeug 3.0. .. versionchanged:: 2.2.3 If a key ends with ``*``, its value will not be quoted. @@ -306,7 +306,7 @@ def dump_header( if allow_token is not None: warnings.warn( "'The 'allow_token' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -394,10 +394,10 @@ def parse_dict_header(value: str, cls: type[dict] | None = None) -> dict[str, st Added support for ``key*=charset''value`` encoded items. .. versionchanged:: 2.3 - Passing bytes is deprecated, support will be removed in Werkzeug 2.4. + Passing bytes is deprecated, support will be removed in Werkzeug 3.0. .. versionchanged:: 2.3 - The ``cls`` argument is deprecated and will be removed in Werkzeug 2.4. + The ``cls`` argument is deprecated and will be removed in Werkzeug 3.0. .. versionchanged:: 0.9 The ``cls`` argument was added. @@ -406,7 +406,7 @@ def parse_dict_header(value: str, cls: type[dict] | None = None) -> dict[str, st cls = dict else: warnings.warn( - "The 'cls' parameter is deprecated and will be removed in Werkzeug 2.4.", + "The 'cls' parameter is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -415,7 +415,7 @@ def parse_dict_header(value: str, cls: type[dict] | None = None) -> dict[str, st if isinstance(value, bytes): warnings.warn( - "Passing bytes is deprecated and will be removed in Werkzeug 2.4.", + "Passing bytes is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -823,7 +823,7 @@ def parse_authorization_header( :return: a :class:`~werkzeug.datastructures.Authorization` object or `None`. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use :meth:`.Authorization.from_header` instead. + Will be removed in Werkzeug 3.0. Use :meth:`.Authorization.from_header` instead. """ from .datastructures import Authorization @@ -850,7 +850,7 @@ def parse_www_authenticate_header( :return: a :class:`~werkzeug.datastructures.WWWAuthenticate` object. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use :meth:`.WWWAuthenticate.from_header` + Will be removed in Werkzeug 3.0. Use :meth:`.WWWAuthenticate.from_header` instead. """ from .datastructures.auth import WWWAuthenticate @@ -1298,7 +1298,7 @@ def parse_cookie( .. versionchanged:: 2.3 Passing bytes, and the ``charset`` and ``errors`` parameters, are deprecated and - will be removed in Werkzeug 2.4. + will be removed in Werkzeug 3.0. .. versionchanged:: 1.0 Returns a :class:`MultiDict` instead of a ``TypeConversionDict``. @@ -1311,7 +1311,7 @@ def parse_cookie( cookie = header.get("HTTP_COOKIE") elif isinstance(header, bytes): warnings.warn( - "Passing bytes is deprecated and will not be supported in Werkzeug 2.4.", + "Passing bytes is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1403,7 +1403,7 @@ def dump_cookie( .. versionchanged:: 2.3 Passing bytes, and the ``charset`` parameter, are deprecated and will be removed - in Werkzeug 2.4. + in Werkzeug 3.0. .. versionchanged:: 1.0.0 The string ``'None'`` is accepted for ``samesite``. @@ -1411,7 +1411,7 @@ def dump_cookie( if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be removed" - " in Werkzeug 2.4.", + " in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1421,7 +1421,7 @@ def dump_cookie( if isinstance(key, bytes): warnings.warn( "The 'key' parameter must be a string. Bytes are deprecated" - " and will not be supported in Werkzeug 2.4.", + " and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1430,7 +1430,7 @@ def dump_cookie( if isinstance(value, bytes): warnings.warn( "The 'value' parameter must be a string. Bytes are" - " deprecated and will not be supported in Werkzeug 2.4.", + " deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/routing/converters.py b/src/werkzeug/routing/converters.py index bf8d80f4..c59e2abc 100644 --- a/src/werkzeug/routing/converters.py +++ b/src/werkzeug/routing/converters.py @@ -45,7 +45,7 @@ class BaseConverter: if isinstance(value, (bytes, bytearray)): warnings.warn( "Passing bytes as a URL value is deprecated and will not be supported" - " in Werkzeug 2.4.", + " in Werkzeug 3.0.", DeprecationWarning, stacklevel=7, ) diff --git a/src/werkzeug/routing/map.py b/src/werkzeug/routing/map.py index cdb935dd..022fd1e0 100644 --- a/src/werkzeug/routing/map.py +++ b/src/werkzeug/routing/map.py @@ -70,7 +70,7 @@ class Map: .. versionchanged:: 2.3 The ``charset`` and ``encoding_errors`` parameters are deprecated and will be - removed in Werkzeug 2.4. + removed in Werkzeug 3.0. .. versionchanged:: 1.0 If ``url_scheme`` is ``ws`` or ``wss``, only WebSocket rules will match. @@ -117,7 +117,7 @@ class Map: if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -129,7 +129,7 @@ class Map: if encoding_errors is not None: warnings.warn( "The 'encoding_errors' parameter is deprecated and will be" - " removed in Werkzeug 2.4.", + " removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/sansio/http.py b/src/werkzeug/sansio/http.py index 8eaf7cf2..21a61972 100644 --- a/src/werkzeug/sansio/http.py +++ b/src/werkzeug/sansio/http.py @@ -140,7 +140,7 @@ def parse_cookie( .. versionchanged:: 2.3 Passing bytes, and the ``charset`` and ``errors`` parameters, are deprecated and - will be removed in Werkzeug 2.4. + will be removed in Werkzeug 3.0. .. versionadded:: 2.2 """ @@ -150,7 +150,7 @@ def parse_cookie( if isinstance(cookie, bytes): warnings.warn( "The 'cookie' parameter must be a string. Passing bytes is deprecated and" - " will not be supported in Werkzeug 2.4.", + " will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -158,7 +158,7 @@ def parse_cookie( if charset is not None: warnings.warn( - "The 'charset' parameter is deprecated and will be removed in Werkzeug 2.4", + "The 'charset' parameter is deprecated and will be removed in Werkzeug 3.0", DeprecationWarning, stacklevel=2, ) @@ -167,7 +167,7 @@ def parse_cookie( if errors is not None: warnings.warn( - "The 'errors' parameter is deprecated and will be removed in Werkzeug 2.4", + "The 'errors' parameter is deprecated and will be removed in Werkzeug 3.0", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/sansio/request.py b/src/werkzeug/sansio/request.py index fb3fcccb..0bcda90b 100644 --- a/src/werkzeug/sansio/request.py +++ b/src/werkzeug/sansio/request.py @@ -69,7 +69,7 @@ class Request: """The charset used to decode body, form, and cookie data. Defaults to UTF-8. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Request data must always be UTF-8. + Will be removed in Werkzeug 3.0. Request data must always be UTF-8. """ warnings.warn( "The 'charset' attribute is deprecated and will not be used in Werkzeug" @@ -98,11 +98,11 @@ class Request: """How errors when decoding bytes are handled. Defaults to "replace". .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. + Will be removed in Werkzeug 3.0. """ warnings.warn( "The 'encoding_errors' attribute is deprecated and will not be used in" - " Werkzeug 2.4.", + " Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -112,7 +112,7 @@ class Request: def encoding_errors(self, value: str) -> None: warnings.warn( "The 'encoding_errors' attribute is deprecated and will not be used in" - " Werkzeug 2.4.", + " Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -126,13 +126,13 @@ class Request: Defaults to the value of :attr:`charset`, which defaults to UTF-8. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Percent-encoded bytes must always be UTF-8. + Will be removed in Werkzeug 3.0. Percent-encoded bytes must always be UTF-8. .. versionadded:: 0.6 """ warnings.warn( "The 'url_charset' attribute is deprecated and will not be used in" - " Werkzeug 2.4. Percent-encoded bytes must always be UTF-8.", + " Werkzeug 3.0. Percent-encoded bytes must always be UTF-8.", DeprecationWarning, stacklevel=2, ) @@ -142,7 +142,7 @@ class Request: def url_charset(self, value: str) -> None: warnings.warn( "The 'url_charset' attribute is deprecated and will not be used in" - " Werkzeug 2.4. Percent-encoded bytes must always be UTF-8.", + " Werkzeug 3.0. Percent-encoded bytes must always be UTF-8.", DeprecationWarning, stacklevel=2, ) @@ -224,7 +224,7 @@ class Request: if not isinstance(type(self).encoding_errors, property): warnings.warn( "The 'encoding_errors' attribute is deprecated and will not be used in" - " Werkzeug 2.4.", + " Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -235,7 +235,7 @@ class Request: if not isinstance(type(self).url_charset, property): warnings.warn( "The 'url_charset' attribute is deprecated and will not be used in" - " Werkzeug 2.4. Percent-encoded bytes must always be UTF-8.", + " Werkzeug 3.0. Percent-encoded bytes must always be UTF-8.", DeprecationWarning, stacklevel=2, ) diff --git a/src/werkzeug/sansio/response.py b/src/werkzeug/sansio/response.py index 387a4ae7..d71839f6 100644 --- a/src/werkzeug/sansio/response.py +++ b/src/werkzeug/sansio/response.py @@ -91,7 +91,7 @@ class Response: """The charset used to encode body and cookie data. Defaults to UTF-8. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Response data must always be UTF-8. + Will be removed in Werkzeug 3.0. Response data must always be UTF-8. """ warnings.warn( "The 'charset' attribute is deprecated and will not be used in Werkzeug" diff --git a/src/werkzeug/security.py b/src/werkzeug/security.py index 10f57cd5..282c4fd8 100644 --- a/src/werkzeug/security.py +++ b/src/werkzeug/security.py @@ -27,7 +27,7 @@ def _hash_internal(method: str, salt: str, password: str) -> tuple[str, str]: if method == "plain": warnings.warn( "The 'plain' password method is deprecated and will be removed in" - " Werkzeug 2.4. Migrate to the 'scrypt' method.", + " Werkzeug 3.0. Migrate to the 'scrypt' method.", stacklevel=3, ) return password, method @@ -74,7 +74,7 @@ def _hash_internal(method: str, salt: str, password: str) -> tuple[str, str]: else: warnings.warn( f"The '{method}' password method is deprecated and will be removed in" - " Werkzeug 2.4. Migrate to the 'scrypt' method.", + " Werkzeug 3.0. Migrate to the 'scrypt' method.", stacklevel=3, ) return hmac.new(salt, password, method).hexdigest(), method @@ -110,7 +110,7 @@ def generate_password_hash( The default iterations for pbkdf2 was increased to 600,000. .. versionchanged:: 2.3 - All plain hashes are deprecated and will not be supported in Werkzeug 2.4. + All plain hashes are deprecated and will not be supported in Werkzeug 3.0. """ salt = gen_salt(salt_length) h, actual_method = _hash_internal(method, salt, password) @@ -129,7 +129,7 @@ def check_password_hash(pwhash: str, password: str) -> bool: :param password: The plaintext password. .. versionchanged:: 2.3 - All plain hashes are deprecated and will not be supported in Werkzeug 2.4. + All plain hashes are deprecated and will not be supported in Werkzeug 3.0. """ try: method, salt, hashval = pwhash.split("$", 2) diff --git a/src/werkzeug/test.py b/src/werkzeug/test.py index 012ec30b..f5b4f2ff 100644 --- a/src/werkzeug/test.py +++ b/src/werkzeug/test.py @@ -65,11 +65,11 @@ def stream_encode_multipart( in a file descriptor. .. versionchanged:: 2.3 - The ``charset`` parameter is deprecated and will be removed in Werkzeug 2.4 + The ``charset`` parameter is deprecated and will be removed in Werkzeug 3.0 """ if charset is not None: warnings.warn( - "The 'charset' parameter is deprecated and will be removed in Werkzeug 2.4", + "The 'charset' parameter is deprecated and will be removed in Werkzeug 3.0", DeprecationWarning, stacklevel=2, ) @@ -163,7 +163,7 @@ def encode_multipart( (``boundary``, ``data``) where data is bytes. .. versionchanged:: 2.3 - The ``charset`` parameter is deprecated and will be removed in Werkzeug 2.4 + The ``charset`` parameter is deprecated and will be removed in Werkzeug 3.0 """ stream, length, boundary = stream_encode_multipart( values, use_tempfile=False, boundary=boundary, charset=charset @@ -259,7 +259,7 @@ class EnvironBuilder: is a shortcut for ``Basic`` authorization. .. versionchanged:: 2.3 - The ``charset`` parameter is deprecated and will be removed in Werkzeug 2.4 + The ``charset`` parameter is deprecated and will be removed in Werkzeug 3.0 .. versionchanged:: 2.1 ``CONTENT_TYPE`` and ``CONTENT_LENGTH`` are not duplicated as @@ -342,7 +342,7 @@ class EnvironBuilder: if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be" - " removed in Werkzeug 2.4", + " removed in Werkzeug 3.0", DeprecationWarning, stacklevel=2, ) @@ -860,7 +860,7 @@ class Client: def cookie_jar(self) -> t.Iterable[Cookie] | None: warnings.warn( "The 'cookie_jar' attribute is a private API and will be removed in" - " Werkzeug 2.4. Use the 'get_cookie' method instead.", + " Werkzeug 3.0. Use the 'get_cookie' method instead.", DeprecationWarning, stacklevel=2, ) @@ -927,7 +927,7 @@ class Client: .. versionchanged:: 2.3 The first parameter ``server_name`` is deprecated and will be removed in - Werkzeug 2.4. The first parameter is ``key``. Use the ``domain`` and + Werkzeug 3.0. The first parameter is ``key``. Use the ``domain`` and ``origin_only`` parameters instead. """ if self._cookies is None: @@ -938,7 +938,7 @@ class Client: if args: warnings.warn( "The first parameter 'server_name' is no longer used, and will be" - " removed in Werkzeug 2.4. The positional parameters are 'key' and" + " removed in Werkzeug 3.0. The positional parameters are 'key' and" " 'value'. Use the 'domain' and 'origin_only' parameters instead.", DeprecationWarning, stacklevel=2, @@ -977,7 +977,7 @@ class Client: .. versionchanged:: 2.3 The first parameter ``server_name`` is deprecated and will be removed in - Werkzeug 2.4. The first parameter is ``key``. Use the ``domain`` parameter + Werkzeug 3.0. The first parameter is ``key``. Use the ``domain`` parameter instead. .. versionchanged:: 2.3 diff --git a/src/werkzeug/urls.py b/src/werkzeug/urls.py index b0e62d0b..89ef2194 100644 --- a/src/werkzeug/urls.py +++ b/src/werkzeug/urls.py @@ -59,7 +59,7 @@ class BaseURL(_URLTuple): """Superclass of :py:class:`URL` and :py:class:`BytesURL`. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use the ``urllib.parse`` library instead. + Will be removed in Werkzeug 3.0. Use the ``urllib.parse`` library instead. """ __slots__ = () @@ -71,7 +71,7 @@ class BaseURL(_URLTuple): def __new__(cls, *args: t.Any, **kwargs: t.Any) -> BaseURL: warnings.warn( f"'werkzeug.urls.{cls.__name__}' is deprecated and will be removed in" - " Werkzeug 2.4. Use the 'urllib.parse' library instead.", + " Werkzeug 3.0. Use the 'urllib.parse' library instead.", DeprecationWarning, stacklevel=2, ) @@ -358,7 +358,7 @@ class URL(BaseURL): URL. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use the ``urllib.parse`` library instead. + Will be removed in Werkzeug 3.0. Use the ``urllib.parse`` library instead. """ __slots__ = () @@ -371,22 +371,20 @@ class URL(BaseURL): """Encodes the URL to a tuple made out of bytes. The charset is only being used for the path, query and fragment. """ - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - return BytesURL( - self.scheme.encode("ascii"), - self.encode_netloc(), - self.path.encode(charset, errors), - self.query.encode(charset, errors), - self.fragment.encode(charset, errors), - ) + return BytesURL( + self.scheme.encode("ascii"), + self.encode_netloc(), + self.path.encode(charset, errors), + self.query.encode(charset, errors), + self.fragment.encode(charset, errors), + ) class BytesURL(BaseURL): """Represents a parsed URL in bytes. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use the ``urllib.parse`` library instead. + Will be removed in Werkzeug 3.0. Use the ``urllib.parse`` library instead. """ __slots__ = () @@ -406,15 +404,13 @@ class BytesURL(BaseURL): """Decodes the URL to a tuple made out of strings. The charset is only being used for the path, query and fragment. """ - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - return URL( - self.scheme.decode("ascii"), # type: ignore - self.decode_netloc(), - self.path.decode(charset, errors), # type: ignore - self.query.decode(charset, errors), # type: ignore - self.fragment.decode(charset, errors), # type: ignore - ) + return URL( + self.scheme.decode("ascii"), # type: ignore + self.decode_netloc(), + self.path.decode(charset, errors), # type: ignore + self.query.decode(charset, errors), # type: ignore + self.fragment.decode(charset, errors), # type: ignore + ) _unquote_maps: dict[frozenset[int], dict[bytes, int]] = {frozenset(): _hextobyte} @@ -504,10 +500,10 @@ def url_parse( from the URL. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.urlsplit`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.urlsplit`` instead. """ warnings.warn( - "'werkzeug.urls.url_parse' is deprecated and will be removed in Werkzeug 2.4." + "'werkzeug.urls.url_parse' is deprecated and will be removed in Werkzeug 3.0." " Use 'urllib.parse.urlsplit' instead.", DeprecationWarning, stacklevel=2, @@ -546,9 +542,7 @@ def url_parse( result_type = URL if is_text_based else BytesURL - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - return result_type(scheme, netloc, url, query, fragment) + return result_type(scheme, netloc, url, query, fragment) def _make_fast_url_quote( @@ -605,13 +599,13 @@ def url_quote( :param unsafe: an optional sequence of unsafe characters. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.quote`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.quote`` instead. .. versionadded:: 0.9.2 The `unsafe` parameter was added. """ warnings.warn( - "'werkzeug.urls.url_quote' is deprecated and will be removed in Werkzeug 2.4." + "'werkzeug.urls.url_quote' is deprecated and will be removed in Werkzeug 3.0." " Use 'urllib.parse.quote' instead.", DeprecationWarning, stacklevel=2, @@ -646,7 +640,7 @@ def url_quote_plus( :param safe: An optional sequence of safe characters. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.quote_plus`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.quote_plus`` instead. """ warnings.warn( "'werkzeug.urls.url_quote_plus' is deprecated and will be removed in Werkzeug" @@ -655,9 +649,7 @@ def url_quote_plus( stacklevel=2, ) - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - return url_quote(string, charset, errors, safe + " ", "+").replace(" ", "+") + return url_quote(string, charset, errors, safe + " ", "+").replace(" ", "+") def url_unparse(components: tuple[str, str, str, str, str]) -> str: @@ -668,10 +660,10 @@ def url_unparse(components: tuple[str, str, str, str, str]) -> str: into a URL string. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.urlunsplit`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.urlunsplit`` instead. """ warnings.warn( - "'werkzeug.urls.url_unparse' is deprecated and will be removed in Werkzeug 2.4." + "'werkzeug.urls.url_unparse' is deprecated and will be removed in Werkzeug 3.0." " Use 'urllib.parse.urlunsplit' instead.", DeprecationWarning, stacklevel=2, @@ -716,10 +708,10 @@ def url_unquote( :param errors: the error handling for the charset decoding. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.unquote`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.unquote`` instead. """ warnings.warn( - "'werkzeug.urls.url_unquote' is deprecated and will be removed in Werkzeug 2.4." + "'werkzeug.urls.url_unquote' is deprecated and will be removed in Werkzeug 3.0." " Use 'urllib.parse.unquote' instead.", DeprecationWarning, stacklevel=2, @@ -745,7 +737,7 @@ def url_unquote_plus( :param errors: The error handling for the `charset` decoding. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.unquote_plus`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.unquote_plus`` instead. """ warnings.warn( "'werkzeug.urls.url_unquote_plus' is deprecated and will be removed in Werkzeug" @@ -759,9 +751,7 @@ def url_unquote_plus( else: s = s.replace(b"+", b" ") - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - return url_unquote(s, charset, errors) + return url_unquote(s, charset, errors) def url_fix(s: str, charset: str = "utf-8") -> str: @@ -778,10 +768,10 @@ def url_fix(s: str, charset: str = "utf-8") -> str: as a string. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. + Will be removed in Werkzeug 3.0. """ warnings.warn( - "'werkzeug.urls.url_fix' is deprecated and will be removed in Werkzeug 2.4.", + "'werkzeug.urls.url_fix' is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -795,13 +785,11 @@ def url_fix(s: str, charset: str = "utf-8") -> str: if s.startswith("file://") and s[7:8].isalpha() and s[8:10] in (":/", "|/"): s = f"file:///{s[7:]}" - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'werkzeug", DeprecationWarning) - url = url_parse(s) - path = url_quote(url.path, charset, safe="/%+$!*'(),") - qs = url_quote_plus(url.query, charset, safe=":&%=+$!*'(),") - anchor = url_quote_plus(url.fragment, charset, safe=":&%=+$!*'(),") - return url_unparse((url.scheme, url.encode_netloc(), path, qs, anchor)) + url = url_parse(s) + path = url_quote(url.path, charset, safe="/%+$!*'(),") + qs = url_quote_plus(url.query, charset, safe=":&%=+$!*'(),") + anchor = url_quote_plus(url.fragment, charset, safe=":&%=+$!*'(),") + return url_unparse((url.scheme, url.encode_netloc(), path, qs, anchor)) def _codec_error_url_quote(e: UnicodeError) -> tuple[str, int]: @@ -868,7 +856,7 @@ def uri_to_iri( .. versionchanged:: 2.3 Passing a tuple or bytes, and the ``charset`` and ``errors`` parameters, are - deprecated and will be removed in Werkzeug 2.4. + deprecated and will be removed in Werkzeug 3.0. .. versionchanged:: 2.3 Which characters remain quoted is specific to each part of the URL. @@ -882,7 +870,7 @@ def uri_to_iri( """ if isinstance(uri, tuple): warnings.warn( - "Passing a tuple is deprecated and will not be supported in Werkzeug 2.4.", + "Passing a tuple is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -890,7 +878,7 @@ def uri_to_iri( if isinstance(uri, bytes): warnings.warn( - "Passing bytes is deprecated and will not be supported in Werkzeug 2.4.", + "Passing bytes is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -899,7 +887,7 @@ def uri_to_iri( if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be removed" - " in Werkzeug 2.4.", + " in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -908,7 +896,7 @@ def uri_to_iri( if errors is not None: warnings.warn( - "The 'errors' parameter is deprecated and will be removed in Werkzeug 2.4.", + "The 'errors' parameter is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -960,7 +948,7 @@ def iri_to_uri( .. versionchanged:: 2.3 Passing a tuple or bytes, and the ``charset`` and ``errors`` parameters, are - deprecated and will be removed in Werkzeug 2.4. + deprecated and will be removed in Werkzeug 3.0. .. versionchanged:: 2.3 Which characters remain unquoted is specific to each part of the URL. @@ -980,7 +968,7 @@ def iri_to_uri( """ if isinstance(iri, tuple): warnings.warn( - "Passing a tuple is deprecated and will not be supported in Werkzeug 2.4.", + "Passing a tuple is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -988,7 +976,7 @@ def iri_to_uri( if isinstance(iri, bytes): warnings.warn( - "Passing bytes is deprecated and will not be supported in Werkzeug 2.4.", + "Passing bytes is deprecated and will not be supported in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -997,7 +985,7 @@ def iri_to_uri( if charset is not None: warnings.warn( "The 'charset' parameter is deprecated and will be removed" - " in Werkzeug 2.4.", + " in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1006,7 +994,7 @@ def iri_to_uri( if errors is not None: warnings.warn( - "The 'errors' parameter is deprecated and will be removed in Werkzeug 2.4.", + "The 'errors' parameter is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1016,7 +1004,7 @@ def iri_to_uri( if safe_conversion is not None: warnings.warn( "The 'safe_conversion' parameter is deprecated and will be removed in" - " Werkzeug 2.4.", + " Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -1065,6 +1053,27 @@ def iri_to_uri( return urlunsplit((parts.scheme, netloc, path, query, fragment)) +def _invalid_iri_to_uri(iri: str) -> str: + """The URL scheme ``itms-services://`` must contain the ``//`` even though it does + not have a host component. There may be other invalid schemes as well. Currently, + responses will always call ``iri_to_uri`` on the redirect ``Location`` header, which + removes the ``//``. For now, if the IRI only contains ASCII and does not contain + spaces, pass it on as-is. In Werkzeug 3.0, this should become a + ``response.process_location`` flag. + + :meta private: + """ + try: + iri.encode("ascii") + except UnicodeError: + pass + else: + if len(iri.split(None, 1)) == 1: + return iri + + return iri_to_uri(iri) + + def url_decode( s: t.AnyStr, charset: str = "utf-8", @@ -1084,7 +1093,7 @@ def url_decode( :param cls: Container to hold result instead of :class:`MultiDict`. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. Use ``urllib.parse.parse_qs`` instead. + Will be removed in Werkzeug 3.0. Use ``urllib.parse.parse_qs`` instead. .. versionchanged:: 2.1 The ``decode_keys`` parameter was removed. @@ -1171,9 +1180,7 @@ def url_decode_stream( cls = MultiDict - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'make_chunk_iter", DeprecationWarning) - return cls(decoder) + return cls(decoder) def _url_decode_impl( diff --git a/src/werkzeug/utils.py b/src/werkzeug/utils.py index d0841d84..785ac28b 100644 --- a/src/werkzeug/utils.py +++ b/src/werkzeug/utils.py @@ -260,21 +260,17 @@ def redirect( response. The default is :class:`werkzeug.wrappers.Response` if unspecified. """ - from .urls import iri_to_uri - if Response is None: from .wrappers import Response - display_location = escape(location) - location = iri_to_uri(location) + html_location = escape(location) response = Response( # type: ignore[misc] "<!doctype html>\n" "<html lang=en>\n" "<title>Redirecting...</title>\n" "<h1>Redirecting...</h1>\n" "<p>You should be redirected automatically to the target URL: " - f'<a href="{escape(location)}">{display_location}</a>. If' - " not, click the link.\n", + f'<a href="{html_location}">{html_location}</a>. If not, click the link.\n', code, mimetype="text/html", ) diff --git a/src/werkzeug/wrappers/response.py b/src/werkzeug/wrappers/response.py index d2f20091..c8488094 100644 --- a/src/werkzeug/wrappers/response.py +++ b/src/werkzeug/wrappers/response.py @@ -8,6 +8,7 @@ from urllib.parse import urljoin from ..datastructures import Headers from ..http import remove_entity_headers from ..sansio.response import Response as _SansIOResponse +from ..urls import _invalid_iri_to_uri from ..urls import iri_to_uri from ..utils import cached_property from ..wsgi import ClosingIterator @@ -478,11 +479,11 @@ class Response(_SansIOResponse): elif ikey == "content-length": content_length = value - # make sure the location header is an absolute URL if location is not None: - location = iri_to_uri(location) + location = _invalid_iri_to_uri(location) if self.autocorrect_location_header: + # Make the location header an absolute URL. current_url = get_current_url(environ, strip_querystring=True) current_url = iri_to_uri(current_url) location = urljoin(current_url, location) diff --git a/src/werkzeug/wsgi.py b/src/werkzeug/wsgi.py index a3a2fbb5..6061e114 100644 --- a/src/werkzeug/wsgi.py +++ b/src/werkzeug/wsgi.py @@ -211,14 +211,14 @@ def get_path_info( .. versionchanged:: 2.3 The ``charset`` and ``errors`` parameters are deprecated and will be removed in - Werkzeug 2.4. + Werkzeug 3.0. .. versionadded:: 0.9 """ if charset is not ...: warnings.warn( "The 'charset' parameter is deprecated and will be removed" - " in Werkzeug 2.4.", + " in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -230,7 +230,7 @@ def get_path_info( if errors is not None: warnings.warn( - "The 'errors' parameter is deprecated and will be removed in Werkzeug 2.4", + "The 'errors' parameter is deprecated and will be removed in Werkzeug 3.0", DeprecationWarning, stacklevel=2, ) @@ -462,7 +462,7 @@ def _make_chunk_iter( ) -> t.Iterator[bytes]: """Helper for the line and chunk iter functions.""" warnings.warn( - "'_make_chunk_iter' is deprecated and will be removed in Werkzeug 2.4.", + "'_make_chunk_iter' is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) @@ -506,7 +506,7 @@ def make_line_iter( over the input stream using this helper function. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. + Will be removed in Werkzeug 3.0. .. versionadded:: 0.11 added support for the `cap_at_buffer` parameter. @@ -528,15 +528,13 @@ def make_line_iter( of two however. """ warnings.warn( - "'make_line_iter' is deprecated and will be removed in Werkzeug 2.4.", + "'make_line_iter' is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) _iter = _make_chunk_iter(stream, limit, buffer_size) - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'_make_chunk_iter", DeprecationWarning) - first_item = next(_iter, "") + first_item = next(_iter, "") if not first_item: return @@ -603,7 +601,7 @@ def make_chunk_iter( supports arbitrary newline markers. .. deprecated:: 2.3 - Will be removed in Werkzeug 2.4. + Will be removed in Werkzeug 3.0. .. versionchanged:: 0.11 added support for the `cap_at_buffer` parameter. @@ -625,15 +623,13 @@ def make_chunk_iter( of two however. """ warnings.warn( - "'make_chunk_iter' is deprecated and will be removed in Werkzeug 2.4.", + "'make_chunk_iter' is deprecated and will be removed in Werkzeug 3.0.", DeprecationWarning, stacklevel=2, ) _iter = _make_chunk_iter(stream, limit, buffer_size) - with warnings.catch_warnings(): - warnings.filterwarnings("ignore", "'_make_chunk_iter", DeprecationWarning) - first_item = next(_iter, b"") + first_item = next(_iter, b"") if not first_item: return diff --git a/tests/test_formparser.py b/tests/test_formparser.py index f9b44d7c..1dcb167e 100644 --- a/tests/test_formparser.py +++ b/tests/test_formparser.py @@ -126,8 +126,8 @@ class TestFormParser: r = Request.from_values(method="POST", data={"a": 1, "b": 2}) r.max_form_parts = 1 - with pytest.raises(RequestEntityTooLarge): - r.form + assert r.form["a"] == "1" + assert r.form["b"] == "2" def test_missing_multipart_boundary(self): data = ( diff --git a/tests/test_urls.py b/tests/test_urls.py index 8baf0ad6..56bca8e9 100644 --- a/tests/test_urls.py +++ b/tests/test_urls.py @@ -1,11 +1,15 @@ import io +import warnings import pytest from werkzeug import urls from werkzeug.datastructures import OrderedMultiDict -pytestmark = [pytest.mark.filterwarnings("ignore:'werkzeug:DeprecationWarning")] +pytestmark = [ + pytest.mark.filterwarnings("ignore:'werkzeug:DeprecationWarning"), + pytest.mark.filterwarnings("ignore:'_?make_chunk_iter':DeprecationWarning"), +] def test_parsing(): @@ -382,3 +386,12 @@ def test_iri_to_uri_dont_quote_valid_code_points(): # [] are not valid URL code points according to WhatWG URL Standard # https://url.spec.whatwg.org/#url-code-points assert urls.iri_to_uri("/path[bracket]?(paren)") == "/path%5Bbracket%5D?(paren)" + + +def test_url_parse_does_not_clear_warnings_registry(recwarn): + warnings.simplefilter("default") + warnings.simplefilter("ignore", DeprecationWarning) + for _ in range(2): + urls.url_parse("http://example.org/") + warnings.warn("test warning") + assert len(recwarn) == 1 diff --git a/tests/test_utils.py b/tests/test_utils.py index ed8d8d03..b7f1bcb1 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import inspect from datetime import datetime @@ -9,48 +11,32 @@ from werkzeug.datastructures import Headers from werkzeug.http import http_date from werkzeug.http import parse_date from werkzeug.test import Client +from werkzeug.test import EnvironBuilder from werkzeug.wrappers import Response -def test_redirect(): - resp = utils.redirect("/füübär") - assert resp.headers["Location"] == "/f%C3%BC%C3%BCb%C3%A4r" - assert resp.status_code == 302 - assert resp.get_data() == ( - b"<!doctype html>\n" - b"<html lang=en>\n" - b"<title>Redirecting...</title>\n" - b"<h1>Redirecting...</h1>\n" - b"<p>You should be redirected automatically to the target URL: " - b'<a href="/f%C3%BC%C3%BCb%C3%A4r">/f\xc3\xbc\xc3\xbcb\xc3\xa4r</a>. ' - b"If not, click the link.\n" - ) +@pytest.mark.parametrize( + ("url", "code", "expect"), + [ + ("http://example.com", None, "http://example.com"), + ("/füübär", 305, "/f%C3%BC%C3%BCb%C3%A4r"), + ("http://☃.example.com/", 307, "http://xn--n3h.example.com/"), + ("itms-services://?url=abc", None, "itms-services://?url=abc"), + ], +) +def test_redirect(url: str, code: int | None, expect: str) -> None: + environ = EnvironBuilder().get_environ() - resp = utils.redirect("http://☃.net/", 307) - assert resp.headers["Location"] == "http://xn--n3h.net/" - assert resp.status_code == 307 - assert resp.get_data() == ( - b"<!doctype html>\n" - b"<html lang=en>\n" - b"<title>Redirecting...</title>\n" - b"<h1>Redirecting...</h1>\n" - b"<p>You should be redirected automatically to the target URL: " - b'<a href="http://xn--n3h.net/">http://\xe2\x98\x83.net/</a>. ' - b"If not, click the link.\n" - ) + if code is None: + resp = utils.redirect(url) + assert resp.status_code == 302 + else: + resp = utils.redirect(url, code) + assert resp.status_code == code - resp = utils.redirect("http://example.com/", 305) - assert resp.headers["Location"] == "http://example.com/" - assert resp.status_code == 305 - assert resp.get_data() == ( - b"<!doctype html>\n" - b"<html lang=en>\n" - b"<title>Redirecting...</title>\n" - b"<h1>Redirecting...</h1>\n" - b"<p>You should be redirected automatically to the target URL: " - b'<a href="http://example.com/">http://example.com/</a>. ' - b"If not, click the link.\n" - ) + assert resp.headers["Location"] == url + assert resp.get_wsgi_headers(environ)["Location"] == expect + assert resp.get_data(as_text=True).count(url) == 2 def test_redirect_xss(): diff --git a/tests/test_wsgi.py b/tests/test_wsgi.py index d8335e5a..5f37aca9 100644 --- a/tests/test_wsgi.py +++ b/tests/test_wsgi.py @@ -257,6 +257,7 @@ def test_get_current_url_invalid_utf8(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_multi_part_line_breaks(): data = b"abcdef\r\nghijkl\r\nmnopqrstuvwxyz\r\nABCDEFGHIJK" test_stream = io.BytesIO(data) @@ -279,6 +280,7 @@ def test_multi_part_line_breaks(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_multi_part_line_breaks_bytes(): data = b"abcdef\r\nghijkl\r\nmnopqrstuvwxyz\r\nABCDEFGHIJK" test_stream = io.BytesIO(data) @@ -301,6 +303,7 @@ def test_multi_part_line_breaks_bytes(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_multi_part_line_breaks_problematic(): data = b"abc\rdef\r\nghi" for _ in range(1, 10): @@ -310,13 +313,14 @@ def test_multi_part_line_breaks_problematic(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_iter_functions_support_iterators(): data = ["abcdef\r\nghi", "jkl\r\nmnopqrstuvwxyz\r", "\nABCDEFGHIJK"] lines = list(wsgi.make_line_iter(data)) assert lines == ["abcdef\r\n", "ghijkl\r\n", "mnopqrstuvwxyz\r\n", "ABCDEFGHIJK"] -@pytest.mark.filterwarnings("ignore:'make_chunk_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_?make_chunk_iter:DeprecationWarning") def test_make_chunk_iter(): data = [b"abcdefXghi", b"jklXmnopqrstuvwxyzX", b"ABCDEFGHIJK"] rv = list(wsgi.make_chunk_iter(data, b"X")) @@ -328,7 +332,7 @@ def test_make_chunk_iter(): assert rv == [b"abcdef", b"ghijkl", b"mnopqrstuvwxyz", b"ABCDEFGHIJK"] -@pytest.mark.filterwarnings("ignore:'make_chunk_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_?make_chunk_iter:DeprecationWarning") def test_make_chunk_iter_bytes(): data = [b"abcdefXghi", b"jklXmnopqrstuvwxyzX", b"ABCDEFGHIJK"] rv = list(wsgi.make_chunk_iter(data, "X")) @@ -362,6 +366,7 @@ def test_make_chunk_iter_bytes(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_lines_longer_buffer_size(): data = b"1234567890\n1234567890\n" for bufsize in range(1, 15): @@ -372,6 +377,7 @@ def test_lines_longer_buffer_size(): @pytest.mark.filterwarnings("ignore:'make_line_iter:DeprecationWarning") +@pytest.mark.filterwarnings("ignore:'_make_chunk_iter:DeprecationWarning") def test_lines_longer_buffer_size_cap(): data = b"1234567890\n1234567890\n" for bufsize in range(1, 15): |