Skip to content

Commit

Permalink
Add a setlist method to the Headers datastructure
Browse files Browse the repository at this point in the history
The update method added in baa7bdc is
meant to replace headers with the mapping passed in. If a MultDict or
Headers object is passed in it would replace headers with the final
iterated value, rather than all the values iterated over. This could
lead to unexpected results, therefore this corrects the functionality
to what I think is expected.

Consider,

    h1 = Headers()
    h1.add("X-Multi", "value")
    h2 = Headers()
    h2.add("X-Multi", "newValue")
    h2.add("X-Multi", "alternativeValue")
    h1.update(h2)

previously `h1.getlist("X-Multi")` would likely equal
`["alternativeValue"]` whereas now it equals `["newValue",
"alternativeValue"]` which is as you'd expect.
  • Loading branch information
pgjones committed Jan 11, 2020
1 parent 3174fa6 commit 3c4783b
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 6 deletions.
32 changes: 28 additions & 4 deletions src/werkzeug/datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,19 @@ def set(self, _key, _value, **kw):
return
self._list[idx + 1 :] = [t for t in listiter if t[0].lower() != ikey]

def setlist(self, key, values):
"""Set multiple header values at once.
The `values` argument should be iterable. This will replace
any existing values for the key with the values passed. It is
the inverse of the getlist method.
.. versionadded:: 1.0
"""
self.set(key, values[0])
for value in values[1:]:
self.add(key, value)

def setdefault(self, key, default):
"""Returns the value for the key if it is in the dict, otherwise it
returns `default` and sets that value for `key`.
Expand Down Expand Up @@ -1279,10 +1292,21 @@ def update(self, *args, **kwargs):
raise TypeError("update expected at most 1 arguments, got %d" % len(args))

if args:
for key, value in iter_multi_items(args[0]):
self[key] = value

for key, value in iter_multi_items(kwargs):
mapping = args[0]

if isinstance(mapping, (Headers, MultiDict)):
for key in iterkeys(mapping):
self.setlist(key, mapping.getlist(key))
elif isinstance(mapping, dict):
for key, value in iteritems(mapping):
if isinstance(value, (tuple, list)):
self.setlist(key, value)
else:
self[key] = value
else:
for item in mapping:
self[key] = item
for key, value in iteritems(kwargs):
self[key] = value

def to_wsgi_list(self):
Expand Down
7 changes: 5 additions & 2 deletions tests/test_datastructures.py
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,11 @@ def test_update(self):
assert h.getlist("y") == ["1"]
h.update(z="2")
assert h.getlist("z") == ["2"]
h.update(self.storage_class([("a", "b")]))
assert h["a"] == "b"
h2 = self.storage_class([("a", "b")])
h2.add("a", "c")
h.update(h2, d="e")
assert h.getlist("a") == ["b", "c"]
assert h["d"] == "e"

def test_to_wsgi_list(self):
h = self.storage_class()
Expand Down

0 comments on commit 3c4783b

Please sign in to comment.