blob: d5a3d9e8945741223b6a20c80ffd48959fd78119 [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
Guido van Rossum1d719962007-08-24 23:47:30 +0000700 def test_dictview_mixed_set_operations(self):
701 # Just a few for .keys()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000702 self.assertTrue({1:1}.keys() == {1})
703 self.assertTrue({1} == {1:1}.keys())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000704 self.assertEqual({1:1}.keys() | {2}, {1, 2})
705 self.assertEqual({2} | {1:1}.keys(), {1, 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000706 # And a few for .items()
Guido van Rossuma401bbe2007-08-24 23:51:55 +0000707 self.assertTrue({1:1}.items() == {(1,1)})
708 self.assertTrue({(1,1)} == {1:1}.items())
Florent Xiclunaa988e422010-03-02 16:06:24 +0000709 self.assertEqual({1:1}.items() | {2}, {(1,1), 2})
710 self.assertEqual({2} | {1:1}.items(), {(1,1), 2})
Guido van Rossum1d719962007-08-24 23:47:30 +0000711
Guido van Rossum1968ad32006-02-25 22:38:04 +0000712 def test_missing(self):
713 # Make sure dict doesn't have a __missing__ method
Florent Xiclunaa988e422010-03-02 16:06:24 +0000714 self.assertFalse(hasattr(dict, "__missing__"))
715 self.assertFalse(hasattr({}, "__missing__"))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000716 # Test several cases:
717 # (D) subclass defines __missing__ method returning a value
718 # (E) subclass defines __missing__ method raising RuntimeError
719 # (F) subclass sets __missing__ instance variable (no effect)
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200720 # (G) subclass doesn't define __missing__ at all
Guido van Rossum1968ad32006-02-25 22:38:04 +0000721 class D(dict):
722 def __missing__(self, key):
723 return 42
724 d = D({1: 2, 3: 4})
725 self.assertEqual(d[1], 2)
726 self.assertEqual(d[3], 4)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000727 self.assertNotIn(2, d)
Benjamin Peterson577473f2010-01-19 00:09:57 +0000728 self.assertNotIn(2, d.keys())
Guido van Rossum1968ad32006-02-25 22:38:04 +0000729 self.assertEqual(d[2], 42)
Florent Xiclunaa988e422010-03-02 16:06:24 +0000730
Guido van Rossum1968ad32006-02-25 22:38:04 +0000731 class E(dict):
732 def __missing__(self, key):
733 raise RuntimeError(key)
734 e = E()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000735 with self.assertRaises(RuntimeError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000736 e[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000737 self.assertEqual(c.exception.args, (42,))
738
Guido van Rossum1968ad32006-02-25 22:38:04 +0000739 class F(dict):
740 def __init__(self):
741 # An instance variable __missing__ should have no effect
742 self.__missing__ = lambda key: None
743 f = F()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000744 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000745 f[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000746 self.assertEqual(c.exception.args, (42,))
747
Guido van Rossum1968ad32006-02-25 22:38:04 +0000748 class G(dict):
749 pass
750 g = G()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000751 with self.assertRaises(KeyError) as c:
Guido van Rossum1968ad32006-02-25 22:38:04 +0000752 g[42]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000753 self.assertEqual(c.exception.args, (42,))
Guido van Rossum1968ad32006-02-25 22:38:04 +0000754
Thomas Wouters89f507f2006-12-13 04:49:30 +0000755 def test_tuple_keyerror(self):
756 # SF #1576657
757 d = {}
Florent Xiclunaa988e422010-03-02 16:06:24 +0000758 with self.assertRaises(KeyError) as c:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000759 d[(1,)]
Florent Xiclunaa988e422010-03-02 16:06:24 +0000760 self.assertEqual(c.exception.args, ((1,),))
Thomas Wouters89f507f2006-12-13 04:49:30 +0000761
Guido van Rossumd8faa362007-04-27 19:54:29 +0000762 def test_bad_key(self):
Mark Dickinsona56c4672009-01-27 18:17:45 +0000763 # Dictionary lookups should fail if __eq__() raises an exception.
Guido van Rossumd8faa362007-04-27 19:54:29 +0000764 class CustomException(Exception):
765 pass
766
767 class BadDictKey:
768 def __hash__(self):
769 return hash(self.__class__)
770
771 def __eq__(self, other):
772 if isinstance(other, self.__class__):
773 raise CustomException
774 return other
775
776 d = {}
777 x1 = BadDictKey()
778 x2 = BadDictKey()
779 d[x1] = 1
780 for stmt in ['d[x2] = 2',
781 'z = d[x2]',
782 'x2 in d',
783 'd.get(x2)',
784 'd.setdefault(x2, 42)',
785 'd.pop(x2)',
786 'd.update({x2: 2})']:
Florent Xiclunaa988e422010-03-02 16:06:24 +0000787 with self.assertRaises(CustomException):
Guido van Rossumd8faa362007-04-27 19:54:29 +0000788 exec(stmt, locals())
Guido van Rossumd8faa362007-04-27 19:54:29 +0000789
790 def test_resize1(self):
791 # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
792 # This version got an assert failure in debug build, infinite loop in
793 # release build. Unfortunately, provoking this kind of stuff requires
794 # a mix of inserts and deletes hitting exactly the right hash codes in
795 # exactly the right order, and I can't think of a randomized approach
796 # that would be *likely* to hit a failing case in reasonable time.
797
798 d = {}
799 for i in range(5):
800 d[i] = i
801 for i in range(5):
802 del d[i]
803 for i in range(5, 9): # i==8 was the problem
804 d[i] = i
805
806 def test_resize2(self):
807 # Another dict resizing bug (SF bug #1456209).
808 # This caused Segmentation faults or Illegal instructions.
809
810 class X(object):
811 def __hash__(self):
812 return 5
813 def __eq__(self, other):
814 if resizing:
815 d.clear()
816 return False
817 d = {}
818 resizing = False
819 d[X()] = 1
820 d[X()] = 2
821 d[X()] = 3
822 d[X()] = 4
823 d[X()] = 5
824 # now trigger a resize
825 resizing = True
826 d[9] = 6
827
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000828 def test_empty_presized_dict_in_freelist(self):
829 # Bug #3537: if an empty but presized dict with a size larger
830 # than 7 was in the freelist, it triggered an assertion failure
Florent Xiclunaa988e422010-03-02 16:06:24 +0000831 with self.assertRaises(ZeroDivisionError):
832 d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None,
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000833 'f': None, 'g': None, 'h': None}
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000834 d = {}
835
Antoine Pitrou7ddda782009-01-01 15:35:33 +0000836 def test_container_iterator(self):
837 # Bug #3680: tp_traverse was not implemented for dictiter and
838 # dictview objects.
839 class C(object):
840 pass
841 views = (dict.items, dict.values, dict.keys)
842 for v in views:
843 obj = C()
844 ref = weakref.ref(obj)
845 container = {obj: 1}
846 obj.v = v(container)
847 obj.x = iter(obj.v)
848 del obj, container
849 gc.collect()
Florent Xiclunaa988e422010-03-02 16:06:24 +0000850 self.assertIs(ref(), None, "Cycle was not collected")
Georg Brandl6aa2d1f2008-08-12 08:35:52 +0000851
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000852 def _not_tracked(self, t):
853 # Nested containers can take several collections to untrack
854 gc.collect()
855 gc.collect()
856 self.assertFalse(gc.is_tracked(t), t)
857
858 def _tracked(self, t):
859 self.assertTrue(gc.is_tracked(t), t)
860 gc.collect()
861 gc.collect()
862 self.assertTrue(gc.is_tracked(t), t)
863
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000864 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000865 def test_track_literals(self):
866 # Test GC-optimization of dict literals
867 x, y, z, w = 1.5, "a", (1, None), []
868
869 self._not_tracked({})
870 self._not_tracked({x:(), y:x, z:1})
871 self._not_tracked({1: "a", "b": 2})
872 self._not_tracked({1: 2, (None, True, False, ()): int})
873 self._not_tracked({1: object()})
874
875 # Dicts with mutable elements are always tracked, even if those
876 # elements are not tracked right now.
877 self._tracked({1: []})
878 self._tracked({1: ([],)})
879 self._tracked({1: {}})
880 self._tracked({1: set()})
881
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000882 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000883 def test_track_dynamic(self):
884 # Test GC-optimization of dynamically-created dicts
885 class MyObject(object):
886 pass
887 x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject()
888
889 d = dict()
890 self._not_tracked(d)
891 d[1] = "a"
892 self._not_tracked(d)
893 d[y] = 2
894 self._not_tracked(d)
895 d[z] = 3
896 self._not_tracked(d)
897 self._not_tracked(d.copy())
898 d[4] = w
899 self._tracked(d)
900 self._tracked(d.copy())
901 d[4] = None
902 self._not_tracked(d)
903 self._not_tracked(d.copy())
904
905 # dd isn't tracked right now, but it may mutate and therefore d
906 # which contains it must be tracked.
907 d = dict()
908 dd = dict()
909 d[1] = dd
910 self._not_tracked(dd)
911 self._tracked(d)
912 dd[1] = d
913 self._tracked(dd)
914
915 d = dict.fromkeys([x, y, z])
916 self._not_tracked(d)
917 dd = dict()
918 dd.update(d)
919 self._not_tracked(dd)
920 d = dict.fromkeys([x, y, z, o])
921 self._tracked(d)
922 dd = dict()
923 dd.update(d)
924 self._tracked(dd)
925
926 d = dict(x=x, y=y, z=z)
927 self._not_tracked(d)
928 d = dict(x=x, y=y, z=z, w=w)
929 self._tracked(d)
930 d = dict()
931 d.update(x=x, y=y, z=z)
932 self._not_tracked(d)
933 d.update(w=w)
934 self._tracked(d)
935
936 d = dict([(x, y), (z, 1)])
937 self._not_tracked(d)
938 d = dict([(x, y), (z, w)])
939 self._tracked(d)
940 d = dict()
941 d.update([(x, y), (z, 1)])
942 self._not_tracked(d)
943 d.update([(x, y), (z, w)])
944 self._tracked(d)
945
Benjamin Peterson3e5cd1d2010-06-27 21:45:24 +0000946 @support.cpython_only
Antoine Pitrou3a652b12009-03-23 18:52:06 +0000947 def test_track_subtypes(self):
948 # Dict subtypes are always tracked
949 class MyDict(dict):
950 pass
951 self._tracked(MyDict())
952
Victor Stinner78601a32016-09-09 19:28:36 -0700953 def make_shared_key_dict(self, n):
954 class C:
955 pass
956
957 dicts = []
958 for i in range(n):
959 a = C()
960 a.x, a.y, a.z = 1, 2, 3
961 dicts.append(a.__dict__)
962
963 return dicts
964
965 @support.cpython_only
INADA Naoki93f26f72016-11-02 18:45:16 +0900966 def test_splittable_setdefault(self):
967 """split table must be combined when setdefault()
968 breaks insertion order"""
969 a, b = self.make_shared_key_dict(2)
970
971 a['a'] = 1
972 size_a = sys.getsizeof(a)
973 a['b'] = 2
974 b.setdefault('b', 2)
975 size_b = sys.getsizeof(b)
976 b['a'] = 1
977
978 self.assertGreater(size_b, size_a)
979 self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b'])
980 self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a'])
981
982 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -0700983 def test_splittable_del(self):
984 """split table must be combined when del d[k]"""
985 a, b = self.make_shared_key_dict(2)
986
987 orig_size = sys.getsizeof(a)
988
989 del a['y'] # split table is combined
990 with self.assertRaises(KeyError):
991 del a['y']
992
993 self.assertGreater(sys.getsizeof(a), orig_size)
994 self.assertEqual(list(a), ['x', 'z'])
995 self.assertEqual(list(b), ['x', 'y', 'z'])
996
997 # Two dicts have different insertion order.
998 a['y'] = 42
999 self.assertEqual(list(a), ['x', 'z', 'y'])
1000 self.assertEqual(list(b), ['x', 'y', 'z'])
1001
1002 @support.cpython_only
1003 def test_splittable_pop(self):
1004 """split table must be combined when d.pop(k)"""
1005 a, b = self.make_shared_key_dict(2)
1006
1007 orig_size = sys.getsizeof(a)
1008
1009 a.pop('y') # split table is combined
1010 with self.assertRaises(KeyError):
1011 a.pop('y')
1012
1013 self.assertGreater(sys.getsizeof(a), orig_size)
1014 self.assertEqual(list(a), ['x', 'z'])
1015 self.assertEqual(list(b), ['x', 'y', 'z'])
1016
1017 # Two dicts have different insertion order.
1018 a['y'] = 42
1019 self.assertEqual(list(a), ['x', 'z', 'y'])
1020 self.assertEqual(list(b), ['x', 'y', 'z'])
1021
1022 @support.cpython_only
Victor Stinnerd0ad11f2016-09-13 16:56:38 +02001023 def test_splittable_pop_pending(self):
1024 """pop a pending key in a splitted table should not crash"""
1025 a, b = self.make_shared_key_dict(2)
1026
1027 a['a'] = 4
1028 with self.assertRaises(KeyError):
1029 b.pop('a')
1030
1031 @support.cpython_only
Victor Stinner78601a32016-09-09 19:28:36 -07001032 def test_splittable_popitem(self):
1033 """split table must be combined when d.popitem()"""
1034 a, b = self.make_shared_key_dict(2)
1035
1036 orig_size = sys.getsizeof(a)
1037
1038 item = a.popitem() # split table is combined
1039 self.assertEqual(item, ('z', 3))
1040 with self.assertRaises(KeyError):
1041 del a['z']
1042
1043 self.assertGreater(sys.getsizeof(a), orig_size)
1044 self.assertEqual(list(a), ['x', 'y'])
1045 self.assertEqual(list(b), ['x', 'y', 'z'])
1046
Victor Stinner3d3f2642016-12-15 17:21:23 +01001047 @support.cpython_only
1048 def test_splittable_setattr_after_pop(self):
1049 """setattr() must not convert combined table into split table."""
1050 # Issue 28147
1051 import _testcapi
1052
1053 class C:
1054 pass
1055 a = C()
1056
1057 a.a = 1
1058 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1059
1060 # dict.pop() convert it to combined table
1061 a.__dict__.pop('a')
1062 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1063
1064 # But C should not convert a.__dict__ to split table again.
1065 a.a = 1
1066 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1067
1068 # Same for popitem()
1069 a = C()
1070 a.a = 2
1071 self.assertTrue(_testcapi.dict_hassplittable(a.__dict__))
1072 a.__dict__.popitem()
1073 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1074 a.a = 3
1075 self.assertFalse(_testcapi.dict_hassplittable(a.__dict__))
1076
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001077 def test_iterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001078 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1079 data = {1:"a", 2:"b", 3:"c"}
1080 it = iter(data)
1081 d = pickle.dumps(it, proto)
1082 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001083 self.assertEqual(list(it), list(data))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001084
Serhiy Storchakabad12572014-12-15 14:03:42 +02001085 it = pickle.loads(d)
1086 try:
1087 drop = next(it)
1088 except StopIteration:
1089 continue
1090 d = pickle.dumps(it, proto)
1091 it = pickle.loads(d)
1092 del data[drop]
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
1095 def test_itemiterator_pickling(self):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001096 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1097 data = {1:"a", 2:"b", 3:"c"}
1098 # dictviews aren't picklable, only their iterators
1099 itorg = iter(data.items())
1100 d = pickle.dumps(itorg, proto)
1101 it = pickle.loads(d)
Martin Pantera90a4a92016-05-30 04:04:50 +00001102 # note that the type of the unpickled iterator
Serhiy Storchakabad12572014-12-15 14:03:42 +02001103 # is not necessarily the same as the original. It is
1104 # merely an object supporting the iterator protocol, yielding
1105 # the same objects as the original one.
1106 # self.assertEqual(type(itorg), type(it))
1107 self.assertIsInstance(it, collections.abc.Iterator)
1108 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001109
Serhiy Storchakabad12572014-12-15 14:03:42 +02001110 it = pickle.loads(d)
1111 drop = next(it)
1112 d = pickle.dumps(it, proto)
1113 it = pickle.loads(d)
1114 del data[drop[0]]
1115 self.assertEqual(dict(it), data)
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001116
1117 def test_valuesiterator_pickling(self):
Sergey Fedoseev1f36bf62018-09-10 14:42:09 +05001118 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Serhiy Storchakabad12572014-12-15 14:03:42 +02001119 data = {1:"a", 2:"b", 3:"c"}
1120 # data.values() isn't picklable, only its iterator
1121 it = iter(data.values())
1122 d = pickle.dumps(it, proto)
1123 it = pickle.loads(d)
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001124 self.assertEqual(list(it), list(data.values()))
Kristján Valur Jónsson31668b82012-04-03 10:49:41 +00001125
Serhiy Storchakabad12572014-12-15 14:03:42 +02001126 it = pickle.loads(d)
1127 drop = next(it)
1128 d = pickle.dumps(it, proto)
1129 it = pickle.loads(d)
1130 values = list(it) + [drop]
1131 self.assertEqual(sorted(values), sorted(list(data.values())))
Guido van Rossum1968ad32006-02-25 22:38:04 +00001132
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001133 def test_reverseiterator_pickling(self):
1134 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1135 data = {1:"a", 2:"b", 3:"c"}
1136 it = reversed(data)
1137 d = pickle.dumps(it, proto)
1138 it = pickle.loads(d)
1139 self.assertEqual(list(it), list(reversed(data)))
1140
1141 it = pickle.loads(d)
1142 try:
1143 drop = next(it)
1144 except StopIteration:
1145 continue
1146 d = pickle.dumps(it, proto)
1147 it = pickle.loads(d)
1148 del data[drop]
1149 self.assertEqual(list(it), list(reversed(data)))
1150
1151 def test_reverseitemiterator_pickling(self):
1152 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1153 data = {1:"a", 2:"b", 3:"c"}
1154 # dictviews aren't picklable, only their iterators
1155 itorg = reversed(data.items())
1156 d = pickle.dumps(itorg, proto)
1157 it = pickle.loads(d)
1158 # note that the type of the unpickled iterator
1159 # is not necessarily the same as the original. It is
1160 # merely an object supporting the iterator protocol, yielding
1161 # the same objects as the original one.
1162 # self.assertEqual(type(itorg), type(it))
1163 self.assertIsInstance(it, collections.abc.Iterator)
1164 self.assertEqual(dict(it), data)
1165
1166 it = pickle.loads(d)
1167 drop = next(it)
1168 d = pickle.dumps(it, proto)
1169 it = pickle.loads(d)
1170 del data[drop[0]]
1171 self.assertEqual(dict(it), data)
1172
1173 def test_reversevaluesiterator_pickling(self):
Zackery Spytzd1cbc6f2018-11-26 22:40:49 -07001174 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001175 data = {1:"a", 2:"b", 3:"c"}
1176 # data.values() isn't picklable, only its iterator
1177 it = reversed(data.values())
1178 d = pickle.dumps(it, proto)
1179 it = pickle.loads(d)
1180 self.assertEqual(list(it), list(reversed(data.values())))
1181
1182 it = pickle.loads(d)
1183 drop = next(it)
1184 d = pickle.dumps(it, proto)
1185 it = pickle.loads(d)
1186 values = list(it) + [drop]
1187 self.assertEqual(sorted(values), sorted(data.values()))
1188
Benjamin Petersondb780d02012-04-23 13:44:32 -04001189 def test_instance_dict_getattr_str_subclass(self):
1190 class Foo:
1191 def __init__(self, msg):
1192 self.msg = msg
1193 f = Foo('123')
1194 class _str(str):
1195 pass
1196 self.assertEqual(f.msg, getattr(f, _str('msg')))
1197 self.assertEqual(f.msg, f.__dict__[_str('msg')])
1198
Benjamin Peterson15ee8212012-04-24 14:44:18 -04001199 def test_object_set_item_single_instance_non_str_key(self):
1200 class Foo: pass
1201 f = Foo()
1202 f.__dict__[1] = 1
1203 f.a = 'a'
1204 self.assertEqual(f.__dict__, {1:1, 'a':'a'})
1205
Antoine Pitroud6967322014-10-18 00:35:00 +02001206 def check_reentrant_insertion(self, mutate):
1207 # This object will trigger mutation of the dict when replaced
1208 # by another value. Note this relies on refcounting: the test
1209 # won't achieve its purpose on fully-GCed Python implementations.
1210 class Mutating:
1211 def __del__(self):
1212 mutate(d)
1213
1214 d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
1215 for k in list(d):
1216 d[k] = k
1217
1218 def test_reentrant_insertion(self):
1219 # Reentrant insertion shouldn't crash (see issue #22653)
1220 def mutate(d):
1221 d['b'] = 5
1222 self.check_reentrant_insertion(mutate)
1223
1224 def mutate(d):
1225 d.update(self.__dict__)
1226 d.clear()
1227 self.check_reentrant_insertion(mutate)
1228
1229 def mutate(d):
1230 while d:
1231 d.popitem()
1232 self.check_reentrant_insertion(mutate)
1233
Benjamin Petersona82f77f2015-07-04 19:55:16 -05001234 def test_merge_and_mutate(self):
1235 class X:
1236 def __hash__(self):
1237 return 0
1238
1239 def __eq__(self, o):
1240 other.clear()
1241 return False
1242
1243 l = [(i,0) for i in range(1, 1337)]
1244 other = dict(l)
1245 other[X()] = 0
1246 d = {X(): 0, 1: 1}
1247 self.assertRaises(RuntimeError, d.update, other)
Antoine Pitroud6967322014-10-18 00:35:00 +02001248
Serhiy Storchakafbb1c5e2016-03-30 20:40:02 +03001249 def test_free_after_iterating(self):
1250 support.check_free_after_iterating(self, iter, dict)
1251 support.check_free_after_iterating(self, lambda d: iter(d.keys()), dict)
1252 support.check_free_after_iterating(self, lambda d: iter(d.values()), dict)
1253 support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
1254
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001255 def test_equal_operator_modifying_operand(self):
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001256 # test fix for seg fault reported in bpo-27945 part 3.
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001257 class X():
1258 def __del__(self):
1259 dict_b.clear()
1260
1261 def __eq__(self, other):
1262 dict_a.clear()
1263 return True
1264
1265 def __hash__(self):
1266 return 13
1267
1268 dict_a = {X(): 0}
1269 dict_b = {X(): X()}
1270 self.assertTrue(dict_a == dict_b)
1271
Dong-hee Na2d5bf562019-12-31 10:04:22 +09001272 # test fix for seg fault reported in bpo-38588 part 1.
1273 class Y:
1274 def __eq__(self, other):
1275 dict_d.clear()
1276 return True
1277
1278 dict_c = {0: Y()}
1279 dict_d = {0: set()}
1280 self.assertTrue(dict_c == dict_d)
1281
Serhiy Storchaka753bca32017-05-20 12:30:02 +03001282 def test_fromkeys_operator_modifying_dict_operand(self):
1283 # test fix for seg fault reported in issue 27945 part 4a.
1284 class X(int):
1285 def __hash__(self):
1286 return 13
1287
1288 def __eq__(self, other):
1289 if len(d) > 1:
1290 d.clear()
1291 return False
1292
1293 d = {} # this is required to exist so that d can be constructed!
1294 d = {X(1): 1, X(2): 2}
1295 try:
1296 dict.fromkeys(d) # shouldn't crash
1297 except RuntimeError: # implementation defined
1298 pass
1299
1300 def test_fromkeys_operator_modifying_set_operand(self):
1301 # test fix for seg fault reported in issue 27945 part 4b.
1302 class X(int):
1303 def __hash__(self):
1304 return 13
1305
1306 def __eq__(self, other):
1307 if len(d) > 1:
1308 d.clear()
1309 return False
1310
1311 d = {} # this is required to exist so that d can be constructed!
1312 d = {X(1), X(2)}
1313 try:
1314 dict.fromkeys(d) # shouldn't crash
1315 except RuntimeError: # implementation defined
1316 pass
1317
1318 def test_dictitems_contains_use_after_free(self):
1319 class X:
1320 def __eq__(self, other):
1321 d.clear()
1322 return NotImplemented
1323
1324 d = {0: set()}
1325 (0, X()) in d.items()
1326
1327 def test_init_use_after_free(self):
1328 class X:
1329 def __hash__(self):
1330 pair[:] = []
1331 return 13
1332
1333 pair = [X(), 123]
1334 dict([pair])
1335
1336 def test_oob_indexing_dictiter_iternextitem(self):
1337 class X(int):
1338 def __del__(self):
1339 d.clear()
1340
1341 d = {i: X(i) for i in range(8)}
1342
1343 def iter_and_mutate():
1344 for result in d.items():
1345 if result[0] == 2:
1346 d[2] = None # free d[2] --> X(2).__del__ was called
1347
1348 self.assertRaises(RuntimeError, iter_and_mutate)
1349
Rémi Lapeyre6531bf62018-11-06 01:38:54 +01001350 def test_reversed(self):
1351 d = {"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4}
1352 del d["foo"]
1353 r = reversed(d)
1354 self.assertEqual(list(r), list('dcba'))
1355 self.assertRaises(StopIteration, next, r)
1356
Dong-hee Na24dc2f82019-10-20 05:01:08 +09001357 def test_reverse_iterator_for_empty_dict(self):
1358 # bpo-38525: revered iterator should work properly
1359
1360 # empty dict is directly used for reference count test
1361 self.assertEqual(list(reversed({})), [])
1362 self.assertEqual(list(reversed({}.items())), [])
1363 self.assertEqual(list(reversed({}.values())), [])
1364 self.assertEqual(list(reversed({}.keys())), [])
1365
1366 # dict() and {} don't trigger the same code path
1367 self.assertEqual(list(reversed(dict())), [])
1368 self.assertEqual(list(reversed(dict().items())), [])
1369 self.assertEqual(list(reversed(dict().values())), [])
1370 self.assertEqual(list(reversed(dict().keys())), [])
1371
1372 def test_reverse_iterator_for_shared_shared_dicts(self):
1373 class A:
1374 def __init__(self, x, y):
1375 if x: self.x = x
1376 if y: self.y = y
1377
1378 self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x'])
1379 self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
1380 self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
1381
INADA Naoki2aaf98c2018-09-26 12:59:00 +09001382 def test_dict_copy_order(self):
1383 # bpo-34320
1384 od = collections.OrderedDict([('a', 1), ('b', 2)])
1385 od.move_to_end('a')
1386 expected = list(od.items())
1387
1388 copy = dict(od)
1389 self.assertEqual(list(copy.items()), expected)
1390
1391 # dict subclass doesn't override __iter__
1392 class CustomDict(dict):
1393 pass
1394
1395 pairs = [('a', 1), ('b', 2), ('c', 3)]
1396
1397 d = CustomDict(pairs)
1398 self.assertEqual(pairs, list(dict(d).items()))
1399
1400 class CustomReversedDict(dict):
1401 def keys(self):
1402 return reversed(list(dict.keys(self)))
1403
1404 __iter__ = keys
1405
1406 def items(self):
1407 return reversed(dict.items(self))
1408
1409 d = CustomReversedDict(pairs)
1410 self.assertEqual(pairs[::-1], list(dict(d).items()))
1411
Serhiy Storchakaf0b311b2016-11-06 13:18:24 +02001412
1413class CAPITest(unittest.TestCase):
1414
1415 # Test _PyDict_GetItem_KnownHash()
1416 @support.cpython_only
1417 def test_getitem_knownhash(self):
1418 from _testcapi import dict_getitem_knownhash
1419
1420 d = {'x': 1, 'y': 2, 'z': 3}
1421 self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1)
1422 self.assertEqual(dict_getitem_knownhash(d, 'y', hash('y')), 2)
1423 self.assertEqual(dict_getitem_knownhash(d, 'z', hash('z')), 3)
1424
1425 # not a dict
1426 self.assertRaises(SystemError, dict_getitem_knownhash, [], 1, hash(1))
1427 # key does not exist
1428 self.assertRaises(KeyError, dict_getitem_knownhash, {}, 1, hash(1))
1429
1430 class Exc(Exception): pass
1431 class BadEq:
1432 def __eq__(self, other):
1433 raise Exc
1434 def __hash__(self):
1435 return 7
1436
1437 k1, k2 = BadEq(), BadEq()
1438 d = {k1: 1}
1439 self.assertEqual(dict_getitem_knownhash(d, k1, hash(k1)), 1)
1440 self.assertRaises(Exc, dict_getitem_knownhash, d, k2, hash(k2))
1441
1442
Neal Norwitzc3e54b82006-03-24 07:38:37 +00001443from test import mapping_tests
Raymond Hettinger49c522b2004-09-30 15:07:29 +00001444
1445class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
1446 type2test = dict
1447
1448class Dict(dict):
1449 pass
1450
1451class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
1452 type2test = Dict
1453
Victor Stinner5ebe2c82016-01-23 13:52:05 +01001454
Walter Dörwald59b23e82004-09-30 13:46:00 +00001455if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -05001456 unittest.main()