Skip to content

Commit 3d92022

Browse files
mikeneroneasvetlov
authored andcommitted
Fix CIMultiDict output casing in Python implementations (to match Cython) (#203)
* Fix: setitem & setdefault lost original casing from caller * Fix: pytest.raises() used incorrect kwarg "matches" (has no effect) * Fix: KeyError messages should preserve passed casing * Fix: missing call to self._key()
1 parent 4b79935 commit 3d92022

3 files changed

Lines changed: 28 additions & 24 deletions

File tree

multidict/_multidict_py.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ def _extend(self, args, kwargs, name, method):
243243

244244
method(items)
245245

246-
method([(self._title(key), key, value)
246+
method([(self._title(key), self._key(key), value)
247247
for key, value in kwargs.items()])
248248

249249
def _extend_items(self, items):
@@ -258,15 +258,14 @@ def clear(self):
258258
# Mapping interface #
259259

260260
def __setitem__(self, key, value):
261-
key = self._title(key)
262261
self._replace(key, value)
263262

264263
def __delitem__(self, key):
265-
key = self._title(key)
264+
identity = self._title(key)
266265
items = self._impl._items
267266
found = False
268267
for i in range(len(items) - 1, -1, -1):
269-
if items[i][0] == key:
268+
if items[i][0] == identity:
270269
del items[i]
271270
found = True
272271
if not found:
@@ -276,9 +275,9 @@ def __delitem__(self, key):
276275

277276
def setdefault(self, key, default=None):
278277
"""Return value for key, set value to default if key is not present."""
279-
key = self._title(key)
278+
identity = self._title(key)
280279
for i, k, v in self._impl._items:
281-
if i == key:
280+
if i == identity:
282281
return v
283282
self.add(key, default)
284283
return default
@@ -290,9 +289,9 @@ def popone(self, key, default=_marker):
290289
KeyError is raised.
291290
292291
"""
293-
key = self._title(key)
292+
identity = self._title(key)
294293
for i in range(len(self._impl._items)):
295-
if self._impl._items[i][0] == key:
294+
if self._impl._items[i][0] == identity:
296295
value = self._impl._items[i][2]
297296
del self._impl._items[i]
298297
self._impl.incr_version()

tests/test_multidict.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ def test_getone(self, cls):
118118
assert d.get('key') == 'value1'
119119
assert d['key'] == 'value1'
120120

121-
with pytest.raises(KeyError, matches='key2'):
121+
with pytest.raises(KeyError, match='key2'):
122122
d['key2']
123-
with pytest.raises(KeyError, matches='key2'):
123+
with pytest.raises(KeyError, match='key2'):
124124
d.getone('key2')
125125

126126
assert d.getone('key2', 'default') == 'default'
@@ -326,7 +326,7 @@ def test_getall(self, cls):
326326

327327
assert d.getall('key') == ['value1', 'value2']
328328

329-
with pytest.raises(KeyError, matches='some_key'):
329+
with pytest.raises(KeyError, match='some_key'):
330330
d.getall('some_key')
331331

332332
default = object()
@@ -374,9 +374,9 @@ def test_basics(self, cls):
374374
assert d['key'] == 'value1'
375375
assert 'key' in d
376376

377-
with pytest.raises(KeyError):
377+
with pytest.raises(KeyError, match='key2'):
378378
d['key2']
379-
with pytest.raises(KeyError):
379+
with pytest.raises(KeyError, match='key2'):
380380
d.getone('key2')
381381

382382
def test_getall(self, cls):
@@ -387,9 +387,8 @@ def test_getall(self, cls):
387387

388388
assert d.getall('key') == ['value1', 'value2']
389389

390-
with pytest.raises(KeyError) as excinfo:
390+
with pytest.raises(KeyError, match='some_key'):
391391
d.getall('some_key')
392-
assert "some_key" in str(excinfo.value)
393392

394393
def test_get(self, cls):
395394
d = cls([('A', 1), ('a', 2)])

tests/test_mutable_multidict.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ def test_getall(self, cls):
3737

3838
assert d.getall('key') == ['value1', 'value2']
3939

40-
with pytest.raises(KeyError) as excinfo:
40+
with pytest.raises(KeyError, match='some_key'):
4141
d.getall('some_key')
42-
assert 'some_key' in str(excinfo.value)
4342

4443
default = object()
4544
assert d.getall('some_key', default) is default
@@ -116,7 +115,7 @@ def test_del(self, cls):
116115
assert d == {'foo': 'bar'}
117116
assert list(d.items()) == [('foo', 'bar')]
118117

119-
with pytest.raises(KeyError):
118+
with pytest.raises(KeyError, match='key'):
120119
del d['key']
121120

122121
def test_set_default(self, cls):
@@ -166,7 +165,7 @@ def test_pop_default(self, cls):
166165
def test_pop_raises(self, cls):
167166
d = cls(other='val')
168167

169-
with pytest.raises(KeyError):
168+
with pytest.raises(KeyError, match='key'):
170169
d.pop('key')
171170

172171
assert 'other' in d
@@ -218,7 +217,7 @@ def test_popall_default(self, cls):
218217

219218
def test_popall_key_error(self, cls):
220219
d = cls()
221-
with pytest.raises(KeyError):
220+
with pytest.raises(KeyError, match='key'):
222221
d.popall('key')
223222

224223

@@ -244,18 +243,19 @@ def test_getall(self, cls):
244243

245244
assert d.getall('key') == ['value1', 'value2']
246245

247-
with pytest.raises(KeyError) as excinfo:
246+
with pytest.raises(KeyError, match='some_key'):
248247
d.getall('some_key')
249-
assert 'some_key' in str(excinfo.value)
250248

251249
def test_ctor(self, cls):
252250
d = cls(k1='v1')
253251
assert 'v1' == d['K1']
252+
assert ('k1', 'v1') in d.items()
254253

255254
def test_setitem(self, cls):
256255
d = cls()
257256
d['k1'] = 'v1'
258257
assert 'v1' == d['K1']
258+
assert ('k1', 'v1') in d.items()
259259

260260
def test_delitem(self, cls):
261261
d = cls()
@@ -269,6 +269,7 @@ def test_copy(self, cls):
269269

270270
d2 = d1.copy()
271271
assert d1 == d2
272+
assert d1.items() == d2.items()
272273
assert d1 is not d2
273274

274275
def test__repr__(self, cls):
@@ -285,18 +286,22 @@ def test_add(self, cls):
285286

286287
assert d == {}
287288
d['KEY'] = 'one'
289+
assert ('KEY', 'one') in d.items()
288290
assert d == cls({'Key': 'one'})
289291
assert d.getall('key') == ['one']
290292

291293
d['KEY'] = 'two'
294+
assert ('KEY', 'two') in d.items()
292295
assert d == cls({'Key': 'two'})
293296
assert d.getall('key') == ['two']
294297

295298
d.add('KEY', 'one')
299+
assert ('KEY', 'one') in d.items()
296300
assert 2 == len(d)
297301
assert d.getall('key') == ['two', 'one']
298302

299303
d.add('FOO', 'bar')
304+
assert ('FOO', 'bar') in d.items()
300305
assert 3 == len(d)
301306
assert d.getall('foo') == ['bar']
302307

@@ -353,14 +358,15 @@ def test_del(self, cls):
353358
assert d == {'foo': 'bar'}
354359
assert list(d.items()) == [('foo', 'bar')]
355360

356-
with pytest.raises(KeyError):
361+
with pytest.raises(KeyError, match='key'):
357362
del d['key']
358363

359364
def test_set_default(self, cls):
360365
d = cls([('KEY', 'one'), ('key', 'two')], foo='bar')
361366
assert 'one' == d.setdefault('key', 'three')
362367
assert 'three' == d.setdefault('otherkey', 'three')
363368
assert 'otherkey' in d
369+
assert ('otherkey', 'three') in d.items()
364370
assert 'three' == d['OTHERKEY']
365371

366372
def test_popitem(self, cls):
@@ -404,7 +410,7 @@ def test_pop_default(self, cls):
404410
def test_pop_raises(self, cls):
405411
d = cls(OTHER='val')
406412

407-
with pytest.raises(KeyError):
413+
with pytest.raises(KeyError, match="KEY"):
408414
d.pop('KEY')
409415

410416
assert 'other' in d

0 commit comments

Comments
 (0)