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