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