Skip to content

Commit

Permalink
add test for positional header parameters
Browse files Browse the repository at this point in the history
pass args to _options_header_vkw
allow positional args to set too
more permissive mapping vs sequence check
  • Loading branch information
davidism committed Apr 8, 2017
1 parent 848b79d commit 50747b9
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 21 deletions.
3 changes: 3 additions & 0 deletions tests/test_datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,9 @@ def test_basic_interface(self):
headers.add('x', 'y', z='"')
assert headers['x'] == r'y; z="\""'

headers.add('multi', 'yes', ('a', '1',), ('b', '2'), c='3')
assert headers['multi'] == 'yes; a=1; b=2; c=3'

def test_defaults_and_conversion(self):
# defaults
headers = self.storage_class([
Expand Down
50 changes: 34 additions & 16 deletions werkzeug/datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,9 +889,20 @@ def popitemlist(self):
return key, [x.value for x in buckets]


def _options_header_vkw(value, kw):
return dump_options_header(value, dict((k.replace('_', '-'), v)
for k, v in kw.items()))
def _options_header_vkw(value, args, kwargs):
if args:
value = dump_options_header(
value,
((k.replace('_', '-'), v) for k, v in args)
)

if kwargs:
value = dump_options_header(
value,
dict((k.replace('_', '-'), v) for k, v in iteritems(kwargs))
)

return value


def _unicodify_header_value(value):
Expand Down Expand Up @@ -1140,7 +1151,7 @@ def __iter__(self):
def __len__(self):
return len(self._list)

def add(self, _key, _value, *args, **kw):
def add(self, _key, _value, *args, **kwargs):
"""Add a new header tuple to the list.
Keyword arguments can specify additional parameters for the header
Expand All @@ -1153,17 +1164,24 @@ def add(self, _key, _value, *args, **kw):
The keyword argument dumping uses :func:`dump_options_header`
behind the scenes.
In some cases, it would be needed to ensure the order of parameters.
In some cases the order of the additional parameters is important.
For those cases, a list of ``(key, value)`` tuples can be passed in
*args.
``*args``::
d.add(
'Content-Disposition', 'attachment',
('filename', 'foo.png'), ('filename*', "UTF-8''fo%C3%B6.png")
)
.. versionadded:: 0.13.0
Key/value tuples as positional arguments are supported to ensure
the order of parameters.
.. versionadded:: 0.4.1
keyword arguments were added for :mod:`wsgiref` compatibility.
"""
if args:
_value = dump_options_header(_value, args)
if kw:
_value = _options_header_vkw(_value, kw)
if args or kwargs:
_value = _options_header_vkw(_value, args, kwargs)
_value = _unicodify_header_value(_value)
self._validate_value(_value)
self._list.append((_key, _value))
Expand All @@ -1187,23 +1205,23 @@ def clear(self):
"""Clears all headers."""
del self._list[:]

def set(self, _key, _value, **kw):
def set(self, _key, _value, *args, **kwargs):
"""Remove all header tuples for `key` and add a new one. The newly
added key either appears at the end of the list if there was no
entry or replaces the first one.
Keyword arguments can specify additional parameters for the header
value, with underscores converted to dashes. See :meth:`add` for
more information.
Positional and keyword arguments can specify additional parameters for
the header value, with underscores converted to dashes. See
:meth:`add` for more information.
.. versionchanged:: 0.6.1
:meth:`set` now accepts the same arguments as :meth:`add`.
:param key: The key to be inserted.
:param value: The value to be inserted.
"""
if kw:
_value = _options_header_vkw(_value, kw)
if args or kwargs:
_value = _options_header_vkw(_value, args, kwargs)
_value = _unicodify_header_value(_value)
self._validate_value(_value)
if not self._list:
Expand Down
9 changes: 4 additions & 5 deletions werkzeug/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
:license: BSD, see LICENSE for more details.
"""
import re
from collections import Mapping
from time import time, gmtime
try:
from email.utils import parsedate_tz
Expand Down Expand Up @@ -207,15 +208,13 @@ def dump_options_header(header, options):
"""The reverse function to :func:`parse_options_header`.
:param header: the header to dump
:param options: a dict of options to append.
:param options: a dict of options to append. Or pass a sequence of
key, value pairs to ensure the order of the keys
"""
segments = []
if header is not None:
segments.append(header)
if isinstance(options, tuple):
iter_func = iter
else:
iter_func = iteritems
iter_func = iteritems if isinstance(options, Mapping) else iter
for key, value in iter_func(options):
if value is None:
segments.append(key)
Expand Down

0 comments on commit 50747b9

Please sign in to comment.