From 2ffa7c1de0b2fca509fc7afebeb82543d4421dfb Mon Sep 17 00:00:00 2001 From: David Lord Date: Fri, 25 Mar 2022 14:16:42 -0700 Subject: [PATCH] deprecate parse_options_header multiple parameter --- CHANGES.rst | 2 ++ src/werkzeug/http.py | 52 ++++++++++++++++++++------------------------ tests/test_http.py | 37 +++++++++++++++++-------------- 3 files changed, 47 insertions(+), 44 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index b1cee54c8..f34ec9bae 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -47,6 +47,8 @@ Unreleased - Remove ``format_string``, use :class:`string.Template` instead. - Remove ``escape`` and ``unescape``. Use MarkupSafe instead. +- The ``multiple`` parameter of ``parse_options_header`` is + deprecated. :pr:`2357` - Rely on :pep:`538` and :pep:`540` to handle decoding file names with the correct filesystem encoding. The ``filesystem`` module is removed. :issue:`1760` diff --git a/src/werkzeug/http.py b/src/werkzeug/http.py index cf1ed1645..936990013 100644 --- a/src/werkzeug/http.py +++ b/src/werkzeug/http.py @@ -376,43 +376,39 @@ def parse_dict_header(value: str, cls: t.Type[dict] = dict) -> t.Dict[str, str]: return result -@typing.overload def parse_options_header( - value: t.Optional[str], multiple: "te.Literal[False]" = False + value: t.Optional[str], multiple: "te.Literal[None]" = None ) -> t.Tuple[str, t.Dict[str, str]]: - ... - - -@typing.overload -def parse_options_header( - value: t.Optional[str], multiple: "te.Literal[True]" -) -> t.Tuple[t.Any, ...]: - ... - - -def parse_options_header( - value: t.Optional[str], multiple: bool = False -) -> t.Union[t.Tuple[str, t.Dict[str, str]], t.Tuple[t.Any, ...]]: - """Parse a ``Content-Type`` like header into a tuple with the content - type and the options: + """Parse a ``Content-Type``-like header into a tuple with the + value and any options: >>> parse_options_header('text/html; charset=utf8') ('text/html', {'charset': 'utf8'}) - This should not be used to parse ``Cache-Control`` like headers that use - a slightly different format. For these headers use the - :func:`parse_dict_header` function. + This should is not for ``Cache-Control``-like headers, which use a + different format. For those, use :func:`parse_dict_header`. + + :param value: The header value to parse. + + .. versionchanged:: 2.1 + The ``multiple`` parameter is deprecated and will be removed in + Werkzeug 2.2. .. versionchanged:: 0.15 :rfc:`2231` parameter continuations are handled. .. versionadded:: 0.5 - - :param value: the header to parse. - :param multiple: Whether try to parse and return multiple MIME types - :return: (mimetype, options) or (mimetype, options, mimetype, options, …) - if multiple=True """ + if multiple is not None: + import warnings + + warnings.warn( + "The 'multiple' parameter of 'parse_options_header' is" + " deprecated and will be removed in Werkzeug 2.2.", + DeprecationWarning, + stacklevel=2, + ) + if not value: return "", {} @@ -463,11 +459,11 @@ def parse_options_header( rest = rest[optmatch.end() :] result.append(options) - if multiple is False: - return tuple(result) + if not multiple: + return tuple(result) # type: ignore[return-value] value = rest - return tuple(result) if result else ("", {}) + return tuple(result) if result else ("", {}) # type: ignore[return-value] _TAnyAccept = t.TypeVar("_TAnyAccept", bound="ds.Accept") diff --git a/tests/test_http.py b/tests/test_http.py index 853df5478..dfa6dd119 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -301,22 +301,27 @@ def test_parse_options_header(self): "audio/*", {"q": "0.2"}, ) - assert http.parse_options_header( - "audio/*; q=0.2, audio/basic", multiple=True - ) == ("audio/*", {"q": "0.2"}, "audio/basic", {}) - assert http.parse_options_header( - "text/plain; q=0.5, text/html\n text/x-dvi; q=0.8, text/x-c", - multiple=True, - ) == ( - "text/plain", - {"q": "0.5"}, - "text/html", - {}, - "text/x-dvi", - {"q": "0.8"}, - "text/x-c", - {}, - ) + + with pytest.warns(DeprecationWarning): + assert http.parse_options_header( + "audio/*; q=0.2, audio/basic", multiple=True + ) == ("audio/*", {"q": "0.2"}, "audio/basic", {}) + + with pytest.warns(DeprecationWarning): + assert http.parse_options_header( + "text/plain; q=0.5, text/html\n text/x-dvi; q=0.8, text/x-c", + multiple=True, + ) == ( + "text/plain", + {"q": "0.5"}, + "text/html", + {}, + "text/x-dvi", + {"q": "0.8"}, + "text/x-c", + {}, + ) + assert http.parse_options_header( "text/plain; q=0.5, text/html\n text/x-dvi; q=0.8, text/x-c" ) == ("text/plain", {"q": "0.5"})