blob: 5c08810f879b1fd9fce6029c228949a6aae31cd8 [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
Walter Dörwald59b23e82004-09-30 13:46:00 +0000108 def test_contains(self):
109 d = {}
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000110 self.assertNotIn('a', d)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000111 self.assertFalse('a' in d)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000112 self.assertTrue('a' not in d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000113 d = {'a': 1, 'b': 2}
Benjamin Peterson577473f2010-01-19 00:09:57 +0000114 self.assertIn('a', d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000115 self.assertIn('b', d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000116 self.assertNotIn('c', d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000117
118 self.assertRaises(TypeError, d.__contains__)
119
120 def test_len(self):
121 d = {}
122 self.assertEqual(len(d), 0)
123 d = {'a': 1, 'b': 2}
124 self.assertEqual(len(d), 2)
125
126 def test_getitem(self):
127 d = {'a': 1, 'b': 2}
128 self.assertEqual(d['a'], 1)
129 self.assertEqual(d['b'], 2)
130 d['c'] = 3
131 d['a'] = 4
132 self.assertEqual(d['c'], 3)
133 self.assertEqual(d['a'], 4)
134 del d['b']
135 self.assertEqual(d, {'a': 4, 'c': 3})
136
137 self.assertRaises(TypeError, d.__getitem__)
138
139 class BadEq(object):
140 def __eq__(self, other):
141 raise Exc()
Guido van Rossum38938152006-08-21 23:36:26 +0000142 def __hash__(self):
143 return 24
Walter Dörwald59b23e82004-09-30 13:46:00 +0000144
145 d = {}
146 d[BadEq()] = 42
147 self.assertRaises(KeyError, d.__getitem__, 23)
148
149 class Exc(Exception): pass
150
151 class BadHash(object):
152 fail = False
153 def __hash__(self):
154 if self.fail:
155 raise Exc()
156 else:
157 return 42
158
159 x = BadHash()
160 d[x] = 42
161 x.fail = True
162 self.assertRaises(Exc, d.__getitem__, x)
163
164 def test_clear(self):
165 d = {1:1, 2:2, 3:3}
166 d.clear()
167 self.assertEqual(d, {})
168
169 self.assertRaises(TypeError, d.clear, None)
170
171 def test_update(self):
172 d = {}
173 d.update({1:100})
174 d.update({2:20})
175 d.update({1:1, 2:2, 3:3})
176 self.assertEqual(d, {1:1, 2:2, 3:3})
177
178 d.update()
179 self.assertEqual(d, {1:1, 2:2, 3:3})
180
181 self.assertRaises((TypeError, AttributeError), d.update, None)
182
183 class SimpleUserDict:
184 def __init__(self):
185 self.d = {1:1, 2:2, 3:3}
186 def keys(self):
187 return self.d.keys()
188 def __getitem__(self, i):
189 return self.d[i]
190 d.clear()
191 d.update(SimpleUserDict())
192 self.assertEqual(d, {1:1, 2:2, 3:3})
193
194 class Exc(Exception): pass
195
196 d.clear()
197 class FailingUserDict:
198 def keys(self):
199 raise Exc
200 self.assertRaises(Exc, d.update, FailingUserDict())
201
202 class FailingUserDict:
203 def keys(self):
204 class BogonIter:
205 def __init__(self):
206 self.i = 1
207 def __iter__(self):
208 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000209 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000210 if self.i:
211 self.i = 0
212 return 'a'
213 raise Exc
214 return BogonIter()
215 def __getitem__(self, key):
216 return key
217 self.assertRaises(Exc, d.update, FailingUserDict())
218
219 class FailingUserDict:
220 def keys(self):
221 class BogonIter:
222 def __init__(self):
223 self.i = ord('a')
224 def __iter__(self):
225 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000226 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000227 if self.i <= ord('z'):
228 rtn = chr(self.i)
229 self.i += 1
230 return rtn
231 raise StopIteration
232 return BogonIter()
233 def __getitem__(self, key):
234 raise Exc
235 self.assertRaises(Exc, d.update, FailingUserDict())
236
237 class badseq(object):
238 def __iter__(self):
239 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000240 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000241 raise Exc()
242
243 self.assertRaises(Exc, {}.update, badseq())
244
245 self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
246
247 def test_fromkeys(self):
248 self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
249 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000250 self.assertIsNot(d.fromkeys('abc'), d)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000251 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
252 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
253 self.assertEqual(d.fromkeys([]), {})
254 def g():
255 yield 1
256 self.assertEqual(d.fromkeys(g()), {1:None})
257 self.assertRaises(TypeError, {}.fromkeys, 3)
258 class dictlike(dict): pass
259 self.assertEqual(dictlike.fromkeys('a'), {'a':None})
260 self.assertEqual(dictlike().fromkeys('a'), {'a':None})
Florent Xiclunaa988e422010-03-02 16:06:24 +0000261 self.assertIsInstance(dictlike.fromkeys('a'), dictlike)
262 self.assertIsInstance(dictlike().fromkeys('a'), dictlike)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000263 class mydict(dict):
264 def __new__(cls):
Raymond Hettingerf80680d2008-02-06 00:07:11 +0000265 return collections.UserDict()
Walter Dörwald59b23e82004-09-30 13:46:00 +0000266 ud = mydict.fromkeys('ab')
267 self.assertEqual(ud, {'a':None, 'b':None})
Ezio Melottie9615932010-01-24 19:26:24 +0000268 self.assertIsInstance(ud, collections.UserDict)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000269 self.assertRaises(TypeError, dict.fromkeys)
270
271 class Exc(Exception): pass
272
273 class baddict1(dict):
274 def __init__(self):
275 raise Exc()
276
277 self.assertRaises(Exc, baddict1.fromkeys, [1])
278
279 class BadSeq(object):
280 def __iter__(self):
281 return self
Georg Brandla18af4e2007-04-21 15:47:16 +0000282 def __next__(self):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000283 raise Exc()
284
285 self.assertRaises(Exc, dict.fromkeys, BadSeq())
286
287 class baddict2(dict):
288 def __setitem__(self, key, value):
289 raise Exc()
290
291 self.assertRaises(Exc, baddict2.fromkeys, [1])
292
Guido van Rossum58da9312007-11-10 23:39:45 +0000293 # test fast path for dictionary inputs
294 d = dict(zip(range(6), range(6)))
295 self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
296
Benjamin Petersond1f2cb32012-10-31 14:05:55 -0400297 class baddict3(dict):
298 def __new__(cls):
299 return d
300 d = {i : i for i in range(10)}
301 res = d.copy()
302 res.update(a=None, b=None, c=None)
303 self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res)
304
Walter Dörwald59b23e82004-09-30 13:46:00 +0000305 def test_copy(self):
Yury Selivanovb0a7a032018-01-22 11:54:41 -0500306 d = {1: 1, 2: 2, 3: 3}
307 self.assertIsNot(d.copy(), d)
308 self.assertEqual(d.copy(), d)
309 self.assertEqual(d.copy(), {1: 1, 2: 2, 3: 3})
310
311 copy = d.copy()
312 d[4] = 4
313 self.assertNotEqual(copy, d)
314
Walter Dörwald59b23e82004-09-30 13:46:00 +0000315 self.assertEqual({}.copy(), {})
316 self.assertRaises(TypeError, d.copy, None)
317
Yury Selivanovb0a7a032018-01-22 11:54:41 -0500318 def test_copy_fuzz(self):
319 for dict_size in [10, 100, 1000, 10000, 100000]:
320 dict_size = random.randrange(
321 dict_size // 2, dict_size + dict_size // 2)
322 with self.subTest(dict_size=dict_size):
323 d = {}
324 for i in range(dict_size):
325 d[i] = i
326
327 d2 = d.copy()
328 self.assertIsNot(d2, d)
329 self.assertEqual(d, d2)
330 d2['key'] = 'value'
331 self.assertNotEqual(d, d2)
332 self.assertEqual(len(d2), len(d) + 1)
333
334 def test_copy_maintains_tracking(self):
335 class A:
336 pass
337
338 key = A()
339
340 for d in ({}, {'a': 1}, {key: 'val'}):
341 d2 = d.copy()
342 self.assertEqual(gc.is_tracked(d), gc.is_tracked(d2))
343
344 def test_copy_noncompact(self):
345 # Dicts don't compact themselves on del/pop operations.
346 # Copy will use a slow merging strategy that produces
347 # a compacted copy when roughly 33% of dict is a non-used
348 # keys-space (to optimize memory footprint).
349 # In this test we want to hit the slow/compacting
350 # branch of dict.copy() and make sure it works OK.
351 d = {k: k for k in range(1000)}
352 for k in range(950):
353 del d[k]
354 d2 = d.copy()
355 self.assertEqual(d2, d)
356
Walter Dörwald59b23e82004-09-30 13:46:00 +0000357 def test_get(self):
358 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000359 self.assertIs(d.get('c'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000360 self.assertEqual(d.get('c', 3), 3)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000361 d = {'a': 1, 'b': 2}
362 self.assertIs(d.get('c'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000363 self.assertEqual(d.get('c', 3), 3)
364 self.assertEqual(d.get('a'), 1)
365 self.assertEqual(d.get('a', 3), 1)
366 self.assertRaises(TypeError, d.get)
367 self.assertRaises(TypeError, d.get, None, None, None)
368
369 def test_setdefault(self):
370 # dict.setdefault()
371 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000372 self.assertIs(d.setdefault('key0'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000373 d.setdefault('key0', [])
Florent Xiclunaa988e422010-03-02 16:06:24 +0000374 self.assertIs(d.setdefault('key0'), None)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000375 d.setdefault('key', []).append(3)
376 self.assertEqual(d['key'][0], 3)
377 d.setdefault('key', []).append(4)
378 self.assertEqual(len(d['key']), 2)
379 self.assertRaises(TypeError, d.setdefault)
380
381 class Exc(Exception): pass
382
383 class BadHash(object):
384 fail = False
385 def __hash__(self):
386 if self.fail:
387 raise Exc()
388 else:
389 return 42
390
391 x = BadHash()
392 d[x] = 42
393 x.fail = True
394 self.assertRaises(Exc, d.setdefault, x, [])
395
Antoine Pitroue965d972012-02-27 00:45:12 +0100396 def test_setdefault_atomic(self):
397 # Issue #13521: setdefault() calls __hash__ and __eq__ only once.
398 class Hashed(object):
399 def __init__(self):
400 self.hash_count = 0
401 self.eq_count = 0
402 def __hash__(self):
403 self.hash_count += 1
404 return 42
405 def __eq__(self, other):
406 self.eq_count += 1
407 return id(self) == id(other)
408 hashed1 = Hashed()
409 y = {hashed1: 5}
410 hashed2 = Hashed()
411 y.setdefault(hashed2, [])
412 self.assertEqual(hashed1.hash_count, 1)
413 self.assertEqual(hashed2.hash_count, 1)
414 self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
415
Benjamin Peterson7d95e402012-04-23 11:24:50 -0400416 def test_setitem_atomic_at_resize(self):
417 class Hashed(object):
418 def __init__(self):
419 self.hash_count = 0
420 self.eq_count = 0
421 def __hash__(self):
422 self.hash_count += 1
423 return 42
424 def __eq__(self, other):
425 self.eq_count += 1
426 return id(self) == id(other)
427 hashed1 = Hashed()
428 # 5 items
429 y = {hashed1: 5, 0: 0, 1: 1, 2: 2, 3: 3}
430 hashed2 = Hashed()
431 # 6th item forces a resize
432 y[hashed2] = []
433 self.assertEqual(hashed1.hash_count, 1)
434 self.assertEqual(hashed2.hash_count, 1)
435 self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
436
Walter Dörwald59b23e82004-09-30 13:46:00 +0000437 def test_popitem(self):
438 # dict.popitem()
439 for copymode in -1, +1:
440 # -1: b has same structure as a
441 # +1: b is a.copy()
442 for log2size in range(12):
443 size = 2**log2size
444 a = {}
445 b = {}
446 for i in range(size):
447 a[repr(i)] = i
448 if copymode < 0:
449 b[repr(i)] = i
450 if copymode > 0:
451 b = a.copy()
452 for i in range(size):
453 ka, va = ta = a.popitem()
454 self.assertEqual(va, int(ka))
455 kb, vb = tb = b.popitem()
456 self.assertEqual(vb, int(kb))
Florent Xiclunaa988e422010-03-02 16:06:24 +0000457 self.assertFalse(copymode < 0 and ta != tb)
458 self.assertFalse(a)
459 self.assertFalse(b)
Walter Dörwald59b23e82004-09-30 13:46:00 +0000460
461 d = {}
462 self.assertRaises(KeyError, d.popitem)
463
464 def test_pop(self):
465 # Tests for pop with specified key
466 d = {}
467 k, v = 'abc', 'def'
468 d[k] = v
469 self.assertRaises(KeyError, d.pop, 'ghi')
470
471 self.assertEqual(d.pop(k), v)
472 self.assertEqual(len(d), 0)
473
474 self.assertRaises(KeyError, d.pop, k)
475
Walter Dörwald59b23e82004-09-30 13:46:00 +0000476 self.assertEqual(d.pop(k, v), v)
477 d[k] = v
478 self.assertEqual(d.pop(k, 1), v)
479
480 self.assertRaises(TypeError, d.pop)
481
482 class Exc(Exception): pass
483
484 class BadHash(object):
485 fail = False
486 def __hash__(self):
487 if self.fail:
488 raise Exc()
489 else:
490 return 42
491
492 x = BadHash()
493 d[x] = 42
494 x.fail = True
495 self.assertRaises(Exc, d.pop, x)
496
Victor Stinner198b2912012-03-06 01:03:13 +0100497 def test_mutating_iteration(self):
Florent Xiclunaa988e422010-03-02 16:06:24 +0000498 # changing dict size during iteration
Walter Dörwald59b23e82004-09-30 13:46:00 +0000499 d = {}
500 d[1] = 1
Florent Xiclunaa988e422010-03-02 16:06:24 +0000501 with self.assertRaises(RuntimeError):
Walter Dörwald59b23e82004-09-30 13:46:00 +0000502 for i in d:
503 d[i+1] = 1
Walter Dörwald59b23e82004-09-30 13:46:00 +0000504
Thomas Perl796cc6e2019-03-28 07:03:25 +0100505 def test_mutating_iteration_delete(self):
506 # change dict content during iteration
507 d = {}
508 d[0] = 0
509 with self.assertRaises(RuntimeError):
510 for i in d:
511 del d[0]
Thomas Perlb8311cf2019-04-02 11:30:10 +0200512 d[0] = 0
513
514 def test_mutating_iteration_delete_over_values(self):
515 # change dict content during iteration
516 d = {}
517 d[0] = 0
518 with self.assertRaises(RuntimeError):
519 for i in d.values():
520 del d[0]
521 d[0] = 0
522
523 def test_mutating_iteration_delete_over_items(self):
524 # change dict content during iteration
525 d = {}
526 d[0] = 0
527 with self.assertRaises(RuntimeError):
528 for i in d.items():
529 del d[0]
530 d[0] = 0
Thomas Perl796cc6e2019-03-28 07:03:25 +0100531
Victor Stinner198b2912012-03-06 01:03:13 +0100532 def test_mutating_lookup(self):
Antoine Pitrou9a234902012-05-13 20:48:01 +0200533 # changing dict during a lookup (issue #14417)
Victor Stinner198b2912012-03-06 01:03:13 +0100534 class NastyKey:
535 mutate_dict = None
536
Victor Stinner28393822012-03-09 22:58:51 +0100537 def __init__(self, value):
538 self.value = value
539
Victor Stinner198b2912012-03-06 01:03:13 +0100540 def __hash__(self):
541 # hash collision!
542 return 1
543
544 def __eq__(self, other):
Victor Stinner28393822012-03-09 22:58:51 +0100545 if NastyKey.mutate_dict:
546 mydict, key = NastyKey.mutate_dict
547 NastyKey.mutate_dict = None
548 del mydict[key]
549 return self.value == other.value
Victor Stinner198b2912012-03-06 01:03:13 +0100550
Victor Stinner28393822012-03-09 22:58:51 +0100551 key1 = NastyKey(1)
552 key2 = NastyKey(2)
553 d = {key1: 1}
554 NastyKey.mutate_dict = (d, key1)
Antoine Pitrou9a234902012-05-13 20:48:01 +0200555 d[key2] = 2
556 self.assertEqual(d, {key2: 2})
Victor Stinner198b2912012-03-06 01:03:13 +0100557
Walter Dörwald59b23e82004-09-30 13:46:00 +0000558 def test_repr(self):
559 d = {}
560 self.assertEqual(repr(d), '{}')
561 d[1] = 2
562 self.assertEqual(repr(d), '{1: 2}')
563 d = {}
564 d[1] = d
565 self.assertEqual(repr(d), '{1: {...}}')
566
567 class Exc(Exception): pass
568
569 class BadRepr(object):
570 def __repr__(self):
571 raise Exc()
572
573 d = {1: BadRepr()}
574 self.assertRaises(Exc, repr, d)
575
Serhiy Storchaka1fb72d22017-12-03 22:12:11 +0200576 def test_repr_deep(self):
577 d = {}
578 for i in range(sys.getrecursionlimit() + 100):
579 d = {1: d}
580 self.assertRaises(RecursionError, repr, d)
581
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000582 def test_eq(self):
583 self.assertEqual({}, {})
Guido van Rossume2a383d2007-01-15 16:59:06 +0000584 self.assertEqual({1: 2}, {1: 2})
Walter Dörwald59b23e82004-09-30 13:46:00 +0000585
586 class Exc(Exception): pass
587
588 class BadCmp(object):
589 def __eq__(self, other):
590 raise Exc()
Guido van Rossum38938152006-08-21 23:36:26 +0000591 def __hash__(self):
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000592 return 1
Walter Dörwald59b23e82004-09-30 13:46:00 +0000593
594 d1 = {BadCmp(): 1}
595 d2 = {1: 1}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000596
597 with self.assertRaises(Exc):
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000598 d1 == d2
Walter Dörwald59b23e82004-09-30 13:46:00 +0000599
Guido van Rossumaac530c2007-08-24 22:33:45 +0000600 def test_keys_contained(self):
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000601 self.helper_keys_contained(lambda x: x.keys())
602 self.helper_keys_contained(lambda x: x.items())
603
604 def helper_keys_contained(self, fn):
Guido van Rossumaac530c2007-08-24 22:33:45 +0000605 # Test rich comparisons against dict key views, which should behave the
606 # same as sets.
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000607 empty = fn(dict())
608 empty2 = fn(dict())
609 smaller = fn({1:1, 2:2})
610 larger = fn({1:1, 2:2, 3:3})
611 larger2 = fn({1:1, 2:2, 3:3})
612 larger3 = fn({4:1, 2:2, 3:3})
Guido van Rossumaac530c2007-08-24 22:33:45 +0000613
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000614 self.assertTrue(smaller < larger)
615 self.assertTrue(smaller <= larger)
616 self.assertTrue(larger > smaller)
617 self.assertTrue(larger >= smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000618
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000619 self.assertFalse(smaller >= larger)
620 self.assertFalse(smaller > larger)
621 self.assertFalse(larger <= smaller)
622 self.assertFalse(larger < smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000623
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000624 self.assertFalse(smaller < larger3)
625 self.assertFalse(smaller <= larger3)
626 self.assertFalse(larger3 > smaller)
627 self.assertFalse(larger3 >= smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000628
629 # Inequality strictness
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000630 self.assertTrue(larger2 >= larger)
631 self.assertTrue(larger2 <= larger)
632 self.assertFalse(larger2 > larger)
633 self.assertFalse(larger2 < larger)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000634
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000635 self.assertTrue(larger == larger2)
636 self.assertTrue(smaller != larger)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000637
638 # There is an optimization on the zero-element case.
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000639 self.assertTrue(empty == empty2)
640 self.assertFalse(empty != empty2)
641 self.assertFalse(empty == smaller)
642 self.assertTrue(empty != smaller)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000643
644 # With the same size, an elementwise compare happens
Guido van Rossumcf2ce362007-08-24 23:49:54 +0000645 self.assertTrue(larger != larger3)
646 self.assertFalse(larger == larger3)
Guido van Rossumaac530c2007-08-24 22:33:45 +0000647
648 def test_errors_in_view_containment_check(self):
649 class C:
650 def __eq__(self, other):
651 raise RuntimeError
Florent Xiclunaa988e422010-03-02 16:06:24 +0000652
Guido van Rossumaac530c2007-08-24 22:33:45 +0000653 d1 = {1: C()}
654 d2 = {1: C()}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000655 with self.assertRaises(RuntimeError):
656 d1.items() == d2.items()
657 with self.assertRaises(RuntimeError):
658 d1.items() != d2.items()
659 with self.assertRaises(RuntimeError):
660 d1.items() <= d2.items()
661 with self.assertRaises(RuntimeError):
662 d1.items() >= d2.items()
663
Guido van Rossumaac530c2007-08-24 22:33:45 +0000664 d3 = {1: C(), 2: C()}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000665 with self.assertRaises(RuntimeError):
666 d2.items() < d3.items()
667 with self.assertRaises(RuntimeError):
668 d3.items() > d2.items()
Guido van Rossumaac530c2007-08-24 22:33:45 +0000669
Guido van Rossumbe534712007-08-24 23:43:52 +0000670 def test_dictview_set_operations_on_keys(self):
Guido van Rossum523259b2007-08-24 23:41:22 +0000671 k1 = {1:1, 2:2}.keys()
672 k2 = {1:1, 2:2, 3:3}.keys()
673 k3 = {4:4}.keys()
674
Florent Xiclunaa988e422010-03-02 16:06:24 +0000675 self.assertEqual(k1 - k2, set())
676 self.assertEqual(k1 - k3, {1,2})
677 self.assertEqual(k2 - k1, {3})
678 self.assertEqual(k3 - k1, {4})
679 self.assertEqual(k1 & k2, {1,2})
680 self.assertEqual(k1 & k3, set())
681 self.assertEqual(k1 | k2, {1,2,3})
682 self.assertEqual(k1 ^ k2, {3})
683 self.assertEqual(k1 ^ k3, {1,2,4})
Guido van Rossum523259b2007-08-24 23:41:22 +0000684
Guido van Rossumbe534712007-08-24 23:43:52 +0000685 def test_dictview_set_operations_on_items(self):
686 k1 = {1:1, 2:2}.items()
687 k2 = {1:1, 2:2, 3:3}.items()
688 k3 = {4:4}.items()
689
Florent Xiclunaa988e422010-03-02 16:06:24 +0000690 self.assertEqual(k1 - k2, set())
691 self.assertEqual(k1 - k3, {(1,1), (2,2)})
692 self.assertEqual(k2 - k1, {(3,3)})
693 self.assertEqual(k3 - k1, {(4,4)})
694 self.assertEqual(k1 & k2, {(1,1), (2,2)})
695 self.assertEqual(k1 & k3, set())
696 self.assertEqual(k1 | k2, {(1,1), (2,2), (3,3)})
697 self.assertEqual(k1 ^ k2, {(3,3)})
698 self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)})
Guido van Rossum523259b2007-08-24 23:41:22 +0000699
Dennis Sweeney07d81122020-06-10 01:56:56 -0400700 def test_items_symmetric_difference(self):
701 rr = random.randrange
702 for _ in range(100):
703 left = {x:rr(3) for x in range(20) if rr(2)}
704 right = {x:rr(3) for x in range(20) if rr(2)}
705 with self.subTest(left=left, right=right):
706 expected = set(left.items()) ^ set(right.items())
707 actual = left.items() ^ right.items()
708 self.assertEqual(actual, expected)
709
Guido van Rossum1d719962007-08-24 23:47:30 +0000710 def test_dictview_mixed_set_operations(self):
711 # Just a few for .keys()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000712 self.assertTrue({1:1}.keys() == {1})
713 self.assertTrue({1} == {1:1}.keys())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000714 self.assertEqual({1:1}.keys() | {2}, {1, 2})
715 self.assertEqual({2} | {1:1}.keys(), {1, 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000716 # And a few for .items()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000717 self.assertTrue({1:1}.items() == {(1,1)})
718 self.assertTrue({(1,1)} == {1:1}.items())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000719 self.assertEqual({1:1}.items() | {2}, {(1,1), 2})
720 self.assertEqual({2} | {1:1}.items(), {(1,1), 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000721
Guido van Rossum1968ad32006-02-25 22:38:04 +0000722 def test_missing(self):
723 # Make sure dict doesn't have a __missing__ method
Florent Xiclunaa988e422010-03-02 16:06:24 +0000724 self.assertFalse(hasattr(dict, "__missing__"))
725 self.assertFalse(hasattr({}, "__missing__"))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000726 # Test several cases:
727 # (D) subclass defines __missing__ method returning a value
728 # (E) subclass defines __missing__ method raising RuntimeError
729 # (F) subclass sets __missing__ instance variable (no effect)
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200730 # (G) subclass doesn't define __missing__ at all
Guido van Rossum1968ad32006-02-25 22:38:04 +0000731 class D(dict):
732 def __missing__(self, key):
733 return 42
734 d = D({1: 2, 3: 4})
735 self.assertEqual(d[1], 2)
736 self.assertEqual(d[3], 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000737 self.assertNotIn(2, d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000738 self.assertNotIn(2, d.keys())
Guido van Rossum1968ad32006-02-25 22:38:04 +0000739 self.assertEqual(d[2], 42)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000740
Guido van Rossum1968ad32006-02-25 22:38:04 +0000741 class E(dict):
742 def __missing__(self, key):
743 raise RuntimeError(key)
744 e = E()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000745 with self.assertRaises(RuntimeError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000746 e[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000747 self.assertEqual(c.exception.args, (42,))
748
Guido van Rossum1968ad32006-02-25 22:38:04 +0000749 class F(dict):
750 def __init__(self):
751 # An instance variable __missing__ should have no effect
752 self.__missing__ = lambda key: None
753 f = F()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000754 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000755 f[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000756 self.assertEqual(c.exception.args, (42,))
757
Guido van Rossum1968ad32006-02-25 22:38:04 +0000758 class G(dict):
759 pass
760 g = G()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000761 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000762 g[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000763 self.assertEqual(c.exception.args, (42,))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000764
Thomas Wouters89f507f2006-12-13 04:49:30 +0000765 def test_tuple_keyerror(self):
766 # SF #1576657
767 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000768 with self.assertRaises(KeyError) as c:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000769 d[(1,)]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000770 self.assertEqual(c.exception.args, ((1,),))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000771
Guido van Rossumd8faa362007-04-27 19:54:29 +0000772 def test_bad_key(self):
Mark Dickinsona56c4672009-01-27 18:17:45 +0000773 # Dictionary lookups should fail if __eq__() raises an exception.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000774 class CustomException(Exception):
775 pass
776
777 class BadDictKey:
778 def __hash__(self):
779 return hash(self.__class__)
780
781 def __eq__(self, other):
782 if isinstance(other, self.__class__):
783 raise CustomException
784 return other
785
786 d = {}
787 x1 = BadDictKey()
788 x2 = BadDictKey()
789 d[x1] = 1
790 for stmt in ['d[x2] = 2',
791 'z = d[x2]',
792 'x2 in d',
793 'd.get(x2)',
794 'd.setdefault(x2, 42)',
795 'd.pop(x2)',
796 'd.update({x2: 2})']:
Florent Xiclunaa988e422010-03-02 16:06:24 +0000797 with self.assertRaises(CustomException):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000798 exec(stmt, locals())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000799
800 def test_resize1(self):
801 # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
802 # This version got an assert failure in debug build, infinite loop in
803 # release build. Unfortunately, provoking this kind of stuff requires
804 # a mix of inserts and deletes hitting exactly the right hash codes in
805 # exactly the right order, and I can't think of a randomized approach
806 # that would be *likely* to hit a failing case in reasonable time.
807
808 d = {}
809 for i in range(5):
810 d[i] = i
811 for i in range(5):
812 del d[i]
813 for i in range(5, 9): # i==8 was the problem
814 d[i] = i
815
816 def test_resize2(self):
817 # Another dict resizing bug (SF bug #1456209).
818 # This caused Segmentation faults or Illegal instructions.
819
820 class X(object):
821 def __hash__(self):
822 return 5
823 def __eq__(self, other):
824 if resizing:
825 d.clear()
826 return False
827 d = {}
828 resizing = False
829 d[X()] = 1
830 d[X()] = 2
831 d[X()] = 3
832 d[X()] = 4
833 d[X()] = 5
834 # now trigger a resize
835 resizing = True
836 d[9] = 6
837
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000838 def test_empty_presized_dict_in_freelist(self):
839 # Bug #3537: if an empty but presized dict with a size larger
840 # than 7 was in the freelist, it triggered an assertion failure
Florent Xiclunaa988e422010-03-02 16:06:24 +0000841 with self.assertRaises(ZeroDivisionError):
842 d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None,
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000843 'f': None, 'g': None, 'h': None}
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000844 d = {}
845
Antoine Pitrou7ddda782009-01-01 15:35:33 +0000846 def test_container_iterator(self):
847 # Bug #3680: tp_traverse was not implemented for dictiter and
848 # dictview objects.
849 class C(object):
850 pass
851 views = (dict.items, dict.values, dict.keys)
852 for v in views:
853 obj = C()
854 ref = weakref.ref(obj)
855 container = {obj: 1}
856 obj.v = v(container)
857 obj.x = iter(obj.v)
858 del obj, container
859 gc.collect()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000860 self.assertIs(ref(), None, "Cycle was not collected")
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000861
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000862 def _not_tracked(self, t):
863 # Nested containers can take several collections to untrack
864 gc.collect()
865 gc.collect()
866 self.assertFalse(gc.is_tracked(t), t)
867
868 def _tracked(self, t):
869 self.assertTrue(gc.is_tracked(t), t)
870 gc.collect()
871 gc.collect()
872 self.assertTrue(gc.is_tracked(t), t)
873
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000874 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000875 def test_track_literals(self):
876 # Test GC-optimization of dict literals
877 x, y, z, w = 1.5, "a", (1, None), []
878
879 self._not_tracked({})
880 self._not_tracked({x:(), y:x, z:1})
881 self._not_tracked({1: "a", "b": 2})
882 self._not_tracked({1: 2, (None, True, False, ()): int})
883 self._not_tracked({1: object()})
884
885 # Dicts with mutable elements are always tracked, even if those
886 # elements are not tracked right now.
887 self._tracked({1: []})
888 self._tracked({1: ([],)})
889 self._tracked({1: {}})
890 self._tracked({1: set()})
891
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000892 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000893 def test_track_dynamic(self):
894 # Test GC-optimization of dynamically-created dicts
895 class MyObject(object):
896 pass
897 x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject()
898
899 d = dict()
900 self._not_tracked(d)
901 d[1] = "a"
902 self._not_tracked(d)
903 d[y] = 2
904 self._not_tracked(d)
905 d[z] = 3
906 self._not_tracked(d)
907 self._not_tracked(d.copy())
908 d[4] = w
909 self._tracked(d)
910 self._tracked(d.copy())
911 d[4] = None
912 self._not_tracked(d)
913 self._not_tracked(d.copy())
914
915 # dd isn't tracked right now, but it may mutate and therefore d
916 # which contains it must be tracked.
917 d = dict()
918 dd = dict()
919 d[1] = dd
920 self._not_tracked(dd)
921 self._tracked(d)
922 dd[1] = d
923 self._tracked(dd)
924
925 d = dict.fromkeys([x, y, z])
926 self._not_tracked(d)
927 dd = dict()
928 dd.update(d)
929 self._not_tracked(dd)
930 d = dict.fromkeys([x, y, z, o])
931 self._tracked(d)
932 dd = dict()
933 dd.update(d)
934 self._tracked(dd)
935
936 d = dict(x=x, y=y, z=z)
937 self._not_tracked(d)
938 d = dict(x=x, y=y, z=z, w=w)
939 self._tracked(d)
940 d = dict()
941 d.update(x=x, y=y, z=z)
942 self._not_tracked(d)
943 d.update(w=w)
944 self._tracked(d)
945
946 d = dict([(x, y), (z, 1)])
947 self._not_tracked(d)
948 d = dict([(x, y), (z, w)])
949 self._tracked(d)
950 d = dict()
951 d.update([(x, y), (z, 1)])
952 self._not_tracked(d)
953 d.update([(x, y), (z, w)])
954 self._tracked(d)
955
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000956 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000957 def test_track_subtypes(self):
958 # Dict subtypes are always tracked
959 class MyDict(dict):
960 pass
961 self._tracked(MyDict())
962
Victor Stinner78601a32016-09-09 19:28:36 -0700963 def make_shared_key_dict(self, n):
964 class C:
965 pass
966
967 dicts = []
968 for i in range(n):
969 a = C()
970 a.x, a.y, a.z = 1, 2, 3
971 dicts.append(a.__dict__)
972
973 return dicts
974
975 @support.cpython_only
INADA Naoki93f26f72016-11-02 18:45:16 +0900976 def test_splittable_setdefault(self):
977 """split table must be combined when setdefault()
978 breaks insertion order"""
979 a, b = self.make_shared_key_dict(2)
980
981 a['a'] = 1
982 size_a = sys.getsizeof(a)
983 a['b'] = 2
984 b.setdefault('b', 2)
985 size_b = sys.getsizeof(b)
986 b['a'] = 1
987
988 self.assertGreater(size_b, size_a)
989 self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b'])
990 self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a'])
991
992 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -0700993 def test_splittable_del(self):
994 """split table must be combined when del d[k]"""
995 a, b = self.make_shared_key_dict(2)
996
997 orig_size = sys.getsizeof(a)
998
999 del a['y'] # split table is combined
1000 with self.assertRaises(KeyError):
1001 del a['y']
1002
1003 self.assertGreater(sys.getsizeof(a), orig_size)
1004 self.assertEqual(list(a), ['x', 'z'])
1005 self.assertEqual(list(b), ['x', 'y', 'z'])
1006
1007 # Two dicts have different insertion order.
1008 a['y'] = 42
1009 self.assertEqual(list(a), ['x', 'z', 'y'])
1010 self.assertEqual(list(b), ['x', 'y', 'z'])
1011
1012 @support.cpython_only
1013 def test_splittable_pop(self):
1014 """split table must be combined when d.pop(k)"""
1015 a, b = self.make_shared_key_dict(2)
1016
1017 orig_size = sys.getsizeof(a)
1018
1019 a.pop('y') # split table is combined
1020 with self.assertRaises(KeyError):
1021 a.pop('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
Victor Stinnerd0ad11f2016-09-13 16:56:38 +02001033 def test_splittable_pop_pending(self):
1034 """pop a pending key in a splitted table should not crash"""
1035 a, b = self.make_shared_key_dict(2)
1036
1037 a['a'] = 4
1038 with self.assertRaises(KeyError):
1039 b.pop('a')
1040
1041 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -07001042 def test_splittable_popitem(self):
1043 """split table must be combined when d.popitem()"""
1044 a, b = self.make_shared_key_dict(2)
1045
1046 orig_size = sys.getsizeof(a)
1047
1048 item = a.popitem() # split table is combined
1049 self.assertEqual(item, ('z', 3))
1050 with self.assertRaises(KeyError):
1051 del a['z']
1052
1053 self.assertGreater(sys.getsizeof(a), orig_size)
1054 self.assertEqual(list(a), ['x', 'y'])
1055 self.assertEqual(list(b), ['x', 'y', 'z'])
1056
Victor Stinner3d3f2642016-12-15 17:21:23 +01001057 @support.cpython_only
1058 def test_splittable_setattr_after_pop(self):
1059 """setattr() must not convert combined table into split table."""
1060 # Issue 28147
1061 import _testcapi
1062
1063 class C:
1064 pass
1065 a = C()
1066
1067 a.a = 1
1068 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1069
1070 # dict.pop() convert it to combined table
1071 a.__dict__.pop('a')
1072 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1073
1074 # But C should not convert a.__dict__ to split table again.
1075 a.a = 1
1076 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1077
1078 # Same for popitem()
1079 a = C()
1080 a.a = 2
1081 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1082 a.__dict__.popitem()
1083 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1084 a.a = 3
1085 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1086
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001087 def test_iterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001088 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1089 data = {1:"a", 2:"b", 3:"c"}
1090 it = iter(data)
1091 d = pickle.dumps(it, proto)
1092 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001093 self.assertEqual(list(it), list(data))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001094
Serhiy Storchakabad12572014-12-15 14:03:42 +02001095 it = pickle.loads(d)
1096 try:
1097 drop = next(it)
1098 except StopIteration:
1099 continue
1100 d = pickle.dumps(it, proto)
1101 it = pickle.loads(d)
1102 del data[drop]
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001103 self.assertEqual(list(it), list(data))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001104
1105 def test_itemiterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001106 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1107 data = {1:"a", 2:"b", 3:"c"}
1108 # dictviews aren't picklable, only their iterators
1109 itorg = iter(data.items())
1110 d = pickle.dumps(itorg, proto)
1111 it = pickle.loads(d)
Martin Pantera90a4a92016-05-30 04:04:50 +00001112 # note that the type of the unpickled iterator
Serhiy Storchakabad12572014-12-15 14:03:42 +02001113 # is not necessarily the same as the original. It is
1114 # merely an object supporting the iterator protocol, yielding
1115 # the same objects as the original one.
1116 # self.assertEqual(type(itorg), type(it))
1117 self.assertIsInstance(it, collections.abc.Iterator)
1118 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001119
Serhiy Storchakabad12572014-12-15 14:03:42 +02001120 it = pickle.loads(d)
1121 drop = next(it)
1122 d = pickle.dumps(it, proto)
1123 it = pickle.loads(d)
1124 del data[drop[0]]
1125 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001126
1127 def test_valuesiterator_pickling(self):
Sergey Fedoseev1f36bf62018-09-10 14:42:09 +05001128 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001129 data = {1:"a", 2:"b", 3:"c"}
1130 # data.values() isn't picklable, only its iterator
1131 it = iter(data.values())
1132 d = pickle.dumps(it, proto)
1133 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001134 self.assertEqual(list(it), list(data.values()))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001135
Serhiy Storchakabad12572014-12-15 14:03:42 +02001136 it = pickle.loads(d)
1137 drop = next(it)
1138 d = pickle.dumps(it, proto)
1139 it = pickle.loads(d)
1140 values = list(it) + [drop]
1141 self.assertEqual(sorted(values), sorted(list(data.values())))
Guido van Rossum1968ad32006-02-25 22:38:04 +00001142
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001143 def test_reverseiterator_pickling(self):
1144 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1145 data = {1:"a", 2:"b", 3:"c"}
1146 it = reversed(data)
1147 d = pickle.dumps(it, proto)
1148 it = pickle.loads(d)
1149 self.assertEqual(list(it), list(reversed(data)))
1150
1151 it = pickle.loads(d)
1152 try:
1153 drop = next(it)
1154 except StopIteration:
1155 continue
1156 d = pickle.dumps(it, proto)
1157 it = pickle.loads(d)
1158 del data[drop]
1159 self.assertEqual(list(it), list(reversed(data)))
1160
1161 def test_reverseitemiterator_pickling(self):
1162 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1163 data = {1:"a", 2:"b", 3:"c"}
1164 # dictviews aren't picklable, only their iterators
1165 itorg = reversed(data.items())
1166 d = pickle.dumps(itorg, proto)
1167 it = pickle.loads(d)
1168 # note that the type of the unpickled iterator
1169 # is not necessarily the same as the original. It is
1170 # merely an object supporting the iterator protocol, yielding
1171 # the same objects as the original one.
1172 # self.assertEqual(type(itorg), type(it))
1173 self.assertIsInstance(it, collections.abc.Iterator)
1174 self.assertEqual(dict(it), data)
1175
1176 it = pickle.loads(d)
1177 drop = next(it)
1178 d = pickle.dumps(it, proto)
1179 it = pickle.loads(d)
1180 del data[drop[0]]
1181 self.assertEqual(dict(it), data)
1182
1183 def test_reversevaluesiterator_pickling(self):
Zackery Spytzd1cbc6f2018-11-26 22:40:49 -07001184 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001185 data = {1:"a", 2:"b", 3:"c"}
1186 # data.values() isn't picklable, only its iterator
1187 it = reversed(data.values())
1188 d = pickle.dumps(it, proto)
1189 it = pickle.loads(d)
1190 self.assertEqual(list(it), list(reversed(data.values())))
1191
1192 it = pickle.loads(d)
1193 drop = next(it)
1194 d = pickle.dumps(it, proto)
1195 it = pickle.loads(d)
1196 values = list(it) + [drop]
1197 self.assertEqual(sorted(values), sorted(data.values()))
1198
Benjamin Petersondb780d02012-04-23 13:44:32 -04001199 def test_instance_dict_getattr_str_subclass(self):
1200 class Foo:
1201 def __init__(self, msg):
1202 self.msg = msg
1203 f = Foo('123')
1204 class _str(str):
1205 pass
1206 self.assertEqual(f.msg, getattr(f, _str('msg')))
1207 self.assertEqual(f.msg, f.__dict__[_str('msg')])
1208
Benjamin Peterson15ee8212012-04-24 14:44:18 -04001209 def test_object_set_item_single_instance_non_str_key(self):
1210 class Foo: pass
1211 f = Foo()
1212 f.__dict__[1] = 1
1213 f.a = 'a'
1214 self.assertEqual(f.__dict__, {1:1, 'a':'a'})
1215
Antoine Pitroud6967322014-10-18 00:35:00 +02001216 def check_reentrant_insertion(self, mutate):
1217 # This object will trigger mutation of the dict when replaced
1218 # by another value. Note this relies on refcounting: the test
1219 # won't achieve its purpose on fully-GCed Python implementations.
1220 class Mutating:
1221 def __del__(self):
1222 mutate(d)
1223
1224 d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
1225 for k in list(d):
1226 d[k] = k
1227
1228 def test_reentrant_insertion(self):
1229 # Reentrant insertion shouldn't crash (see issue #22653)
1230 def mutate(d):
1231 d['b'] = 5
1232 self.check_reentrant_insertion(mutate)
1233
1234 def mutate(d):
1235 d.update(self.__dict__)
1236 d.clear()
1237 self.check_reentrant_insertion(mutate)
1238
1239 def mutate(d):
1240 while d:
1241 d.popitem()
1242 self.check_reentrant_insertion(mutate)
1243
Benjamin Petersona82f77f2015-07-04 19:55:16 -05001244 def test_merge_and_mutate(self):
1245 class X:
1246 def __hash__(self):
1247 return 0
1248
1249 def __eq__(self, o):
1250 other.clear()
1251 return False
1252
1253 l = [(i,0) for i in range(1, 1337)]
1254 other = dict(l)
1255 other[X()] = 0
1256 d = {X(): 0, 1: 1}
1257 self.assertRaises(RuntimeError, d.update, other)
Antoine Pitroud6967322014-10-18 00:35:00 +02001258
Serhiy Storchakafbb1c5e2016-03-30 20:40:02 +03001259 def test_free_after_iterating(self):
1260 support.check_free_after_iterating(self, iter, dict)
1261 support.check_free_after_iterating(self, lambda d: iter(d.keys()), dict)
1262 support.check_free_after_iterating(self, lambda d: iter(d.values()), dict)
1263 support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
1264
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001265 def test_equal_operator_modifying_operand(self):
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001266 # test fix for seg fault reported in bpo-27945 part 3.
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001267 class X():
1268 def __del__(self):
1269 dict_b.clear()
1270
1271 def __eq__(self, other):
1272 dict_a.clear()
1273 return True
1274
1275 def __hash__(self):
1276 return 13
1277
1278 dict_a = {X(): 0}
1279 dict_b = {X(): X()}
1280 self.assertTrue(dict_a == dict_b)
1281
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001282 # test fix for seg fault reported in bpo-38588 part 1.
1283 class Y:
1284 def __eq__(self, other):
1285 dict_d.clear()
1286 return True
1287
1288 dict_c = {0: Y()}
1289 dict_d = {0: set()}
1290 self.assertTrue(dict_c == dict_d)
1291
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001292 def test_fromkeys_operator_modifying_dict_operand(self):
1293 # test fix for seg fault reported in issue 27945 part 4a.
1294 class X(int):
1295 def __hash__(self):
1296 return 13
1297
1298 def __eq__(self, other):
1299 if len(d) > 1:
1300 d.clear()
1301 return False
1302
1303 d = {} # this is required to exist so that d can be constructed!
1304 d = {X(1): 1, X(2): 2}
1305 try:
1306 dict.fromkeys(d) # shouldn't crash
1307 except RuntimeError: # implementation defined
1308 pass
1309
1310 def test_fromkeys_operator_modifying_set_operand(self):
1311 # test fix for seg fault reported in issue 27945 part 4b.
1312 class X(int):
1313 def __hash__(self):
1314 return 13
1315
1316 def __eq__(self, other):
1317 if len(d) > 1:
1318 d.clear()
1319 return False
1320
1321 d = {} # this is required to exist so that d can be constructed!
1322 d = {X(1), X(2)}
1323 try:
1324 dict.fromkeys(d) # shouldn't crash
1325 except RuntimeError: # implementation defined
1326 pass
1327
1328 def test_dictitems_contains_use_after_free(self):
1329 class X:
1330 def __eq__(self, other):
1331 d.clear()
1332 return NotImplemented
1333
1334 d = {0: set()}
1335 (0, X()) in d.items()
1336
Dong-hee Na785f5e62020-05-05 02:30:42 +09001337 def test_dict_contain_use_after_free(self):
1338 # bpo-40489
1339 class S(str):
1340 def __eq__(self, other):
1341 d.clear()
1342 return NotImplemented
1343
1344 def __hash__(self):
1345 return hash('test')
1346
1347 d = {S(): 'value'}
1348 self.assertFalse('test' in d)
1349
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001350 def test_init_use_after_free(self):
1351 class X:
1352 def __hash__(self):
1353 pair[:] = []
1354 return 13
1355
1356 pair = [X(), 123]
1357 dict([pair])
1358
1359 def test_oob_indexing_dictiter_iternextitem(self):
1360 class X(int):
1361 def __del__(self):
1362 d.clear()
1363
1364 d = {i: X(i) for i in range(8)}
1365
1366 def iter_and_mutate():
1367 for result in d.items():
1368 if result[0] == 2:
1369 d[2] = None # free d[2] --> X(2).__del__ was called
1370
1371 self.assertRaises(RuntimeError, iter_and_mutate)
1372
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001373 def test_reversed(self):
1374 d = {"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4}
1375 del d["foo"]
1376 r = reversed(d)
1377 self.assertEqual(list(r), list('dcba'))
1378 self.assertRaises(StopIteration, next, r)
1379
Dong-hee Na24dc2f82019-10-20 05:01:08 +09001380 def test_reverse_iterator_for_empty_dict(self):
1381 # bpo-38525: revered iterator should work properly
1382
1383 # empty dict is directly used for reference count test
1384 self.assertEqual(list(reversed({})), [])
1385 self.assertEqual(list(reversed({}.items())), [])
1386 self.assertEqual(list(reversed({}.values())), [])
1387 self.assertEqual(list(reversed({}.keys())), [])
1388
1389 # dict() and {} don't trigger the same code path
1390 self.assertEqual(list(reversed(dict())), [])
1391 self.assertEqual(list(reversed(dict().items())), [])
1392 self.assertEqual(list(reversed(dict().values())), [])
1393 self.assertEqual(list(reversed(dict().keys())), [])
1394
1395 def test_reverse_iterator_for_shared_shared_dicts(self):
1396 class A:
1397 def __init__(self, x, y):
1398 if x: self.x = x
1399 if y: self.y = y
1400
1401 self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x'])
1402 self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
1403 self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
1404
INADA Naoki2aaf98c2018-09-26 12:59:00 +09001405 def test_dict_copy_order(self):
1406 # bpo-34320
1407 od = collections.OrderedDict([('a', 1), ('b', 2)])
1408 od.move_to_end('a')
1409 expected = list(od.items())
1410
1411 copy = dict(od)
1412 self.assertEqual(list(copy.items()), expected)
1413
1414 # dict subclass doesn't override __iter__
1415 class CustomDict(dict):
1416 pass
1417
1418 pairs = [('a', 1), ('b', 2), ('c', 3)]
1419
1420 d = CustomDict(pairs)
1421 self.assertEqual(pairs, list(dict(d).items()))
1422
1423 class CustomReversedDict(dict):
1424 def keys(self):
1425 return reversed(list(dict.keys(self)))
1426
1427 __iter__ = keys
1428
1429 def items(self):
1430 return reversed(dict.items(self))
1431
1432 d = CustomReversedDict(pairs)
1433 self.assertEqual(pairs[::-1], list(dict(d).items()))
1434
Serhiy Storchakaf0b311b2016-11-06 13:18:24 +02001435
1436class CAPITest(unittest.TestCase):
1437
1438 # Test _PyDict_GetItem_KnownHash()
1439 @support.cpython_only
1440 def test_getitem_knownhash(self):
1441 from _testcapi import dict_getitem_knownhash
1442
1443 d = {'x': 1, 'y': 2, 'z': 3}
1444 self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1)
1445 self.assertEqual(dict_getitem_knownhash(d, 'y', hash('y')), 2)
1446 self.assertEqual(dict_getitem_knownhash(d, 'z', hash('z')), 3)
1447
1448 # not a dict
1449 self.assertRaises(SystemError, dict_getitem_knownhash, [], 1, hash(1))
1450 # key does not exist
1451 self.assertRaises(KeyError, dict_getitem_knownhash, {}, 1, hash(1))
1452
1453 class Exc(Exception): pass
1454 class BadEq:
1455 def __eq__(self, other):
1456 raise Exc
1457 def __hash__(self):
1458 return 7
1459
1460 k1, k2 = BadEq(), BadEq()
1461 d = {k1: 1}
1462 self.assertEqual(dict_getitem_knownhash(d, k1, hash(k1)), 1)
1463 self.assertRaises(Exc, dict_getitem_knownhash, d, k2, hash(k2))
1464
1465
Neal Norwitzc3e54b82006-03-24 07:38:37 +00001466from test import mapping_tests
Raymond Hettinger49c522b2004-09-30 15:07:29 +00001467
1468class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
1469 type2test = dict
1470
1471class Dict(dict):
1472 pass
1473
1474class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
1475 type2test = Dict
1476
Victor Stinner5ebe2c82016-01-23 13:52:05 +01001477
Walter Dörwald59b23e82004-09-30 13:46:00 +00001478if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001479 unittest.main()