Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deprecate parse_options_header multiple parameter #2357

Merged
merged 1 commit into from Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.rst
Expand Up @@ -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`
Expand Down
52 changes: 24 additions & 28 deletions src/werkzeug/http.py
Expand Up @@ -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 "", {}

Expand Down Expand Up @@ -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")
Expand Down
37 changes: 21 additions & 16 deletions tests/test_http.py
Expand Up @@ -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"})
Expand Down