blob: 901d4b2ad29478f9fb35c702cc777b3132b9f26b [file] [log] [blame]
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +02001import contextlib
2import copy
Serhiy Storchakad205d012016-01-19 14:46:25 +02003import gc
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +02004import pickle
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +02005from random import randrange, shuffle
Serhiy Storchaka0ce7a3a2015-12-22 08:16:18 +02006import struct
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +02007import sys
8import unittest
Serhiy Storchakad205d012016-01-19 14:46:25 +02009import weakref
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +020010from collections.abc import MutableMapping
11from test import mapping_tests, support
12
13
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +020014py_coll = support.import_fresh_module('collections', blocked=['_collections'])
15c_coll = support.import_fresh_module('collections', fresh=['_collections'])
16
17
18@contextlib.contextmanager
19def replaced_module(name, replacement):
20 original_module = sys.modules[name]
21 sys.modules[name] = replacement
22 try:
23 yield
24 finally:
25 sys.modules[name] = original_module
26
27
28class OrderedDictTests:
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +020029
30 def test_init(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +020031 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +020032 with self.assertRaises(TypeError):
33 OrderedDict([('a', 1), ('b', 2)], None) # too many args
34 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
35 self.assertEqual(sorted(OrderedDict(dict(pairs)).items()), pairs) # dict input
36 self.assertEqual(sorted(OrderedDict(**dict(pairs)).items()), pairs) # kwds input
37 self.assertEqual(list(OrderedDict(pairs).items()), pairs) # pairs input
38 self.assertEqual(list(OrderedDict([('a', 1), ('b', 2), ('c', 9), ('d', 4)],
39 c=3, e=5).items()), pairs) # mixed input
40
41 # make sure no positional args conflict with possible kwdargs
42 self.assertEqual(list(OrderedDict(self=42).items()), [('self', 42)])
43 self.assertEqual(list(OrderedDict(other=42).items()), [('other', 42)])
44 self.assertRaises(TypeError, OrderedDict, 42)
45 self.assertRaises(TypeError, OrderedDict, (), ())
46 self.assertRaises(TypeError, OrderedDict.__init__)
47
48 # Make sure that direct calls to __init__ do not clear previous contents
49 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
50 d.__init__([('e', 5), ('f', 6)], g=7, d=4)
51 self.assertEqual(list(d.items()),
52 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
53
54 def test_update(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +020055 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +020056 with self.assertRaises(TypeError):
57 OrderedDict().update([('a', 1), ('b', 2)], None) # too many args
58 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
59 od = OrderedDict()
60 od.update(dict(pairs))
61 self.assertEqual(sorted(od.items()), pairs) # dict input
62 od = OrderedDict()
63 od.update(**dict(pairs))
64 self.assertEqual(sorted(od.items()), pairs) # kwds input
65 od = OrderedDict()
66 od.update(pairs)
67 self.assertEqual(list(od.items()), pairs) # pairs input
68 od = OrderedDict()
69 od.update([('a', 1), ('b', 2), ('c', 9), ('d', 4)], c=3, e=5)
70 self.assertEqual(list(od.items()), pairs) # mixed input
71
72 # Issue 9137: Named argument called 'other' or 'self'
73 # shouldn't be treated specially.
74 od = OrderedDict()
75 od.update(self=23)
76 self.assertEqual(list(od.items()), [('self', 23)])
77 od = OrderedDict()
78 od.update(other={})
79 self.assertEqual(list(od.items()), [('other', {})])
80 od = OrderedDict()
81 od.update(red=5, blue=6, other=7, self=8)
82 self.assertEqual(sorted(list(od.items())),
83 [('blue', 6), ('other', 7), ('red', 5), ('self', 8)])
84
85 # Make sure that direct calls to update do not clear previous contents
86 # add that updates items are not moved to the end
87 d = OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 44), ('e', 55)])
88 d.update([('e', 5), ('f', 6)], g=7, d=4)
89 self.assertEqual(list(d.items()),
90 [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)])
91
92 self.assertRaises(TypeError, OrderedDict().update, 42)
93 self.assertRaises(TypeError, OrderedDict().update, (), ())
94 self.assertRaises(TypeError, OrderedDict.update)
95
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +020096 self.assertRaises(TypeError, OrderedDict().update, 42)
97 self.assertRaises(TypeError, OrderedDict().update, (), ())
98 self.assertRaises(TypeError, OrderedDict.update)
99
100 def test_fromkeys(self):
101 OrderedDict = self.OrderedDict
102 od = OrderedDict.fromkeys('abc')
103 self.assertEqual(list(od.items()), [(c, None) for c in 'abc'])
104 od = OrderedDict.fromkeys('abc', value=None)
105 self.assertEqual(list(od.items()), [(c, None) for c in 'abc'])
106 od = OrderedDict.fromkeys('abc', value=0)
107 self.assertEqual(list(od.items()), [(c, 0) for c in 'abc'])
108
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200109 def test_abc(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200110 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200111 self.assertIsInstance(OrderedDict(), MutableMapping)
112 self.assertTrue(issubclass(OrderedDict, MutableMapping))
113
114 def test_clear(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200115 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200116 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
117 shuffle(pairs)
118 od = OrderedDict(pairs)
119 self.assertEqual(len(od), len(pairs))
120 od.clear()
121 self.assertEqual(len(od), 0)
122
123 def test_delitem(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200124 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200125 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
126 od = OrderedDict(pairs)
127 del od['a']
128 self.assertNotIn('a', od)
129 with self.assertRaises(KeyError):
130 del od['a']
131 self.assertEqual(list(od.items()), pairs[:2] + pairs[3:])
132
133 def test_setitem(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200134 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200135 od = OrderedDict([('d', 1), ('b', 2), ('c', 3), ('a', 4), ('e', 5)])
136 od['c'] = 10 # existing element
137 od['f'] = 20 # new element
138 self.assertEqual(list(od.items()),
139 [('d', 1), ('b', 2), ('c', 10), ('a', 4), ('e', 5), ('f', 20)])
140
141 def test_iterators(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200142 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200143 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
144 shuffle(pairs)
145 od = OrderedDict(pairs)
146 self.assertEqual(list(od), [t[0] for t in pairs])
147 self.assertEqual(list(od.keys()), [t[0] for t in pairs])
148 self.assertEqual(list(od.values()), [t[1] for t in pairs])
149 self.assertEqual(list(od.items()), pairs)
150 self.assertEqual(list(reversed(od)),
151 [t[0] for t in reversed(pairs)])
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200152 self.assertEqual(list(reversed(od.keys())),
153 [t[0] for t in reversed(pairs)])
154 self.assertEqual(list(reversed(od.values())),
155 [t[1] for t in reversed(pairs)])
156 self.assertEqual(list(reversed(od.items())), list(reversed(pairs)))
157
158 def test_detect_deletion_during_iteration(self):
159 OrderedDict = self.OrderedDict
160 od = OrderedDict.fromkeys('abc')
161 it = iter(od)
162 key = next(it)
163 del od[key]
164 with self.assertRaises(Exception):
165 # Note, the exact exception raised is not guaranteed
166 # The only guarantee that the next() will not succeed
167 next(it)
168
169 def test_sorted_iterators(self):
170 OrderedDict = self.OrderedDict
171 with self.assertRaises(TypeError):
172 OrderedDict([('a', 1), ('b', 2)], None)
173 pairs = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)]
174 od = OrderedDict(pairs)
175 self.assertEqual(sorted(od), [t[0] for t in pairs])
176 self.assertEqual(sorted(od.keys()), [t[0] for t in pairs])
177 self.assertEqual(sorted(od.values()), [t[1] for t in pairs])
178 self.assertEqual(sorted(od.items()), pairs)
179 self.assertEqual(sorted(reversed(od)),
180 sorted([t[0] for t in reversed(pairs)]))
181
182 def test_iterators_empty(self):
183 OrderedDict = self.OrderedDict
184 od = OrderedDict()
185 empty = []
186 self.assertEqual(list(od), empty)
187 self.assertEqual(list(od.keys()), empty)
188 self.assertEqual(list(od.values()), empty)
189 self.assertEqual(list(od.items()), empty)
190 self.assertEqual(list(reversed(od)), empty)
191 self.assertEqual(list(reversed(od.keys())), empty)
192 self.assertEqual(list(reversed(od.values())), empty)
193 self.assertEqual(list(reversed(od.items())), empty)
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200194
195 def test_popitem(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200196 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200197 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
198 shuffle(pairs)
199 od = OrderedDict(pairs)
200 while pairs:
201 self.assertEqual(od.popitem(), pairs.pop())
202 with self.assertRaises(KeyError):
203 od.popitem()
204 self.assertEqual(len(od), 0)
205
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200206 def test_popitem_last(self):
207 OrderedDict = self.OrderedDict
208 pairs = [(i, i) for i in range(30)]
209
210 obj = OrderedDict(pairs)
211 for i in range(8):
212 obj.popitem(True)
213 obj.popitem(True)
214 obj.popitem(last=True)
215 self.assertEqual(len(obj), 20)
216
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200217 def test_pop(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200218 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200219 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
220 shuffle(pairs)
221 od = OrderedDict(pairs)
222 shuffle(pairs)
223 while pairs:
224 k, v = pairs.pop()
225 self.assertEqual(od.pop(k), v)
226 with self.assertRaises(KeyError):
227 od.pop('xyz')
228 self.assertEqual(len(od), 0)
229 self.assertEqual(od.pop(k, 12345), 12345)
230
231 # make sure pop still works when __missing__ is defined
232 class Missing(OrderedDict):
233 def __missing__(self, key):
234 return 0
235 m = Missing(a=1)
236 self.assertEqual(m.pop('b', 5), 5)
237 self.assertEqual(m.pop('a', 6), 1)
238 self.assertEqual(m.pop('a', 6), 6)
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200239 self.assertEqual(m.pop('a', default=6), 6)
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200240 with self.assertRaises(KeyError):
241 m.pop('a')
242
243 def test_equality(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200244 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200245 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
246 shuffle(pairs)
247 od1 = OrderedDict(pairs)
248 od2 = OrderedDict(pairs)
249 self.assertEqual(od1, od2) # same order implies equality
250 pairs = pairs[2:] + pairs[:2]
251 od2 = OrderedDict(pairs)
252 self.assertNotEqual(od1, od2) # different order implies inequality
253 # comparison to regular dict is not order sensitive
254 self.assertEqual(od1, dict(od2))
255 self.assertEqual(dict(od2), od1)
256 # different length implied inequality
257 self.assertNotEqual(od1, OrderedDict(pairs[:-1]))
258
259 def test_copying(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200260 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200261 # Check that ordered dicts are copyable, deepcopyable, picklable,
262 # and have a repr/eval round-trip
263 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
264 od = OrderedDict(pairs)
265 def check(dup):
266 msg = "\ncopy: %s\nod: %s" % (dup, od)
267 self.assertIsNot(dup, od, msg)
268 self.assertEqual(dup, od)
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200269 self.assertEqual(list(dup.items()), list(od.items()))
270 self.assertEqual(len(dup), len(od))
271 self.assertEqual(type(dup), type(od))
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200272 check(od.copy())
273 check(copy.copy(od))
274 check(copy.deepcopy(od))
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200275 # pickle directly pulls the module, so we have to fake it
276 with replaced_module('collections', self.module):
277 for proto in range(pickle.HIGHEST_PROTOCOL + 1):
278 with self.subTest(proto=proto):
279 check(pickle.loads(pickle.dumps(od, proto)))
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200280 check(eval(repr(od)))
281 update_test = OrderedDict()
282 update_test.update(od)
283 check(update_test)
284 check(OrderedDict(od))
285
286 def test_yaml_linkage(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200287 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200288 # Verify that __reduce__ is setup in a way that supports PyYAML's dump() feature.
289 # In yaml, lists are native but tuples are not.
290 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
291 od = OrderedDict(pairs)
292 # yaml.dump(od) -->
293 # '!!python/object/apply:__main__.OrderedDict\n- - [a, 1]\n - [b, 2]\n'
294 self.assertTrue(all(type(pair)==list for pair in od.__reduce__()[1]))
295
296 def test_reduce_not_too_fat(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200297 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200298 # do not save instance dictionary if not needed
299 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
300 od = OrderedDict(pairs)
301 self.assertIsNone(od.__reduce__()[2])
302 od.x = 10
303 self.assertIsNotNone(od.__reduce__()[2])
304
305 def test_pickle_recursive(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200306 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200307 od = OrderedDict()
308 od[1] = od
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200309
310 # pickle directly pulls the module, so we have to fake it
311 with replaced_module('collections', self.module):
312 for proto in range(-1, pickle.HIGHEST_PROTOCOL + 1):
313 dup = pickle.loads(pickle.dumps(od, proto))
314 self.assertIsNot(dup, od)
315 self.assertEqual(list(dup.keys()), [1])
316 self.assertIs(dup[1], dup)
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200317
318 def test_repr(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200319 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200320 od = OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])
321 self.assertEqual(repr(od),
322 "OrderedDict([('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)])")
323 self.assertEqual(eval(repr(od)), od)
324 self.assertEqual(repr(OrderedDict()), "OrderedDict()")
325
326 def test_repr_recursive(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200327 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200328 # See issue #9826
329 od = OrderedDict.fromkeys('abc')
330 od['x'] = od
331 self.assertEqual(repr(od),
332 "OrderedDict([('a', None), ('b', None), ('c', None), ('x', ...)])")
333
334 def test_setdefault(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200335 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200336 pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)]
337 shuffle(pairs)
338 od = OrderedDict(pairs)
339 pair_order = list(od.items())
340 self.assertEqual(od.setdefault('a', 10), 3)
341 # make sure order didn't change
342 self.assertEqual(list(od.items()), pair_order)
343 self.assertEqual(od.setdefault('x', 10), 10)
344 # make sure 'x' is added to the end
345 self.assertEqual(list(od.items())[-1], ('x', 10))
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200346 self.assertEqual(od.setdefault('g', default=9), 9)
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200347
348 # make sure setdefault still works when __missing__ is defined
349 class Missing(OrderedDict):
350 def __missing__(self, key):
351 return 0
352 self.assertEqual(Missing().setdefault(5, 9), 9)
353
354 def test_reinsert(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200355 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200356 # Given insert a, insert b, delete a, re-insert a,
357 # verify that a is now later than b.
358 od = OrderedDict()
359 od['a'] = 1
360 od['b'] = 2
361 del od['a']
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200362 self.assertEqual(list(od.items()), [('b', 2)])
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200363 od['a'] = 1
364 self.assertEqual(list(od.items()), [('b', 2), ('a', 1)])
365
366 def test_move_to_end(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200367 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200368 od = OrderedDict.fromkeys('abcde')
369 self.assertEqual(list(od), list('abcde'))
370 od.move_to_end('c')
371 self.assertEqual(list(od), list('abdec'))
372 od.move_to_end('c', 0)
373 self.assertEqual(list(od), list('cabde'))
374 od.move_to_end('c', 0)
375 self.assertEqual(list(od), list('cabde'))
376 od.move_to_end('e')
377 self.assertEqual(list(od), list('cabde'))
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200378 od.move_to_end('b', last=False)
379 self.assertEqual(list(od), list('bcade'))
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200380 with self.assertRaises(KeyError):
381 od.move_to_end('x')
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200382 with self.assertRaises(KeyError):
383 od.move_to_end('x', 0)
384
385 def test_move_to_end_issue25406(self):
386 OrderedDict = self.OrderedDict
387 od = OrderedDict.fromkeys('abc')
388 od.move_to_end('c', last=False)
389 self.assertEqual(list(od), list('cab'))
390 od.move_to_end('a', last=False)
391 self.assertEqual(list(od), list('acb'))
392
393 od = OrderedDict.fromkeys('abc')
394 od.move_to_end('a')
395 self.assertEqual(list(od), list('bca'))
396 od.move_to_end('c')
397 self.assertEqual(list(od), list('bac'))
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200398
399 def test_sizeof(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200400 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200401 # Wimpy test: Just verify the reported size is larger than a regular dict
402 d = dict(a=1)
403 od = OrderedDict(**d)
404 self.assertGreater(sys.getsizeof(od), sys.getsizeof(d))
405
406 def test_override_update(self):
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200407 OrderedDict = self.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200408 # Verify that subclasses can override update() without breaking __init__()
409 class MyOD(OrderedDict):
410 def update(self, *args, **kwds):
411 raise Exception()
412 items = [('a', 1), ('c', 3), ('b', 2)]
413 self.assertEqual(list(MyOD(items).items()), items)
414
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200415 def test_highly_nested(self):
416 # Issue 25395: crashes during garbage collection
417 OrderedDict = self.OrderedDict
418 obj = None
419 for _ in range(1000):
420 obj = OrderedDict([(None, obj)])
421 del obj
422 support.gc_collect()
423
424 def test_highly_nested_subclass(self):
425 # Issue 25395: crashes during garbage collection
426 OrderedDict = self.OrderedDict
427 deleted = []
428 class MyOD(OrderedDict):
429 def __del__(self):
430 deleted.append(self.i)
431 obj = None
432 for i in range(100):
433 obj = MyOD([(None, obj)])
434 obj.i = i
435 del obj
436 support.gc_collect()
437 self.assertEqual(deleted, list(reversed(range(100))))
438
439 def test_delitem_hash_collision(self):
440 OrderedDict = self.OrderedDict
441
442 class Key:
443 def __init__(self, hash):
444 self._hash = hash
445 self.value = str(id(self))
446 def __hash__(self):
447 return self._hash
448 def __eq__(self, other):
449 try:
450 return self.value == other.value
451 except AttributeError:
452 return False
453 def __repr__(self):
454 return self.value
455
456 def blocking_hash(hash):
457 # See the collision-handling in lookdict (in Objects/dictobject.c).
458 MINSIZE = 8
459 i = (hash & MINSIZE-1)
460 return (i << 2) + i + hash + 1
461
462 COLLIDING = 1
463
464 key = Key(COLLIDING)
465 colliding = Key(COLLIDING)
466 blocking = Key(blocking_hash(COLLIDING))
467
468 od = OrderedDict()
469 od[key] = ...
470 od[blocking] = ...
471 od[colliding] = ...
472 od['after'] = ...
473
474 del od[blocking]
475 del od[colliding]
476 self.assertEqual(list(od.items()), [(key, ...), ('after', ...)])
477
478 def test_issue24347(self):
479 OrderedDict = self.OrderedDict
480
481 class Key:
482 def __hash__(self):
483 return randrange(100000)
484
485 od = OrderedDict()
486 for i in range(100):
487 key = Key()
488 od[key] = i
489
490 # These should not crash.
491 with self.assertRaises(KeyError):
492 list(od.values())
493 with self.assertRaises(KeyError):
494 list(od.items())
495 with self.assertRaises(KeyError):
496 repr(od)
497 with self.assertRaises(KeyError):
498 od.copy()
499
500 def test_issue24348(self):
501 OrderedDict = self.OrderedDict
502
503 class Key:
504 def __hash__(self):
505 return 1
506
507 od = OrderedDict()
508 od[Key()] = 0
509 # This should not crash.
510 od.popitem()
511
512 def test_issue24667(self):
513 """
514 dict resizes after a certain number of insertion operations,
515 whether or not there were deletions that freed up slots in the
516 hash table. During fast node lookup, OrderedDict must correctly
517 respond to all resizes, even if the current "size" is the same
518 as the old one. We verify that here by forcing a dict resize
519 on a sparse odict and then perform an operation that should
520 trigger an odict resize (e.g. popitem). One key aspect here is
521 that we will keep the size of the odict the same at each popitem
522 call. This verifies that we handled the dict resize properly.
523 """
524 OrderedDict = self.OrderedDict
525
526 od = OrderedDict()
527 for c0 in '0123456789ABCDEF':
528 for c1 in '0123456789ABCDEF':
529 if len(od) == 4:
530 # This should not raise a KeyError.
531 od.popitem(last=False)
532 key = c0 + c1
533 od[key] = key
534
535 # Direct use of dict methods
536
537 def test_dict_setitem(self):
538 OrderedDict = self.OrderedDict
539 od = OrderedDict()
540 dict.__setitem__(od, 'spam', 1)
541 self.assertNotIn('NULL', repr(od))
542
543 def test_dict_delitem(self):
544 OrderedDict = self.OrderedDict
545 od = OrderedDict()
546 od['spam'] = 1
547 od['ham'] = 2
548 dict.__delitem__(od, 'spam')
549 with self.assertRaises(KeyError):
550 repr(od)
551
552 def test_dict_clear(self):
553 OrderedDict = self.OrderedDict
554 od = OrderedDict()
555 od['spam'] = 1
556 od['ham'] = 2
557 dict.clear(od)
558 self.assertNotIn('NULL', repr(od))
559
560 def test_dict_pop(self):
561 OrderedDict = self.OrderedDict
562 od = OrderedDict()
563 od['spam'] = 1
564 od['ham'] = 2
565 dict.pop(od, 'spam')
566 with self.assertRaises(KeyError):
567 repr(od)
568
569 def test_dict_popitem(self):
570 OrderedDict = self.OrderedDict
571 od = OrderedDict()
572 od['spam'] = 1
573 od['ham'] = 2
574 dict.popitem(od)
575 with self.assertRaises(KeyError):
576 repr(od)
577
578 def test_dict_setdefault(self):
579 OrderedDict = self.OrderedDict
580 od = OrderedDict()
581 dict.setdefault(od, 'spam', 1)
582 self.assertNotIn('NULL', repr(od))
583
584 def test_dict_update(self):
585 OrderedDict = self.OrderedDict
586 od = OrderedDict()
587 dict.update(od, [('spam', 1)])
588 self.assertNotIn('NULL', repr(od))
589
Serhiy Storchakad205d012016-01-19 14:46:25 +0200590 def test_reference_loop(self):
591 # Issue 25935
592 OrderedDict = self.OrderedDict
593 class A:
594 od = OrderedDict()
595 A.od[A] = None
596 r = weakref.ref(A)
597 del A
598 gc.collect()
599 self.assertIsNone(r())
600
Serhiy Storchakafbb1c5e2016-03-30 20:40:02 +0300601 def test_free_after_iterating(self):
602 support.check_free_after_iterating(self, iter, self.OrderedDict)
603 support.check_free_after_iterating(self, lambda d: iter(d.keys()), self.OrderedDict)
604 support.check_free_after_iterating(self, lambda d: iter(d.values()), self.OrderedDict)
605 support.check_free_after_iterating(self, lambda d: iter(d.items()), self.OrderedDict)
606
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200607
608class PurePythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
609
610 module = py_coll
611 OrderedDict = py_coll.OrderedDict
612
613
614@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
615class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
616
617 module = c_coll
618 OrderedDict = c_coll.OrderedDict
Serhiy Storchaka0ce7a3a2015-12-22 08:16:18 +0200619 check_sizeof = support.check_sizeof
620
621 @support.cpython_only
622 def test_sizeof_exact(self):
623 OrderedDict = self.OrderedDict
624 calcsize = struct.calcsize
625 size = support.calcobjsize
626 check = self.check_sizeof
627
628 basicsize = size('n2P' + '3PnPn2P') + calcsize('2nPn')
629 entrysize = calcsize('n2P') + calcsize('P')
630 nodesize = calcsize('Pn2P')
631
632 od = OrderedDict()
633 check(od, basicsize + 8*entrysize)
634 od.x = 1
635 check(od, basicsize + 8*entrysize)
636 od.update([(i, i) for i in range(3)])
637 check(od, basicsize + 8*entrysize + 3*nodesize)
638 od.update([(i, i) for i in range(3, 10)])
639 check(od, basicsize + 16*entrysize + 10*nodesize)
640
641 check(od.keys(), size('P'))
642 check(od.items(), size('P'))
643 check(od.values(), size('P'))
644
645 itersize = size('iP2n2P')
646 check(iter(od), itersize)
647 check(iter(od.keys()), itersize)
648 check(iter(od.items()), itersize)
649 check(iter(od.values()), itersize)
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200650
651 def test_key_change_during_iteration(self):
652 OrderedDict = self.OrderedDict
653
654 od = OrderedDict.fromkeys('abcde')
655 self.assertEqual(list(od), list('abcde'))
656 with self.assertRaises(RuntimeError):
657 for i, k in enumerate(od):
658 od.move_to_end(k)
659 self.assertLess(i, 5)
660 with self.assertRaises(RuntimeError):
661 for k in od:
662 od['f'] = None
663 with self.assertRaises(RuntimeError):
664 for k in od:
665 del od['c']
666 self.assertEqual(list(od), list('bdeaf'))
667
668
669class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
670
671 module = py_coll
672 class OrderedDict(py_coll.OrderedDict):
673 pass
674
675
676class CPythonOrderedDictSubclassTests(CPythonOrderedDictTests):
677
678 module = c_coll
679 class OrderedDict(c_coll.OrderedDict):
680 pass
681
682
683class PurePythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
684
685 @classmethod
686 def setUpClass(cls):
687 cls.type2test = py_coll.OrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200688
689 def test_popitem(self):
690 d = self._empty_mapping()
691 self.assertRaises(KeyError, d.popitem)
692
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200693
Serhiy Storchaka2cefc1e2015-11-25 17:12:02 +0200694@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
695class CPythonGeneralMappingTests(mapping_tests.BasicTestMappingProtocol):
696
697 @classmethod
698 def setUpClass(cls):
699 cls.type2test = c_coll.OrderedDict
700
701 def test_popitem(self):
702 d = self._empty_mapping()
703 self.assertRaises(KeyError, d.popitem)
704
705
706class PurePythonSubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
707
708 @classmethod
709 def setUpClass(cls):
710 class MyOrderedDict(py_coll.OrderedDict):
711 pass
712 cls.type2test = MyOrderedDict
713
714 def test_popitem(self):
715 d = self._empty_mapping()
716 self.assertRaises(KeyError, d.popitem)
717
718
719@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
720class CPythonSubclassMappingTests(mapping_tests.BasicTestMappingProtocol):
721
722 @classmethod
723 def setUpClass(cls):
724 class MyOrderedDict(c_coll.OrderedDict):
725 pass
726 cls.type2test = MyOrderedDict
Serhiy Storchaka33e7ea52015-11-25 17:09:01 +0200727
728 def test_popitem(self):
729 d = self._empty_mapping()
730 self.assertRaises(KeyError, d.popitem)
731
732
733if __name__ == "__main__":
734 unittest.main()