blob: 9ff8b7d501aad63e59da742facd033e41c7ab1ba [file] [log] [blame]
Victor Stinner5ebe2c82016-01-23 13:52:05 +01001import collections
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00002import collections.abc
Victor Stinner5ebe2c82016-01-23 13:52:05 +01003import gc
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00004import pickle
Victor Stinner5ebe2c82016-01-23 13:52:05 +01005import random
6import string
Victor Stinner78601a32016-09-09 19:28:36 -07007import sys
Victor Stinner5ebe2c82016-01-23 13:52:05 +01008import unittest
9import weakref
10from test import support
Walter Dörwald59b23e82004-09-30 13:46:00 +000011
12
13class DictTest(unittest.TestCase):
Guido van Rossum47b9ff62006-08-24 00:41:19 +000014
Benjamin Petersonfb886362010-04-24 18:21:17 +000015 def test_invalid_keyword_arguments(self):
Benjamin Petersonf6096542010-11-17 22:33:12 +000016 class Custom(dict):
17 pass
18 for invalid in {1 : 2}, Custom({1 : 2}):
19 with self.assertRaises(TypeError):
20 dict(**invalid)
21 with self.assertRaises(TypeError):
22 {}.update(**invalid)
Benjamin Petersonfb886362010-04-24 18:21:17 +000023
Walter Dörwald59b23e82004-09-30 13:46:00 +000024 def test_constructor(self):
25 # calling built-in types without argument must return empty
26 self.assertEqual(dict(), {})
Florent Xiclunaa988e422010-03-02 16:06:24 +000027 self.assertIsNot(dict(), {})
Walter Dörwald59b23e82004-09-30 13:46:00 +000028
Christian Heimes99170a52007-12-19 02:07:34 +000029 def test_literal_constructor(self):
Florent Xiclunaa988e422010-03-02 16:06:24 +000030 # check literal constructor for different sized dicts
31 # (to exercise the BUILD_MAP oparg).
Christian Heimesb186d002008-03-18 15:15:01 +000032 for n in (0, 1, 6, 256, 400):
Florent Xiclunaa988e422010-03-02 16:06:24 +000033 items = [(''.join(random.sample(string.ascii_letters, 8)), i)
Christian Heimesb186d002008-03-18 15:15:01 +000034 for i in range(n)]
35 random.shuffle(items)
Florent Xiclunaa988e422010-03-02 16:06:24 +000036 formatted_items = ('{!r}: {:d}'.format(k, v) for k, v in items)
37 dictliteral = '{' + ', '.join(formatted_items) + '}'
Christian Heimes99170a52007-12-19 02:07:34 +000038 self.assertEqual(eval(dictliteral), dict(items))
Christian Heimes99170a52007-12-19 02:07:34 +000039
Brandt Buchereb8ac572020-02-24 19:47:34 -080040 def test_merge_operator(self):
41
42 a = {0: 0, 1: 1, 2: 1}
43 b = {1: 1, 2: 2, 3: 3}
44
45 c = a.copy()
46 c |= b
47
48 self.assertEqual(a | b, {0: 0, 1: 1, 2: 2, 3: 3})
49 self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3})
50
51 c = b.copy()
52 c |= a
53
54 self.assertEqual(b | a, {1: 1, 2: 1, 3: 3, 0: 0})
55 self.assertEqual(c, {1: 1, 2: 1, 3: 3, 0: 0})
56
57 c = a.copy()
58 c |= [(1, 1), (2, 2), (3, 3)]
59
60 self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3})
61
62 self.assertIs(a.__or__(None), NotImplemented)
63 self.assertIs(a.__or__(()), NotImplemented)
64 self.assertIs(a.__or__("BAD"), NotImplemented)
65 self.assertIs(a.__or__(""), NotImplemented)
66
67 self.assertRaises(TypeError, a.__ior__, None)
68 self.assertEqual(a.__ior__(()), {0: 0, 1: 1, 2: 1})
69 self.assertRaises(ValueError, a.__ior__, "BAD")
70 self.assertEqual(a.__ior__(""), {0: 0, 1: 1, 2: 1})
71
Walter Dörwald59b23e82004-09-30 13:46:00 +000072 def test_bool(self):
Florent Xiclunaa988e422010-03-02 16:06:24 +000073 self.assertIs(not {}, True)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +000074 self.assertTrue({1: 2})
Florent Xiclunaa988e422010-03-02 16:06:24 +000075 self.assertIs(bool({}), False)
76 self.assertIs(bool({1: 2}), True)
Walter Dörwald59b23e82004-09-30 13:46:00 +000077
78 def test_keys(self):
79 d = {}
Guido van Rossume34cdd12007-02-14 17:49:04 +000080 self.assertEqual(set(d.keys()), set())
Walter Dörwald59b23e82004-09-30 13:46:00 +000081 d = {'a': 1, 'b': 2}
82 k = d.keys()
Ezio Melotti4e1f3d62013-10-05 03:07:03 +030083 self.assertEqual(set(k), {'a', 'b'})
84 self.assertIn('a', k)
85 self.assertIn('b', k)
Benjamin Peterson577473f2010-01-19 00:09:57 +000086 self.assertIn('a', d)
Benjamin Peterson577473f2010-01-19 00:09:57 +000087 self.assertIn('b', d)
Walter Dörwald59b23e82004-09-30 13:46:00 +000088 self.assertRaises(TypeError, d.keys, None)
Raymond Hettingerb0d56af2009-03-03 10:52:49 +000089 self.assertEqual(repr(dict(a=1).keys()), "dict_keys(['a'])")
Walter Dörwald59b23e82004-09-30 13:46:00 +000090
91 def test_values(self):
92 d = {}
Guido van Rossume34cdd12007-02-14 17:49:04 +000093 self.assertEqual(set(d.values()), set())
Walter Dörwald59b23e82004-09-30 13:46:00 +000094 d = {1:2}
Guido van Rossume34cdd12007-02-14 17:49:04 +000095 self.assertEqual(set(d.values()), {2})
Walter Dörwald59b23e82004-09-30 13:46:00 +000096 self.assertRaises(TypeError, d.values, None)
Raymond Hettingerb0d56af2009-03-03 10:52:49 +000097 self.assertEqual(repr(dict(a=1).values()), "dict_values([1])")
Walter Dörwald59b23e82004-09-30 13:46:00 +000098
99 def test_items(self):
100 d = {}
Guido van Rossume34cdd12007-02-14 17:49:04 +0000101 self.assertEqual(set(d.items()), set())
Walter Dörwald59b23e82004-09-30 13:46:00 +0000102
103 d = {1:2}
Guido van Rossume34cdd12007-02-14 17:49:04 +0000104 self.assertEqual(set(d.items()), {(1, 2)})
Walter Dörwald59b23e82004-09-30 13:46:00 +0000105 self.assertRaises(TypeError, d.items, None)
Raymond Hettingerb0d56af2009-03-03 10:52:49 +0000106 self.assertEqual(repr(dict(a=1).items()), "dict_items([('a', 1)])")
Walter Dörwald59b23e82004-09-30 13:46:00 +0000107
Dennis Sweeney3ee0e482020-06-12 13:19:25 -0400108 def test_views_mapping(self):
109 mappingproxy = type(type.__dict__)
110 class Dict(dict):
111 pass
112 for cls in [dict, Dict]:
113 d = cls()
114 m1 = d.keys().mapping
115 m2 = d.values().mapping
116 m3 = d.items().mapping
117
118 for m in [m1, m2, m3]:
119 self.assertIsInstance(m, mappingproxy)
120 self.assertEqual(m, d)
121
122 d["foo"] = "bar"
123
124 for m in [m1, m2, m3]:
125 self.assertIsInstance(m, mappingproxy)
126 self.assertEqual(m, d)
127
Walter Dörwald59b23e82004-09-30 13:46:00 +0000128 def test_contains(self):
129 d = {}
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000130 self.assertNotIn('a', d)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000131 self.assertFalse('a' in d)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000132 self.assertTrue('a' not in d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000133 d = {'a': 1, 'b': 2}
Benjamin Peterson577473f2010-01-19 00:09:57 +0000134 self.assertIn('a', d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000135 self.assertIn('b', d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000136 self.assertNotIn('c', d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000137
138 self.assertRaises(TypeError, d.__contains__)
139
140 def test_len(self):
141 d = {}
142 self.assertEqual(len(d), 0)
143 d = {'a': 1, 'b': 2}
144 self.assertEqual(len(d), 2)
145
146 def test_getitem(self):
147 d = {'a': 1, 'b': 2}
148 self.assertEqual(d['a'], 1)
149 self.assertEqual(d['b'], 2)
150 d['c'] = 3
151 d['a'] = 4
152 self.assertEqual(d['c'], 3)
153 self.assertEqual(d['a'], 4)
154 del d['b']
155 self.assertEqual(d, {'a': 4, 'c': 3})
156
157 self.assertRaises(TypeError, d.__getitem__)
158
159 class BadEq(object):
160 def __eq__(self, other):
161 raise Exc()
Guido van Rossum38938152006-08-21 23:36:26 +0000162 def __hash__(self):
163 return 24
Walter Dörwald59b23e82004-09-30 13:46:00 +0000164
165 d = {}
166 d[BadEq()] = 42
167 self.assertRaises(KeyError, d.__getitem__, 23)
168
169 class Exc(Exception): pass
170
171 class BadHash(object):
172 fail = False
173 def __hash__(self):
174 if self.fail:
175 raise Exc()
176 else:
177 return 42
178
179 x = BadHash()
180 d[x] = 42
181 x.fail = True
182 self.assertRaises(Exc, d.__getitem__, x)
183
184 def test_clear(self):
185 d = {1:1, 2:2, 3:3}
186 d.clear()
187 self.assertEqual(d, {})
188
189 self.assertRaises(TypeError, d.clear, None)
190
191 def test_update(self):
192 d = {}
193 d.update({1:100})
194 d.update({2:20})
195 d.update({1:1, 2:2, 3:3})
196 self.assertEqual(d, {1:1, 2:2, 3:3})
197
198 d.update()
199 self.assertEqual(d, {1:1, 2:2, 3:3})
200
201 self.assertRaises((TypeError, AttributeError), d.update, None)
202
203 class SimpleUserDict:
204 def __init__(self):
205 self.d = {1:1, 2:2, 3:3}
206 def keys(self):
207 return self.d.keys()
208 def __getitem__(self, i):
209 return self.d[i]
210 d.clear()
211 d.update(SimpleUserDict())
212 self.assertEqual(d, {1:1, 2:2, 3:3})
213
214 class Exc(Exception): pass
215
216 d.clear()
217 class FailingUserDict:
218 def keys(self):
219 raise Exc
220 self.assertRaises(Exc, d.update, FailingUserDict())
221
222 class FailingUserDict:
223 def keys(self):
224 class BogonIter:
225 def __init__(self):
226 self.i = 1
227 def __iter__(self):
228 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000229 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000230 if self.i:
231 self.i = 0
232 return 'a'
233 raise Exc
234 return BogonIter()
235 def __getitem__(self, key):
236 return key
237 self.assertRaises(Exc, d.update, FailingUserDict())
238
239 class FailingUserDict:
240 def keys(self):
241 class BogonIter:
242 def __init__(self):
243 self.i = ord('a')
244 def __iter__(self):
245 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000246 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000247 if self.i <= ord('z'):
248 rtn = chr(self.i)
249 self.i += 1
250 return rtn
251 raise StopIteration
252 return BogonIter()
253 def __getitem__(self, key):
254 raise Exc
255 self.assertRaises(Exc, d.update, FailingUserDict())
256
257 class badseq(object):
258 def __iter__(self):
259 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000260 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000261 raise Exc()
262
263 self.assertRaises(Exc, {}.update, badseq())
264
265 self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
266
267 def test_fromkeys(self):
268 self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
269 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000270 self.assertIsNot(d.fromkeys('abc'), d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000271 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
272 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
273 self.assertEqual(d.fromkeys([]), {})
274 def g():
275 yield 1
276 self.assertEqual(d.fromkeys(g()), {1:None})
277 self.assertRaises(TypeError, {}.fromkeys, 3)
278 class dictlike(dict): pass
279 self.assertEqual(dictlike.fromkeys('a'), {'a':None})
280 self.assertEqual(dictlike().fromkeys('a'), {'a':None})
Florent Xiclunaa988e422010-03-02 16:06:24 +0000281 self.assertIsInstance(dictlike.fromkeys('a'), dictlike)
282 self.assertIsInstance(dictlike().fromkeys('a'), dictlike)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000283 class mydict(dict):
284 def __new__(cls):
Raymond Hettingerf80680d2008-02-06 00:07:11 +0000285 return collections.UserDict()
Walter Dörwald59b23e82004-09-30 13:46:00 +0000286 ud = mydict.fromkeys('ab')
287 self.assertEqual(ud, {'a':None, 'b':None})
Ezio Melottie9615932010-01-24 19:26:24 +0000288 self.assertIsInstance(ud, collections.UserDict)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000289 self.assertRaises(TypeError, dict.fromkeys)
290
291 class Exc(Exception): pass
292
293 class baddict1(dict):
294 def __init__(self):
295 raise Exc()
296
297 self.assertRaises(Exc, baddict1.fromkeys, [1])
298
299 class BadSeq(object):
300 def __iter__(self):
301 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000302 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000303 raise Exc()
304
305 self.assertRaises(Exc, dict.fromkeys, BadSeq())
306
307 class baddict2(dict):
308 def __setitem__(self, key, value):
309 raise Exc()
310
311 self.assertRaises(Exc, baddict2.fromkeys, [1])
312
Guido van Rossum58da9312007-11-10 23:39:45 +0000313 # test fast path for dictionary inputs
314 d = dict(zip(range(6), range(6)))
315 self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
316
Benjamin Petersond1f2cb32012-10-31 14:05:55 -0400317 class baddict3(dict):
318 def __new__(cls):
319 return d
320 d = {i : i for i in range(10)}
321 res = d.copy()
322 res.update(a=None, b=None, c=None)
323 self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res)
324
Walter Dörwald59b23e82004-09-30 13:46:00 +0000325 def test_copy(self):
Yury Selivanovb0a7a032018-01-22 11:54:41 -0500326 d = {1: 1, 2: 2, 3: 3}
327 self.assertIsNot(d.copy(), d)
328 self.assertEqual(d.copy(), d)
329 self.assertEqual(d.copy(), {1: 1, 2: 2, 3: 3})
330
331 copy = d.copy()
332 d[4] = 4
333 self.assertNotEqual(copy, d)
334
Walter Dörwald59b23e82004-09-30 13:46:00 +0000335 self.assertEqual({}.copy(), {})
336 self.assertRaises(TypeError, d.copy, None)
337
Yury Selivanovb0a7a032018-01-22 11:54:41 -0500338 def test_copy_fuzz(self):
339 for dict_size in [10, 100, 1000, 10000, 100000]:
340 dict_size = random.randrange(
341 dict_size // 2, dict_size + dict_size // 2)
342 with self.subTest(dict_size=dict_size):
343 d = {}
344 for i in range(dict_size):
345 d[i] = i
346
347 d2 = d.copy()
348 self.assertIsNot(d2, d)
349 self.assertEqual(d, d2)
350 d2['key'] = 'value'
351 self.assertNotEqual(d, d2)
352 self.assertEqual(len(d2), len(d) + 1)
353
354 def test_copy_maintains_tracking(self):
355 class A:
356 pass
357
358 key = A()
359
360 for d in ({}, {'a': 1}, {key: 'val'}):
361 d2 = d.copy()
362 self.assertEqual(gc.is_tracked(d), gc.is_tracked(d2))
363
364 def test_copy_noncompact(self):
365 # Dicts don't compact themselves on del/pop operations.
366 # Copy will use a slow merging strategy that produces
367 # a compacted copy when roughly 33% of dict is a non-used
368 # keys-space (to optimize memory footprint).
369 # In this test we want to hit the slow/compacting
370 # branch of dict.copy() and make sure it works OK.
371 d = {k: k for k in range(1000)}
372 for k in range(950):
373 del d[k]
374 d2 = d.copy()
375 self.assertEqual(d2, d)
376
Walter Dörwald59b23e82004-09-30 13:46:00 +0000377 def test_get(self):
378 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000379 self.assertIs(d.get('c'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000380 self.assertEqual(d.get('c', 3), 3)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000381 d = {'a': 1, 'b': 2}
382 self.assertIs(d.get('c'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000383 self.assertEqual(d.get('c', 3), 3)
384 self.assertEqual(d.get('a'), 1)
385 self.assertEqual(d.get('a', 3), 1)
386 self.assertRaises(TypeError, d.get)
387 self.assertRaises(TypeError, d.get, None, None, None)
388
389 def test_setdefault(self):
390 # dict.setdefault()
391 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000392 self.assertIs(d.setdefault('key0'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000393 d.setdefault('key0', [])
Florent Xiclunaa988e422010-03-02 16:06:24 +0000394 self.assertIs(d.setdefault('key0'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000395 d.setdefault('key', []).append(3)
396 self.assertEqual(d['key'][0], 3)
397 d.setdefault('key', []).append(4)
398 self.assertEqual(len(d['key']), 2)
399 self.assertRaises(TypeError, d.setdefault)
400
401 class Exc(Exception): pass
402
403 class BadHash(object):
404 fail = False
405 def __hash__(self):
406 if self.fail:
407 raise Exc()
408 else:
409 return 42
410
411 x = BadHash()
412 d[x] = 42
413 x.fail = True
414 self.assertRaises(Exc, d.setdefault, x, [])
415
Antoine Pitroue965d972012-02-27 00:45:12 +0100416 def test_setdefault_atomic(self):
417 # Issue #13521: setdefault() calls __hash__ and __eq__ only once.
418 class Hashed(object):
419 def __init__(self):
420 self.hash_count = 0
421 self.eq_count = 0
422 def __hash__(self):
423 self.hash_count += 1
424 return 42
425 def __eq__(self, other):
426 self.eq_count += 1
427 return id(self) == id(other)
428 hashed1 = Hashed()
429 y = {hashed1: 5}
430 hashed2 = Hashed()
431 y.setdefault(hashed2, [])
432 self.assertEqual(hashed1.hash_count, 1)
433 self.assertEqual(hashed2.hash_count, 1)
434 self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
435
Benjamin Peterson7d95e402012-04-23 11:24:50 -0400436 def test_setitem_atomic_at_resize(self):
437 class Hashed(object):
438 def __init__(self):
439 self.hash_count = 0
440 self.eq_count = 0
441 def __hash__(self):
442 self.hash_count += 1
443 return 42
444 def __eq__(self, other):
445 self.eq_count += 1
446 return id(self) == id(other)
447 hashed1 = Hashed()
448 # 5 items
449 y = {hashed1: 5, 0: 0, 1: 1, 2: 2, 3: 3}
450 hashed2 = Hashed()
451 # 6th item forces a resize
452 y[hashed2] = []
453 self.assertEqual(hashed1.hash_count, 1)
454 self.assertEqual(hashed2.hash_count, 1)
455 self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
456
Walter Dörwald59b23e82004-09-30 13:46:00 +0000457 def test_popitem(self):
458 # dict.popitem()
459 for copymode in -1, +1:
460 # -1: b has same structure as a
461 # +1: b is a.copy()
462 for log2size in range(12):
463 size = 2**log2size
464 a = {}
465 b = {}
466 for i in range(size):
467 a[repr(i)] = i
468 if copymode < 0:
469 b[repr(i)] = i
470 if copymode > 0:
471 b = a.copy()
472 for i in range(size):
473 ka, va = ta = a.popitem()
474 self.assertEqual(va, int(ka))
475 kb, vb = tb = b.popitem()
476 self.assertEqual(vb, int(kb))
Florent Xiclunaa988e422010-03-02 16:06:24 +0000477 self.assertFalse(copymode < 0 and ta != tb)
478 self.assertFalse(a)
479 self.assertFalse(b)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000480
481 d = {}
482 self.assertRaises(KeyError, d.popitem)
483
484 def test_pop(self):
485 # Tests for pop with specified key
486 d = {}
487 k, v = 'abc', 'def'
488 d[k] = v
489 self.assertRaises(KeyError, d.pop, 'ghi')
490
491 self.assertEqual(d.pop(k), v)
492 self.assertEqual(len(d), 0)
493
494 self.assertRaises(KeyError, d.pop, k)
495
Walter Dörwald59b23e82004-09-30 13:46:00 +0000496 self.assertEqual(d.pop(k, v), v)
497 d[k] = v
498 self.assertEqual(d.pop(k, 1), v)
499
500 self.assertRaises(TypeError, d.pop)
501
502 class Exc(Exception): pass
503
504 class BadHash(object):
505 fail = False
506 def __hash__(self):
507 if self.fail:
508 raise Exc()
509 else:
510 return 42
511
512 x = BadHash()
513 d[x] = 42
514 x.fail = True
515 self.assertRaises(Exc, d.pop, x)
516
Victor Stinner198b2912012-03-06 01:03:13 +0100517 def test_mutating_iteration(self):
Florent Xiclunaa988e422010-03-02 16:06:24 +0000518 # changing dict size during iteration
Walter Dörwald59b23e82004-09-30 13:46:00 +0000519 d = {}
520 d[1] = 1
Florent Xiclunaa988e422010-03-02 16:06:24 +0000521 with self.assertRaises(RuntimeError):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000522 for i in d:
523 d[i+1] = 1
Walter Dörwald59b23e82004-09-30 13:46:00 +0000524
Thomas Perl796cc6e2019-03-28 07:03:25 +0100525 def test_mutating_iteration_delete(self):
526 # change dict content during iteration
527 d = {}
528 d[0] = 0
529 with self.assertRaises(RuntimeError):
530 for i in d:
531 del d[0]
Thomas Perlb8311cf2019-04-02 11:30:10 +0200532 d[0] = 0
533
534 def test_mutating_iteration_delete_over_values(self):
535 # change dict content during iteration
536 d = {}
537 d[0] = 0
538 with self.assertRaises(RuntimeError):
539 for i in d.values():
540 del d[0]
541 d[0] = 0
542
543 def test_mutating_iteration_delete_over_items(self):
544 # change dict content during iteration
545 d = {}
546 d[0] = 0
547 with self.assertRaises(RuntimeError):
548 for i in d.items():
549 del d[0]
550 d[0] = 0
Thomas Perl796cc6e2019-03-28 07:03:25 +0100551
Victor Stinner198b2912012-03-06 01:03:13 +0100552 def test_mutating_lookup(self):
Antoine Pitrou9a234902012-05-13 20:48:01 +0200553 # changing dict during a lookup (issue #14417)
Victor Stinner198b2912012-03-06 01:03:13 +0100554 class NastyKey:
555 mutate_dict = None
556
Victor Stinner28393822012-03-09 22:58:51 +0100557 def __init__(self, value):
558 self.value = value
559
Victor Stinner198b2912012-03-06 01:03:13 +0100560 def __hash__(self):
561 # hash collision!
562 return 1
563
564 def __eq__(self, other):
Victor Stinner28393822012-03-09 22:58:51 +0100565 if NastyKey.mutate_dict:
566 mydict, key = NastyKey.mutate_dict
567 NastyKey.mutate_dict = None
568 del mydict[key]
569 return self.value == other.value
Victor Stinner198b2912012-03-06 01:03:13 +0100570
Victor Stinner28393822012-03-09 22:58:51 +0100571 key1 = NastyKey(1)
572 key2 = NastyKey(2)
573 d = {key1: 1}
574 NastyKey.mutate_dict = (d, key1)
Antoine Pitrou9a234902012-05-13 20:48:01 +0200575 d[key2] = 2
576 self.assertEqual(d, {key2: 2})
Victor Stinner198b2912012-03-06 01:03:13 +0100577
Walter Dörwald59b23e82004-09-30 13:46:00 +0000578 def test_repr(self):
579 d = {}
580 self.assertEqual(repr(d), '{}')
581 d[1] = 2
582 self.assertEqual(repr(d), '{1: 2}')
583 d = {}
584 d[1] = d
585 self.assertEqual(repr(d), '{1: {...}}')
586
587 class Exc(Exception): pass
588
589 class BadRepr(object):
590 def __repr__(self):
591 raise Exc()
592
593 d = {1: BadRepr()}
594 self.assertRaises(Exc, repr, d)
595
Serhiy Storchaka1fb72d22017-12-03 22:12:11 +0200596 def test_repr_deep(self):
597 d = {}
598 for i in range(sys.getrecursionlimit() + 100):
599 d = {1: d}
600 self.assertRaises(RecursionError, repr, d)
601
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000602 def test_eq(self):
603 self.assertEqual({}, {})
Guido van Rossume2a383d2007-01-15 16:59:06 +0000604 self.assertEqual({1: 2}, {1: 2})
Walter Dörwald59b23e82004-09-30 13:46:00 +0000605
606 class Exc(Exception): pass
607
608 class BadCmp(object):
609 def __eq__(self, other):
610 raise Exc()
Guido van Rossum38938152006-08-21 23:36:26 +0000611 def __hash__(self):
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000612 return 1
Walter Dörwald59b23e82004-09-30 13:46:00 +0000613
614 d1 = {BadCmp(): 1}
615 d2 = {1: 1}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000616
617 with self.assertRaises(Exc):
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000618 d1 == d2
Walter Dörwald59b23e82004-09-30 13:46:00 +0000619
Guido van Rossumaac530c2007-08-24 22:33:45 +0000620 def test_keys_contained(self):
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000621 self.helper_keys_contained(lambda x: x.keys())
622 self.helper_keys_contained(lambda x: x.items())
623
624 def helper_keys_contained(self, fn):
Guido van Rossumaac530c2007-08-24 22:33:45 +0000625 # Test rich comparisons against dict key views, which should behave the
626 # same as sets.
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000627 empty = fn(dict())
628 empty2 = fn(dict())
629 smaller = fn({1:1, 2:2})
630 larger = fn({1:1, 2:2, 3:3})
631 larger2 = fn({1:1, 2:2, 3:3})
632 larger3 = fn({4:1, 2:2, 3:3})
Guido van Rossumaac530c2007-08-24 22:33:45 +0000633
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000634 self.assertTrue(smaller < larger)
635 self.assertTrue(smaller <= larger)
636 self.assertTrue(larger > smaller)
637 self.assertTrue(larger >= smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000638
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000639 self.assertFalse(smaller >= larger)
640 self.assertFalse(smaller > larger)
641 self.assertFalse(larger <= smaller)
642 self.assertFalse(larger < smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000643
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000644 self.assertFalse(smaller < larger3)
645 self.assertFalse(smaller <= larger3)
646 self.assertFalse(larger3 > smaller)
647 self.assertFalse(larger3 >= smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000648
649 # Inequality strictness
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000650 self.assertTrue(larger2 >= larger)
651 self.assertTrue(larger2 <= larger)
652 self.assertFalse(larger2 > larger)
653 self.assertFalse(larger2 < larger)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000654
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000655 self.assertTrue(larger == larger2)
656 self.assertTrue(smaller != larger)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000657
658 # There is an optimization on the zero-element case.
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000659 self.assertTrue(empty == empty2)
660 self.assertFalse(empty != empty2)
661 self.assertFalse(empty == smaller)
662 self.assertTrue(empty != smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000663
664 # With the same size, an elementwise compare happens
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000665 self.assertTrue(larger != larger3)
666 self.assertFalse(larger == larger3)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000667
668 def test_errors_in_view_containment_check(self):
669 class C:
670 def __eq__(self, other):
671 raise RuntimeError
Florent Xiclunaa988e422010-03-02 16:06:24 +0000672
Guido van Rossumaac530c2007-08-24 22:33:45 +0000673 d1 = {1: C()}
674 d2 = {1: C()}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000675 with self.assertRaises(RuntimeError):
676 d1.items() == d2.items()
677 with self.assertRaises(RuntimeError):
678 d1.items() != d2.items()
679 with self.assertRaises(RuntimeError):
680 d1.items() <= d2.items()
681 with self.assertRaises(RuntimeError):
682 d1.items() >= d2.items()
683
Guido van Rossumaac530c2007-08-24 22:33:45 +0000684 d3 = {1: C(), 2: C()}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000685 with self.assertRaises(RuntimeError):
686 d2.items() < d3.items()
687 with self.assertRaises(RuntimeError):
688 d3.items() > d2.items()
Guido van Rossumaac530c2007-08-24 22:33:45 +0000689
Guido van Rossumbe534712007-08-24 23:43:52 +0000690 def test_dictview_set_operations_on_keys(self):
Guido van Rossum523259b2007-08-24 23:41:22 +0000691 k1 = {1:1, 2:2}.keys()
692 k2 = {1:1, 2:2, 3:3}.keys()
693 k3 = {4:4}.keys()
694
Florent Xiclunaa988e422010-03-02 16:06:24 +0000695 self.assertEqual(k1 - k2, set())
696 self.assertEqual(k1 - k3, {1,2})
697 self.assertEqual(k2 - k1, {3})
698 self.assertEqual(k3 - k1, {4})
699 self.assertEqual(k1 & k2, {1,2})
700 self.assertEqual(k1 & k3, set())
701 self.assertEqual(k1 | k2, {1,2,3})
702 self.assertEqual(k1 ^ k2, {3})
703 self.assertEqual(k1 ^ k3, {1,2,4})
Guido van Rossum523259b2007-08-24 23:41:22 +0000704
Guido van Rossumbe534712007-08-24 23:43:52 +0000705 def test_dictview_set_operations_on_items(self):
706 k1 = {1:1, 2:2}.items()
707 k2 = {1:1, 2:2, 3:3}.items()
708 k3 = {4:4}.items()
709
Florent Xiclunaa988e422010-03-02 16:06:24 +0000710 self.assertEqual(k1 - k2, set())
711 self.assertEqual(k1 - k3, {(1,1), (2,2)})
712 self.assertEqual(k2 - k1, {(3,3)})
713 self.assertEqual(k3 - k1, {(4,4)})
714 self.assertEqual(k1 & k2, {(1,1), (2,2)})
715 self.assertEqual(k1 & k3, set())
716 self.assertEqual(k1 | k2, {(1,1), (2,2), (3,3)})
717 self.assertEqual(k1 ^ k2, {(3,3)})
718 self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)})
Guido van Rossum523259b2007-08-24 23:41:22 +0000719
Dennis Sweeney07d81122020-06-10 01:56:56 -0400720 def test_items_symmetric_difference(self):
721 rr = random.randrange
722 for _ in range(100):
723 left = {x:rr(3) for x in range(20) if rr(2)}
724 right = {x:rr(3) for x in range(20) if rr(2)}
725 with self.subTest(left=left, right=right):
726 expected = set(left.items()) ^ set(right.items())
727 actual = left.items() ^ right.items()
728 self.assertEqual(actual, expected)
729
Guido van Rossum1d719962007-08-24 23:47:30 +0000730 def test_dictview_mixed_set_operations(self):
731 # Just a few for .keys()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000732 self.assertTrue({1:1}.keys() == {1})
733 self.assertTrue({1} == {1:1}.keys())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000734 self.assertEqual({1:1}.keys() | {2}, {1, 2})
735 self.assertEqual({2} | {1:1}.keys(), {1, 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000736 # And a few for .items()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000737 self.assertTrue({1:1}.items() == {(1,1)})
738 self.assertTrue({(1,1)} == {1:1}.items())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000739 self.assertEqual({1:1}.items() | {2}, {(1,1), 2})
740 self.assertEqual({2} | {1:1}.items(), {(1,1), 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000741
Guido van Rossum1968ad32006-02-25 22:38:04 +0000742 def test_missing(self):
743 # Make sure dict doesn't have a __missing__ method
Florent Xiclunaa988e422010-03-02 16:06:24 +0000744 self.assertFalse(hasattr(dict, "__missing__"))
745 self.assertFalse(hasattr({}, "__missing__"))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000746 # Test several cases:
747 # (D) subclass defines __missing__ method returning a value
748 # (E) subclass defines __missing__ method raising RuntimeError
749 # (F) subclass sets __missing__ instance variable (no effect)
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200750 # (G) subclass doesn't define __missing__ at all
Guido van Rossum1968ad32006-02-25 22:38:04 +0000751 class D(dict):
752 def __missing__(self, key):
753 return 42
754 d = D({1: 2, 3: 4})
755 self.assertEqual(d[1], 2)
756 self.assertEqual(d[3], 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000757 self.assertNotIn(2, d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000758 self.assertNotIn(2, d.keys())
Guido van Rossum1968ad32006-02-25 22:38:04 +0000759 self.assertEqual(d[2], 42)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000760
Guido van Rossum1968ad32006-02-25 22:38:04 +0000761 class E(dict):
762 def __missing__(self, key):
763 raise RuntimeError(key)
764 e = E()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000765 with self.assertRaises(RuntimeError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000766 e[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000767 self.assertEqual(c.exception.args, (42,))
768
Guido van Rossum1968ad32006-02-25 22:38:04 +0000769 class F(dict):
770 def __init__(self):
771 # An instance variable __missing__ should have no effect
772 self.__missing__ = lambda key: None
773 f = F()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000774 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000775 f[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000776 self.assertEqual(c.exception.args, (42,))
777
Guido van Rossum1968ad32006-02-25 22:38:04 +0000778 class G(dict):
779 pass
780 g = G()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000781 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000782 g[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000783 self.assertEqual(c.exception.args, (42,))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000784
Thomas Wouters89f507f2006-12-13 04:49:30 +0000785 def test_tuple_keyerror(self):
786 # SF #1576657
787 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000788 with self.assertRaises(KeyError) as c:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000789 d[(1,)]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000790 self.assertEqual(c.exception.args, ((1,),))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000791
Guido van Rossumd8faa362007-04-27 19:54:29 +0000792 def test_bad_key(self):
Mark Dickinsona56c4672009-01-27 18:17:45 +0000793 # Dictionary lookups should fail if __eq__() raises an exception.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000794 class CustomException(Exception):
795 pass
796
797 class BadDictKey:
798 def __hash__(self):
799 return hash(self.__class__)
800
801 def __eq__(self, other):
802 if isinstance(other, self.__class__):
803 raise CustomException
804 return other
805
806 d = {}
807 x1 = BadDictKey()
808 x2 = BadDictKey()
809 d[x1] = 1
810 for stmt in ['d[x2] = 2',
811 'z = d[x2]',
812 'x2 in d',
813 'd.get(x2)',
814 'd.setdefault(x2, 42)',
815 'd.pop(x2)',
816 'd.update({x2: 2})']:
Florent Xiclunaa988e422010-03-02 16:06:24 +0000817 with self.assertRaises(CustomException):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000818 exec(stmt, locals())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000819
820 def test_resize1(self):
821 # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
822 # This version got an assert failure in debug build, infinite loop in
823 # release build. Unfortunately, provoking this kind of stuff requires
824 # a mix of inserts and deletes hitting exactly the right hash codes in
825 # exactly the right order, and I can't think of a randomized approach
826 # that would be *likely* to hit a failing case in reasonable time.
827
828 d = {}
829 for i in range(5):
830 d[i] = i
831 for i in range(5):
832 del d[i]
833 for i in range(5, 9): # i==8 was the problem
834 d[i] = i
835
836 def test_resize2(self):
837 # Another dict resizing bug (SF bug #1456209).
838 # This caused Segmentation faults or Illegal instructions.
839
840 class X(object):
841 def __hash__(self):
842 return 5
843 def __eq__(self, other):
844 if resizing:
845 d.clear()
846 return False
847 d = {}
848 resizing = False
849 d[X()] = 1
850 d[X()] = 2
851 d[X()] = 3
852 d[X()] = 4
853 d[X()] = 5
854 # now trigger a resize
855 resizing = True
856 d[9] = 6
857
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000858 def test_empty_presized_dict_in_freelist(self):
859 # Bug #3537: if an empty but presized dict with a size larger
860 # than 7 was in the freelist, it triggered an assertion failure
Florent Xiclunaa988e422010-03-02 16:06:24 +0000861 with self.assertRaises(ZeroDivisionError):
862 d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None,
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000863 'f': None, 'g': None, 'h': None}
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000864 d = {}
865
Antoine Pitrou7ddda782009-01-01 15:35:33 +0000866 def test_container_iterator(self):
867 # Bug #3680: tp_traverse was not implemented for dictiter and
868 # dictview objects.
869 class C(object):
870 pass
871 views = (dict.items, dict.values, dict.keys)
872 for v in views:
873 obj = C()
874 ref = weakref.ref(obj)
875 container = {obj: 1}
876 obj.v = v(container)
877 obj.x = iter(obj.v)
878 del obj, container
879 gc.collect()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000880 self.assertIs(ref(), None, "Cycle was not collected")
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000881
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000882 def _not_tracked(self, t):
883 # Nested containers can take several collections to untrack
884 gc.collect()
885 gc.collect()
886 self.assertFalse(gc.is_tracked(t), t)
887
888 def _tracked(self, t):
889 self.assertTrue(gc.is_tracked(t), t)
890 gc.collect()
891 gc.collect()
892 self.assertTrue(gc.is_tracked(t), t)
893
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000894 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000895 def test_track_literals(self):
896 # Test GC-optimization of dict literals
897 x, y, z, w = 1.5, "a", (1, None), []
898
899 self._not_tracked({})
900 self._not_tracked({x:(), y:x, z:1})
901 self._not_tracked({1: "a", "b": 2})
902 self._not_tracked({1: 2, (None, True, False, ()): int})
903 self._not_tracked({1: object()})
904
905 # Dicts with mutable elements are always tracked, even if those
906 # elements are not tracked right now.
907 self._tracked({1: []})
908 self._tracked({1: ([],)})
909 self._tracked({1: {}})
910 self._tracked({1: set()})
911
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000912 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000913 def test_track_dynamic(self):
914 # Test GC-optimization of dynamically-created dicts
915 class MyObject(object):
916 pass
917 x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject()
918
919 d = dict()
920 self._not_tracked(d)
921 d[1] = "a"
922 self._not_tracked(d)
923 d[y] = 2
924 self._not_tracked(d)
925 d[z] = 3
926 self._not_tracked(d)
927 self._not_tracked(d.copy())
928 d[4] = w
929 self._tracked(d)
930 self._tracked(d.copy())
931 d[4] = None
932 self._not_tracked(d)
933 self._not_tracked(d.copy())
934
935 # dd isn't tracked right now, but it may mutate and therefore d
936 # which contains it must be tracked.
937 d = dict()
938 dd = dict()
939 d[1] = dd
940 self._not_tracked(dd)
941 self._tracked(d)
942 dd[1] = d
943 self._tracked(dd)
944
945 d = dict.fromkeys([x, y, z])
946 self._not_tracked(d)
947 dd = dict()
948 dd.update(d)
949 self._not_tracked(dd)
950 d = dict.fromkeys([x, y, z, o])
951 self._tracked(d)
952 dd = dict()
953 dd.update(d)
954 self._tracked(dd)
955
956 d = dict(x=x, y=y, z=z)
957 self._not_tracked(d)
958 d = dict(x=x, y=y, z=z, w=w)
959 self._tracked(d)
960 d = dict()
961 d.update(x=x, y=y, z=z)
962 self._not_tracked(d)
963 d.update(w=w)
964 self._tracked(d)
965
966 d = dict([(x, y), (z, 1)])
967 self._not_tracked(d)
968 d = dict([(x, y), (z, w)])
969 self._tracked(d)
970 d = dict()
971 d.update([(x, y), (z, 1)])
972 self._not_tracked(d)
973 d.update([(x, y), (z, w)])
974 self._tracked(d)
975
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000976 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000977 def test_track_subtypes(self):
978 # Dict subtypes are always tracked
979 class MyDict(dict):
980 pass
981 self._tracked(MyDict())
982
Victor Stinner78601a32016-09-09 19:28:36 -0700983 def make_shared_key_dict(self, n):
984 class C:
985 pass
986
987 dicts = []
988 for i in range(n):
989 a = C()
990 a.x, a.y, a.z = 1, 2, 3
991 dicts.append(a.__dict__)
992
993 return dicts
994
995 @support.cpython_only
INADA Naoki93f26f72016-11-02 18:45:16 +0900996 def test_splittable_setdefault(self):
997 """split table must be combined when setdefault()
998 breaks insertion order"""
999 a, b = self.make_shared_key_dict(2)
1000
1001 a['a'] = 1
1002 size_a = sys.getsizeof(a)
1003 a['b'] = 2
1004 b.setdefault('b', 2)
1005 size_b = sys.getsizeof(b)
1006 b['a'] = 1
1007
1008 self.assertGreater(size_b, size_a)
1009 self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b'])
1010 self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a'])
1011
1012 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -07001013 def test_splittable_del(self):
1014 """split table must be combined when del d[k]"""
1015 a, b = self.make_shared_key_dict(2)
1016
1017 orig_size = sys.getsizeof(a)
1018
1019 del a['y'] # split table is combined
1020 with self.assertRaises(KeyError):
1021 del a['y']
1022
1023 self.assertGreater(sys.getsizeof(a), orig_size)
1024 self.assertEqual(list(a), ['x', 'z'])
1025 self.assertEqual(list(b), ['x', 'y', 'z'])
1026
1027 # Two dicts have different insertion order.
1028 a['y'] = 42
1029 self.assertEqual(list(a), ['x', 'z', 'y'])
1030 self.assertEqual(list(b), ['x', 'y', 'z'])
1031
1032 @support.cpython_only
1033 def test_splittable_pop(self):
1034 """split table must be combined when d.pop(k)"""
1035 a, b = self.make_shared_key_dict(2)
1036
1037 orig_size = sys.getsizeof(a)
1038
1039 a.pop('y') # split table is combined
1040 with self.assertRaises(KeyError):
1041 a.pop('y')
1042
1043 self.assertGreater(sys.getsizeof(a), orig_size)
1044 self.assertEqual(list(a), ['x', 'z'])
1045 self.assertEqual(list(b), ['x', 'y', 'z'])
1046
1047 # Two dicts have different insertion order.
1048 a['y'] = 42
1049 self.assertEqual(list(a), ['x', 'z', 'y'])
1050 self.assertEqual(list(b), ['x', 'y', 'z'])
1051
1052 @support.cpython_only
Victor Stinnerd0ad11f2016-09-13 16:56:38 +02001053 def test_splittable_pop_pending(self):
1054 """pop a pending key in a splitted table should not crash"""
1055 a, b = self.make_shared_key_dict(2)
1056
1057 a['a'] = 4
1058 with self.assertRaises(KeyError):
1059 b.pop('a')
1060
1061 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -07001062 def test_splittable_popitem(self):
1063 """split table must be combined when d.popitem()"""
1064 a, b = self.make_shared_key_dict(2)
1065
1066 orig_size = sys.getsizeof(a)
1067
1068 item = a.popitem() # split table is combined
1069 self.assertEqual(item, ('z', 3))
1070 with self.assertRaises(KeyError):
1071 del a['z']
1072
1073 self.assertGreater(sys.getsizeof(a), orig_size)
1074 self.assertEqual(list(a), ['x', 'y'])
1075 self.assertEqual(list(b), ['x', 'y', 'z'])
1076
Victor Stinner3d3f2642016-12-15 17:21:23 +01001077 @support.cpython_only
1078 def test_splittable_setattr_after_pop(self):
1079 """setattr() must not convert combined table into split table."""
1080 # Issue 28147
1081 import _testcapi
1082
1083 class C:
1084 pass
1085 a = C()
1086
1087 a.a = 1
1088 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1089
1090 # dict.pop() convert it to combined table
1091 a.__dict__.pop('a')
1092 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1093
1094 # But C should not convert a.__dict__ to split table again.
1095 a.a = 1
1096 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1097
1098 # Same for popitem()
1099 a = C()
1100 a.a = 2
1101 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1102 a.__dict__.popitem()
1103 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1104 a.a = 3
1105 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1106
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001107 def test_iterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001108 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1109 data = {1:"a", 2:"b", 3:"c"}
1110 it = iter(data)
1111 d = pickle.dumps(it, proto)
1112 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001113 self.assertEqual(list(it), list(data))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001114
Serhiy Storchakabad12572014-12-15 14:03:42 +02001115 it = pickle.loads(d)
1116 try:
1117 drop = next(it)
1118 except StopIteration:
1119 continue
1120 d = pickle.dumps(it, proto)
1121 it = pickle.loads(d)
1122 del data[drop]
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001123 self.assertEqual(list(it), list(data))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001124
1125 def test_itemiterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001126 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1127 data = {1:"a", 2:"b", 3:"c"}
1128 # dictviews aren't picklable, only their iterators
1129 itorg = iter(data.items())
1130 d = pickle.dumps(itorg, proto)
1131 it = pickle.loads(d)
Martin Pantera90a4a92016-05-30 04:04:50 +00001132 # note that the type of the unpickled iterator
Serhiy Storchakabad12572014-12-15 14:03:42 +02001133 # is not necessarily the same as the original. It is
1134 # merely an object supporting the iterator protocol, yielding
1135 # the same objects as the original one.
1136 # self.assertEqual(type(itorg), type(it))
1137 self.assertIsInstance(it, collections.abc.Iterator)
1138 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001139
Serhiy Storchakabad12572014-12-15 14:03:42 +02001140 it = pickle.loads(d)
1141 drop = next(it)
1142 d = pickle.dumps(it, proto)
1143 it = pickle.loads(d)
1144 del data[drop[0]]
1145 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001146
1147 def test_valuesiterator_pickling(self):
Sergey Fedoseev1f36bf62018-09-10 14:42:09 +05001148 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001149 data = {1:"a", 2:"b", 3:"c"}
1150 # data.values() isn't picklable, only its iterator
1151 it = iter(data.values())
1152 d = pickle.dumps(it, proto)
1153 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001154 self.assertEqual(list(it), list(data.values()))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001155
Serhiy Storchakabad12572014-12-15 14:03:42 +02001156 it = pickle.loads(d)
1157 drop = next(it)
1158 d = pickle.dumps(it, proto)
1159 it = pickle.loads(d)
1160 values = list(it) + [drop]
1161 self.assertEqual(sorted(values), sorted(list(data.values())))
Guido van Rossum1968ad32006-02-25 22:38:04 +00001162
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001163 def test_reverseiterator_pickling(self):
1164 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1165 data = {1:"a", 2:"b", 3:"c"}
1166 it = reversed(data)
1167 d = pickle.dumps(it, proto)
1168 it = pickle.loads(d)
1169 self.assertEqual(list(it), list(reversed(data)))
1170
1171 it = pickle.loads(d)
1172 try:
1173 drop = next(it)
1174 except StopIteration:
1175 continue
1176 d = pickle.dumps(it, proto)
1177 it = pickle.loads(d)
1178 del data[drop]
1179 self.assertEqual(list(it), list(reversed(data)))
1180
1181 def test_reverseitemiterator_pickling(self):
1182 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1183 data = {1:"a", 2:"b", 3:"c"}
1184 # dictviews aren't picklable, only their iterators
1185 itorg = reversed(data.items())
1186 d = pickle.dumps(itorg, proto)
1187 it = pickle.loads(d)
1188 # note that the type of the unpickled iterator
1189 # is not necessarily the same as the original. It is
1190 # merely an object supporting the iterator protocol, yielding
1191 # the same objects as the original one.
1192 # self.assertEqual(type(itorg), type(it))
1193 self.assertIsInstance(it, collections.abc.Iterator)
1194 self.assertEqual(dict(it), data)
1195
1196 it = pickle.loads(d)
1197 drop = next(it)
1198 d = pickle.dumps(it, proto)
1199 it = pickle.loads(d)
1200 del data[drop[0]]
1201 self.assertEqual(dict(it), data)
1202
1203 def test_reversevaluesiterator_pickling(self):
Zackery Spytzd1cbc6f2018-11-26 22:40:49 -07001204 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001205 data = {1:"a", 2:"b", 3:"c"}
1206 # data.values() isn't picklable, only its iterator
1207 it = reversed(data.values())
1208 d = pickle.dumps(it, proto)
1209 it = pickle.loads(d)
1210 self.assertEqual(list(it), list(reversed(data.values())))
1211
1212 it = pickle.loads(d)
1213 drop = next(it)
1214 d = pickle.dumps(it, proto)
1215 it = pickle.loads(d)
1216 values = list(it) + [drop]
1217 self.assertEqual(sorted(values), sorted(data.values()))
1218
Benjamin Petersondb780d02012-04-23 13:44:32 -04001219 def test_instance_dict_getattr_str_subclass(self):
1220 class Foo:
1221 def __init__(self, msg):
1222 self.msg = msg
1223 f = Foo('123')
1224 class _str(str):
1225 pass
1226 self.assertEqual(f.msg, getattr(f, _str('msg')))
1227 self.assertEqual(f.msg, f.__dict__[_str('msg')])
1228
Benjamin Peterson15ee8212012-04-24 14:44:18 -04001229 def test_object_set_item_single_instance_non_str_key(self):
1230 class Foo: pass
1231 f = Foo()
1232 f.__dict__[1] = 1
1233 f.a = 'a'
1234 self.assertEqual(f.__dict__, {1:1, 'a':'a'})
1235
Antoine Pitroud6967322014-10-18 00:35:00 +02001236 def check_reentrant_insertion(self, mutate):
1237 # This object will trigger mutation of the dict when replaced
1238 # by another value. Note this relies on refcounting: the test
1239 # won't achieve its purpose on fully-GCed Python implementations.
1240 class Mutating:
1241 def __del__(self):
1242 mutate(d)
1243
1244 d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
1245 for k in list(d):
1246 d[k] = k
1247
1248 def test_reentrant_insertion(self):
1249 # Reentrant insertion shouldn't crash (see issue #22653)
1250 def mutate(d):
1251 d['b'] = 5
1252 self.check_reentrant_insertion(mutate)
1253
1254 def mutate(d):
1255 d.update(self.__dict__)
1256 d.clear()
1257 self.check_reentrant_insertion(mutate)
1258
1259 def mutate(d):
1260 while d:
1261 d.popitem()
1262 self.check_reentrant_insertion(mutate)
1263
Benjamin Petersona82f77f2015-07-04 19:55:16 -05001264 def test_merge_and_mutate(self):
1265 class X:
1266 def __hash__(self):
1267 return 0
1268
1269 def __eq__(self, o):
1270 other.clear()
1271 return False
1272
1273 l = [(i,0) for i in range(1, 1337)]
1274 other = dict(l)
1275 other[X()] = 0
1276 d = {X(): 0, 1: 1}
1277 self.assertRaises(RuntimeError, d.update, other)
Antoine Pitroud6967322014-10-18 00:35:00 +02001278
Serhiy Storchakafbb1c5e2016-03-30 20:40:02 +03001279 def test_free_after_iterating(self):
1280 support.check_free_after_iterating(self, iter, dict)
1281 support.check_free_after_iterating(self, lambda d: iter(d.keys()), dict)
1282 support.check_free_after_iterating(self, lambda d: iter(d.values()), dict)
1283 support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
1284
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001285 def test_equal_operator_modifying_operand(self):
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001286 # test fix for seg fault reported in bpo-27945 part 3.
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001287 class X():
1288 def __del__(self):
1289 dict_b.clear()
1290
1291 def __eq__(self, other):
1292 dict_a.clear()
1293 return True
1294
1295 def __hash__(self):
1296 return 13
1297
1298 dict_a = {X(): 0}
1299 dict_b = {X(): X()}
1300 self.assertTrue(dict_a == dict_b)
1301
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001302 # test fix for seg fault reported in bpo-38588 part 1.
1303 class Y:
1304 def __eq__(self, other):
1305 dict_d.clear()
1306 return True
1307
1308 dict_c = {0: Y()}
1309 dict_d = {0: set()}
1310 self.assertTrue(dict_c == dict_d)
1311
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001312 def test_fromkeys_operator_modifying_dict_operand(self):
1313 # test fix for seg fault reported in issue 27945 part 4a.
1314 class X(int):
1315 def __hash__(self):
1316 return 13
1317
1318 def __eq__(self, other):
1319 if len(d) > 1:
1320 d.clear()
1321 return False
1322
1323 d = {} # this is required to exist so that d can be constructed!
1324 d = {X(1): 1, X(2): 2}
1325 try:
1326 dict.fromkeys(d) # shouldn't crash
1327 except RuntimeError: # implementation defined
1328 pass
1329
1330 def test_fromkeys_operator_modifying_set_operand(self):
1331 # test fix for seg fault reported in issue 27945 part 4b.
1332 class X(int):
1333 def __hash__(self):
1334 return 13
1335
1336 def __eq__(self, other):
1337 if len(d) > 1:
1338 d.clear()
1339 return False
1340
1341 d = {} # this is required to exist so that d can be constructed!
1342 d = {X(1), X(2)}
1343 try:
1344 dict.fromkeys(d) # shouldn't crash
1345 except RuntimeError: # implementation defined
1346 pass
1347
1348 def test_dictitems_contains_use_after_free(self):
1349 class X:
1350 def __eq__(self, other):
1351 d.clear()
1352 return NotImplemented
1353
1354 d = {0: set()}
1355 (0, X()) in d.items()
1356
Dong-hee Na785f5e62020-05-05 02:30:42 +09001357 def test_dict_contain_use_after_free(self):
1358 # bpo-40489
1359 class S(str):
1360 def __eq__(self, other):
1361 d.clear()
1362 return NotImplemented
1363
1364 def __hash__(self):
1365 return hash('test')
1366
1367 d = {S(): 'value'}
1368 self.assertFalse('test' in d)
1369
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001370 def test_init_use_after_free(self):
1371 class X:
1372 def __hash__(self):
1373 pair[:] = []
1374 return 13
1375
1376 pair = [X(), 123]
1377 dict([pair])
1378
1379 def test_oob_indexing_dictiter_iternextitem(self):
1380 class X(int):
1381 def __del__(self):
1382 d.clear()
1383
1384 d = {i: X(i) for i in range(8)}
1385
1386 def iter_and_mutate():
1387 for result in d.items():
1388 if result[0] == 2:
1389 d[2] = None # free d[2] --> X(2).__del__ was called
1390
1391 self.assertRaises(RuntimeError, iter_and_mutate)
1392
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001393 def test_reversed(self):
1394 d = {"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4}
1395 del d["foo"]
1396 r = reversed(d)
1397 self.assertEqual(list(r), list('dcba'))
1398 self.assertRaises(StopIteration, next, r)
1399
Dong-hee Na24dc2f82019-10-20 05:01:08 +09001400 def test_reverse_iterator_for_empty_dict(self):
1401 # bpo-38525: revered iterator should work properly
1402
1403 # empty dict is directly used for reference count test
1404 self.assertEqual(list(reversed({})), [])
1405 self.assertEqual(list(reversed({}.items())), [])
1406 self.assertEqual(list(reversed({}.values())), [])
1407 self.assertEqual(list(reversed({}.keys())), [])
1408
1409 # dict() and {} don't trigger the same code path
1410 self.assertEqual(list(reversed(dict())), [])
1411 self.assertEqual(list(reversed(dict().items())), [])
1412 self.assertEqual(list(reversed(dict().values())), [])
1413 self.assertEqual(list(reversed(dict().keys())), [])
1414
1415 def test_reverse_iterator_for_shared_shared_dicts(self):
1416 class A:
1417 def __init__(self, x, y):
1418 if x: self.x = x
1419 if y: self.y = y
1420
1421 self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x'])
1422 self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
1423 self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
1424
INADA Naoki2aaf98c2018-09-26 12:59:00 +09001425 def test_dict_copy_order(self):
1426 # bpo-34320
1427 od = collections.OrderedDict([('a', 1), ('b', 2)])
1428 od.move_to_end('a')
1429 expected = list(od.items())
1430
1431 copy = dict(od)
1432 self.assertEqual(list(copy.items()), expected)
1433
1434 # dict subclass doesn't override __iter__
1435 class CustomDict(dict):
1436 pass
1437
1438 pairs = [('a', 1), ('b', 2), ('c', 3)]
1439
1440 d = CustomDict(pairs)
1441 self.assertEqual(pairs, list(dict(d).items()))
1442
1443 class CustomReversedDict(dict):
1444 def keys(self):
1445 return reversed(list(dict.keys(self)))
1446
1447 __iter__ = keys
1448
1449 def items(self):
1450 return reversed(dict.items(self))
1451
1452 d = CustomReversedDict(pairs)
1453 self.assertEqual(pairs[::-1], list(dict(d).items()))
1454
Serhiy Storchakaf0b311b2016-11-06 13:18:24 +02001455
1456class CAPITest(unittest.TestCase):
1457
1458 # Test _PyDict_GetItem_KnownHash()
1459 @support.cpython_only
1460 def test_getitem_knownhash(self):
1461 from _testcapi import dict_getitem_knownhash
1462
1463 d = {'x': 1, 'y': 2, 'z': 3}
1464 self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1)
1465 self.assertEqual(dict_getitem_knownhash(d, 'y', hash('y')), 2)
1466 self.assertEqual(dict_getitem_knownhash(d, 'z', hash('z')), 3)
1467
1468 # not a dict
1469 self.assertRaises(SystemError, dict_getitem_knownhash, [], 1, hash(1))
1470 # key does not exist
1471 self.assertRaises(KeyError, dict_getitem_knownhash, {}, 1, hash(1))
1472
1473 class Exc(Exception): pass
1474 class BadEq:
1475 def __eq__(self, other):
1476 raise Exc
1477 def __hash__(self):
1478 return 7
1479
1480 k1, k2 = BadEq(), BadEq()
1481 d = {k1: 1}
1482 self.assertEqual(dict_getitem_knownhash(d, k1, hash(k1)), 1)
1483 self.assertRaises(Exc, dict_getitem_knownhash, d, k2, hash(k2))
1484
1485
Neal Norwitzc3e54b82006-03-24 07:38:37 +00001486from test import mapping_tests
Raymond Hettinger49c522b2004-09-30 15:07:29 +00001487
1488class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
1489 type2test = dict
1490
1491class Dict(dict):
1492 pass
1493
1494class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
1495 type2test = Dict
1496
Victor Stinner5ebe2c82016-01-23 13:52:05 +01001497
Walter Dörwald59b23e82004-09-30 13:46:00 +00001498if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001499 unittest.main()