1import unittest 2from test import test_support 3 4import UserDict, random, string 5import gc, weakref 6import sys 7 8 9class DictTest(unittest.TestCase): 10 def test_constructor(self): 11 # calling built-in types without argument must return empty 12 self.assertEqual(dict(), {}) 13 self.assertIsNot(dict(), {}) 14 15 def test_literal_constructor(self): 16 # check literal constructor for different sized dicts 17 # (to exercise the BUILD_MAP oparg). 18 for n in (0, 1, 6, 256, 400): 19 items = [(''.join(random.sample(string.letters, 8)), i) 20 for i in range(n)] 21 random.shuffle(items) 22 formatted_items = ('{!r}: {:d}'.format(k, v) for k, v in items) 23 dictliteral = '{' + ', '.join(formatted_items) + '}' 24 self.assertEqual(eval(dictliteral), dict(items)) 25 26 def test_bool(self): 27 self.assertIs(not {}, True) 28 self.assertTrue({1: 2}) 29 self.assertIs(bool({}), False) 30 self.assertIs(bool({1: 2}), True) 31 32 def test_keys(self): 33 d = {} 34 self.assertEqual(d.keys(), []) 35 d = {'a': 1, 'b': 2} 36 k = d.keys() 37 self.assertEqual(set(k), {'a', 'b'}) 38 self.assertIn('a', k) 39 self.assertIn('b', k) 40 self.assertTrue(d.has_key('a')) 41 self.assertTrue(d.has_key('b')) 42 self.assertRaises(TypeError, d.keys, None) 43 44 def test_values(self): 45 d = {} 46 self.assertEqual(d.values(), []) 47 d = {1:2} 48 self.assertEqual(d.values(), [2]) 49 50 self.assertRaises(TypeError, d.values, None) 51 52 def test_items(self): 53 d = {} 54 self.assertEqual(d.items(), []) 55 56 d = {1:2} 57 self.assertEqual(d.items(), [(1, 2)]) 58 59 self.assertRaises(TypeError, d.items, None) 60 61 def test_has_key(self): 62 d = {} 63 self.assertFalse(d.has_key('a')) 64 d = {'a': 1, 'b': 2} 65 k = d.keys() 66 k.sort() 67 self.assertEqual(k, ['a', 'b']) 68 69 self.assertRaises(TypeError, d.has_key) 70 71 def test_contains(self): 72 d = {} 73 self.assertNotIn('a', d) 74 self.assertFalse('a' in d) 75 self.assertTrue('a' not in d) 76 d = {'a': 1, 'b': 2} 77 self.assertIn('a', d) 78 self.assertIn('b', d) 79 self.assertNotIn('c', d) 80 81 self.assertRaises(TypeError, d.__contains__) 82 83 def test_len(self): 84 d = {} 85 self.assertEqual(len(d), 0) 86 d = {'a': 1, 'b': 2} 87 self.assertEqual(len(d), 2) 88 89 def test_getitem(self): 90 d = {'a': 1, 'b': 2} 91 self.assertEqual(d['a'], 1) 92 self.assertEqual(d['b'], 2) 93 d['c'] = 3 94 d['a'] = 4 95 self.assertEqual(d['c'], 3) 96 self.assertEqual(d['a'], 4) 97 del d['b'] 98 self.assertEqual(d, {'a': 4, 'c': 3}) 99 100 self.assertRaises(TypeError, d.__getitem__) 101 102 class BadEq(object): 103 def __eq__(self, other): 104 raise Exc() 105 def __hash__(self): 106 return 24 107 108 d = {} 109 d[BadEq()] = 42 110 self.assertRaises(KeyError, d.__getitem__, 23) 111 112 class Exc(Exception): pass 113 114 class BadHash(object): 115 fail = False 116 def __hash__(self): 117 if self.fail: 118 raise Exc() 119 else: 120 return 42 121 122 x = BadHash() 123 d[x] = 42 124 x.fail = True 125 self.assertRaises(Exc, d.__getitem__, x) 126 127 def test_clear(self): 128 d = {1:1, 2:2, 3:3} 129 d.clear() 130 self.assertEqual(d, {}) 131 132 self.assertRaises(TypeError, d.clear, None) 133 134 def test_update(self): 135 d = {} 136 d.update({1:100}) 137 d.update({2:20}) 138 d.update({1:1, 2:2, 3:3}) 139 self.assertEqual(d, {1:1, 2:2, 3:3}) 140 141 d.update() 142 self.assertEqual(d, {1:1, 2:2, 3:3}) 143 144 self.assertRaises((TypeError, AttributeError), d.update, None) 145 146 class SimpleUserDict: 147 def __init__(self): 148 self.d = {1:1, 2:2, 3:3} 149 def keys(self): 150 return self.d.keys() 151 def __getitem__(self, i): 152 return self.d[i] 153 d.clear() 154 d.update(SimpleUserDict()) 155 self.assertEqual(d, {1:1, 2:2, 3:3}) 156 157 class Exc(Exception): pass 158 159 d.clear() 160 class FailingUserDict: 161 def keys(self): 162 raise Exc 163 self.assertRaises(Exc, d.update, FailingUserDict()) 164 165 class FailingUserDict: 166 def keys(self): 167 class BogonIter: 168 def __init__(self): 169 self.i = 1 170 def __iter__(self): 171 return self 172 def next(self): 173 if self.i: 174 self.i = 0 175 return 'a' 176 raise Exc 177 return BogonIter() 178 def __getitem__(self, key): 179 return key 180 self.assertRaises(Exc, d.update, FailingUserDict()) 181 182 class FailingUserDict: 183 def keys(self): 184 class BogonIter: 185 def __init__(self): 186 self.i = ord('a') 187 def __iter__(self): 188 return self 189 def next(self): 190 if self.i <= ord('z'): 191 rtn = chr(self.i) 192 self.i += 1 193 return rtn 194 raise StopIteration 195 return BogonIter() 196 def __getitem__(self, key): 197 raise Exc 198 self.assertRaises(Exc, d.update, FailingUserDict()) 199 200 class badseq(object): 201 def __iter__(self): 202 return self 203 def next(self): 204 raise Exc() 205 206 self.assertRaises(Exc, {}.update, badseq()) 207 208 self.assertRaises(ValueError, {}.update, [(1, 2, 3)]) 209 210 def test_fromkeys(self): 211 self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 212 d = {} 213 self.assertIsNot(d.fromkeys('abc'), d) 214 self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 215 self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) 216 self.assertEqual(d.fromkeys([]), {}) 217 def g(): 218 yield 1 219 self.assertEqual(d.fromkeys(g()), {1:None}) 220 self.assertRaises(TypeError, {}.fromkeys, 3) 221 class dictlike(dict): pass 222 self.assertEqual(dictlike.fromkeys('a'), {'a':None}) 223 self.assertEqual(dictlike().fromkeys('a'), {'a':None}) 224 self.assertIsInstance(dictlike.fromkeys('a'), dictlike) 225 self.assertIsInstance(dictlike().fromkeys('a'), dictlike) 226 class mydict(dict): 227 def __new__(cls): 228 return UserDict.UserDict() 229 ud = mydict.fromkeys('ab') 230 self.assertEqual(ud, {'a':None, 'b':None}) 231 self.assertIsInstance(ud, UserDict.UserDict) 232 self.assertRaises(TypeError, dict.fromkeys) 233 234 class Exc(Exception): pass 235 236 class baddict1(dict): 237 def __init__(self): 238 raise Exc() 239 240 self.assertRaises(Exc, baddict1.fromkeys, [1]) 241 242 class BadSeq(object): 243 def __iter__(self): 244 return self 245 def next(self): 246 raise Exc() 247 248 self.assertRaises(Exc, dict.fromkeys, BadSeq()) 249 250 class baddict2(dict): 251 def __setitem__(self, key, value): 252 raise Exc() 253 254 self.assertRaises(Exc, baddict2.fromkeys, [1]) 255 256 # test fast path for dictionary inputs 257 d = dict(zip(range(6), range(6))) 258 self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) 259 260 class baddict3(dict): 261 def __new__(cls): 262 return d 263 d = {i : i for i in range(10)} 264 res = d.copy() 265 res.update(a=None, b=None, c=None) 266 self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) 267 268 def test_copy(self): 269 d = {1:1, 2:2, 3:3} 270 self.assertEqual(d.copy(), {1:1, 2:2, 3:3}) 271 self.assertEqual({}.copy(), {}) 272 self.assertRaises(TypeError, d.copy, None) 273 274 def test_get(self): 275 d = {} 276 self.assertIs(d.get('c'), None) 277 self.assertEqual(d.get('c', 3), 3) 278 d = {'a': 1, 'b': 2} 279 self.assertIs(d.get('c'), None) 280 self.assertEqual(d.get('c', 3), 3) 281 self.assertEqual(d.get('a'), 1) 282 self.assertEqual(d.get('a', 3), 1) 283 self.assertRaises(TypeError, d.get) 284 self.assertRaises(TypeError, d.get, None, None, None) 285 286 def test_setdefault(self): 287 # dict.setdefault() 288 d = {} 289 self.assertIs(d.setdefault('key0'), None) 290 d.setdefault('key0', []) 291 self.assertIs(d.setdefault('key0'), None) 292 d.setdefault('key', []).append(3) 293 self.assertEqual(d['key'][0], 3) 294 d.setdefault('key', []).append(4) 295 self.assertEqual(len(d['key']), 2) 296 self.assertRaises(TypeError, d.setdefault) 297 298 class Exc(Exception): pass 299 300 class BadHash(object): 301 fail = False 302 def __hash__(self): 303 if self.fail: 304 raise Exc() 305 else: 306 return 42 307 308 x = BadHash() 309 d[x] = 42 310 x.fail = True 311 self.assertRaises(Exc, d.setdefault, x, []) 312 313 def test_setdefault_atomic(self): 314 # Issue #13521: setdefault() calls __hash__ and __eq__ only once. 315 class Hashed(object): 316 def __init__(self): 317 self.hash_count = 0 318 self.eq_count = 0 319 def __hash__(self): 320 self.hash_count += 1 321 return 42 322 def __eq__(self, other): 323 self.eq_count += 1 324 return id(self) == id(other) 325 hashed1 = Hashed() 326 y = {hashed1: 5} 327 hashed2 = Hashed() 328 y.setdefault(hashed2, []) 329 self.assertEqual(hashed1.hash_count, 1) 330 self.assertEqual(hashed2.hash_count, 1) 331 self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1) 332 333 def test_popitem(self): 334 # dict.popitem() 335 for copymode in -1, +1: 336 # -1: b has same structure as a 337 # +1: b is a.copy() 338 for log2size in range(12): 339 size = 2**log2size 340 a = {} 341 b = {} 342 for i in range(size): 343 a[repr(i)] = i 344 if copymode < 0: 345 b[repr(i)] = i 346 if copymode > 0: 347 b = a.copy() 348 for i in range(size): 349 ka, va = ta = a.popitem() 350 self.assertEqual(va, int(ka)) 351 kb, vb = tb = b.popitem() 352 self.assertEqual(vb, int(kb)) 353 self.assertFalse(copymode < 0 and ta != tb) 354 self.assertFalse(a) 355 self.assertFalse(b) 356 357 d = {} 358 self.assertRaises(KeyError, d.popitem) 359 360 def test_pop(self): 361 # Tests for pop with specified key 362 d = {} 363 k, v = 'abc', 'def' 364 d[k] = v 365 self.assertRaises(KeyError, d.pop, 'ghi') 366 367 self.assertEqual(d.pop(k), v) 368 self.assertEqual(len(d), 0) 369 370 self.assertRaises(KeyError, d.pop, k) 371 372 # verify longs/ints get same value when key > 32 bits 373 # (for 64-bit archs). See SF bug #689659. 374 x = 4503599627370496L 375 y = 4503599627370496 376 h = {x: 'anything', y: 'something else'} 377 self.assertEqual(h[x], h[y]) 378 379 self.assertEqual(d.pop(k, v), v) 380 d[k] = v 381 self.assertEqual(d.pop(k, 1), v) 382 383 self.assertRaises(TypeError, d.pop) 384 385 class Exc(Exception): pass 386 387 class BadHash(object): 388 fail = False 389 def __hash__(self): 390 if self.fail: 391 raise Exc() 392 else: 393 return 42 394 395 x = BadHash() 396 d[x] = 42 397 x.fail = True 398 self.assertRaises(Exc, d.pop, x) 399 400 def test_mutatingiteration(self): 401 # changing dict size during iteration 402 d = {} 403 d[1] = 1 404 with self.assertRaises(RuntimeError): 405 for i in d: 406 d[i+1] = 1 407 408 def test_repr(self): 409 d = {} 410 self.assertEqual(repr(d), '{}') 411 d[1] = 2 412 self.assertEqual(repr(d), '{1: 2}') 413 d = {} 414 d[1] = d 415 self.assertEqual(repr(d), '{1: {...}}') 416 417 class Exc(Exception): pass 418 419 class BadRepr(object): 420 def __repr__(self): 421 raise Exc() 422 423 d = {1: BadRepr()} 424 self.assertRaises(Exc, repr, d) 425 426 def test_repr_deep(self): 427 d = {} 428 for i in range(sys.getrecursionlimit() + 100): 429 d = {1: d} 430 self.assertRaises(RuntimeError, repr, d) 431 432 def test_le(self): 433 self.assertFalse({} < {}) 434 self.assertFalse({1: 2} < {1L: 2L}) 435 436 class Exc(Exception): pass 437 438 class BadCmp(object): 439 def __eq__(self, other): 440 raise Exc() 441 def __hash__(self): 442 return 42 443 444 d1 = {BadCmp(): 1} 445 d2 = {1: 1} 446 447 with self.assertRaises(Exc): 448 d1 < d2 449 450 def test_missing(self): 451 # Make sure dict doesn't have a __missing__ method 452 self.assertFalse(hasattr(dict, "__missing__")) 453 self.assertFalse(hasattr({}, "__missing__")) 454 # Test several cases: 455 # (D) subclass defines __missing__ method returning a value 456 # (E) subclass defines __missing__ method raising RuntimeError 457 # (F) subclass sets __missing__ instance variable (no effect) 458 # (G) subclass doesn't define __missing__ at all 459 class D(dict): 460 def __missing__(self, key): 461 return 42 462 d = D({1: 2, 3: 4}) 463 self.assertEqual(d[1], 2) 464 self.assertEqual(d[3], 4) 465 self.assertNotIn(2, d) 466 self.assertNotIn(2, d.keys()) 467 self.assertEqual(d[2], 42) 468 469 class E(dict): 470 def __missing__(self, key): 471 raise RuntimeError(key) 472 e = E() 473 with self.assertRaises(RuntimeError) as c: 474 e[42] 475 self.assertEqual(c.exception.args, (42,)) 476 477 class F(dict): 478 def __init__(self): 479 # An instance variable __missing__ should have no effect 480 self.__missing__ = lambda key: None 481 f = F() 482 with self.assertRaises(KeyError) as c: 483 f[42] 484 self.assertEqual(c.exception.args, (42,)) 485 486 class G(dict): 487 pass 488 g = G() 489 with self.assertRaises(KeyError) as c: 490 g[42] 491 self.assertEqual(c.exception.args, (42,)) 492 493 def test_tuple_keyerror(self): 494 # SF #1576657 495 d = {} 496 with self.assertRaises(KeyError) as c: 497 d[(1,)] 498 self.assertEqual(c.exception.args, ((1,),)) 499 500 def test_bad_key(self): 501 # Dictionary lookups should fail if __cmp__() raises an exception. 502 class CustomException(Exception): 503 pass 504 505 class BadDictKey: 506 def __hash__(self): 507 return hash(self.__class__) 508 509 def __cmp__(self, other): 510 if isinstance(other, self.__class__): 511 raise CustomException 512 return other 513 514 d = {} 515 x1 = BadDictKey() 516 x2 = BadDictKey() 517 d[x1] = 1 518 for stmt in ['d[x2] = 2', 519 'z = d[x2]', 520 'x2 in d', 521 'd.has_key(x2)', 522 'd.get(x2)', 523 'd.setdefault(x2, 42)', 524 'd.pop(x2)', 525 'd.update({x2: 2})']: 526 with self.assertRaises(CustomException): 527 exec stmt in locals() 528 529 def test_resize1(self): 530 # Dict resizing bug, found by Jack Jansen in 2.2 CVS development. 531 # This version got an assert failure in debug build, infinite loop in 532 # release build. Unfortunately, provoking this kind of stuff requires 533 # a mix of inserts and deletes hitting exactly the right hash codes in 534 # exactly the right order, and I can't think of a randomized approach 535 # that would be *likely* to hit a failing case in reasonable time. 536 537 d = {} 538 for i in range(5): 539 d[i] = i 540 for i in range(5): 541 del d[i] 542 for i in range(5, 9): # i==8 was the problem 543 d[i] = i 544 545 def test_resize2(self): 546 # Another dict resizing bug (SF bug #1456209). 547 # This caused Segmentation faults or Illegal instructions. 548 549 class X(object): 550 def __hash__(self): 551 return 5 552 def __eq__(self, other): 553 if resizing: 554 d.clear() 555 return False 556 d = {} 557 resizing = False 558 d[X()] = 1 559 d[X()] = 2 560 d[X()] = 3 561 d[X()] = 4 562 d[X()] = 5 563 # now trigger a resize 564 resizing = True 565 d[9] = 6 566 567 def test_empty_presized_dict_in_freelist(self): 568 # Bug #3537: if an empty but presized dict with a size larger 569 # than 7 was in the freelist, it triggered an assertion failure 570 with self.assertRaises(ZeroDivisionError): 571 d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None, 572 'f': None, 'g': None, 'h': None} 573 d = {} 574 575 def test_container_iterator(self): 576 # Bug #3680: tp_traverse was not implemented for dictiter objects 577 class C(object): 578 pass 579 iterators = (dict.iteritems, dict.itervalues, dict.iterkeys) 580 for i in iterators: 581 obj = C() 582 ref = weakref.ref(obj) 583 container = {obj: 1} 584 obj.x = i(container) 585 del obj, container 586 gc.collect() 587 self.assertIs(ref(), None, "Cycle was not collected") 588 589 def _not_tracked(self, t): 590 # Nested containers can take several collections to untrack 591 gc.collect() 592 gc.collect() 593 self.assertFalse(gc.is_tracked(t), t) 594 595 def _tracked(self, t): 596 self.assertTrue(gc.is_tracked(t), t) 597 gc.collect() 598 gc.collect() 599 self.assertTrue(gc.is_tracked(t), t) 600 601 @test_support.cpython_only 602 def test_track_literals(self): 603 # Test GC-optimization of dict literals 604 x, y, z, w = 1.5, "a", (1, None), [] 605 606 self._not_tracked({}) 607 self._not_tracked({x:(), y:x, z:1}) 608 self._not_tracked({1: "a", "b": 2}) 609 self._not_tracked({1: 2, (None, True, False, ()): int}) 610 self._not_tracked({1: object()}) 611 612 # Dicts with mutable elements are always tracked, even if those 613 # elements are not tracked right now. 614 self._tracked({1: []}) 615 self._tracked({1: ([],)}) 616 self._tracked({1: {}}) 617 self._tracked({1: set()}) 618 619 @test_support.cpython_only 620 def test_track_dynamic(self): 621 # Test GC-optimization of dynamically-created dicts 622 class MyObject(object): 623 pass 624 x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject() 625 626 d = dict() 627 self._not_tracked(d) 628 d[1] = "a" 629 self._not_tracked(d) 630 d[y] = 2 631 self._not_tracked(d) 632 d[z] = 3 633 self._not_tracked(d) 634 self._not_tracked(d.copy()) 635 d[4] = w 636 self._tracked(d) 637 self._tracked(d.copy()) 638 d[4] = None 639 self._not_tracked(d) 640 self._not_tracked(d.copy()) 641 642 # dd isn't tracked right now, but it may mutate and therefore d 643 # which contains it must be tracked. 644 d = dict() 645 dd = dict() 646 d[1] = dd 647 self._not_tracked(dd) 648 self._tracked(d) 649 dd[1] = d 650 self._tracked(dd) 651 652 d = dict.fromkeys([x, y, z]) 653 self._not_tracked(d) 654 dd = dict() 655 dd.update(d) 656 self._not_tracked(dd) 657 d = dict.fromkeys([x, y, z, o]) 658 self._tracked(d) 659 dd = dict() 660 dd.update(d) 661 self._tracked(dd) 662 663 d = dict(x=x, y=y, z=z) 664 self._not_tracked(d) 665 d = dict(x=x, y=y, z=z, w=w) 666 self._tracked(d) 667 d = dict() 668 d.update(x=x, y=y, z=z) 669 self._not_tracked(d) 670 d.update(w=w) 671 self._tracked(d) 672 673 d = dict([(x, y), (z, 1)]) 674 self._not_tracked(d) 675 d = dict([(x, y), (z, w)]) 676 self._tracked(d) 677 d = dict() 678 d.update([(x, y), (z, 1)]) 679 self._not_tracked(d) 680 d.update([(x, y), (z, w)]) 681 self._tracked(d) 682 683 @test_support.cpython_only 684 def test_track_subtypes(self): 685 # Dict subtypes are always tracked 686 class MyDict(dict): 687 pass 688 self._tracked(MyDict()) 689 690 691 def test_free_after_iterating(self): 692 test_support.check_free_after_iterating(self, iter, dict) 693 test_support.check_free_after_iterating(self, lambda d: d.iterkeys(), dict) 694 test_support.check_free_after_iterating(self, lambda d: d.itervalues(), dict) 695 test_support.check_free_after_iterating(self, lambda d: d.iteritems(), dict) 696 test_support.check_free_after_iterating(self, lambda d: iter(d.viewkeys()), dict) 697 test_support.check_free_after_iterating(self, lambda d: iter(d.viewvalues()), dict) 698 test_support.check_free_after_iterating(self, lambda d: iter(d.viewitems()), dict) 699 700 def test_equal_operator_modifying_operand(self): 701 # test fix for seg fault reported in issue 27945 part 3. 702 class X(object): 703 def __del__(self): 704 dict_b.clear() 705 706 def __eq__(self, other): 707 dict_a.clear() 708 return True 709 710 def __hash__(self): 711 return 13 712 713 dict_a = {X(): 0} 714 dict_b = {X(): X()} 715 self.assertTrue(dict_a == dict_b) 716 717 def test_fromkeys_operator_modifying_dict_operand(self): 718 # test fix for seg fault reported in issue 27945 part 4a. 719 class X(int): 720 def __hash__(self): 721 return 13 722 723 def __eq__(self, other): 724 if len(d) > 1: 725 d.clear() 726 return False 727 728 d = {} # this is required to exist so that d can be constructed! 729 d = {X(1): 1, X(2): 2} 730 try: 731 dict.fromkeys(d) # shouldn't crash 732 except RuntimeError: # implementation defined 733 pass 734 735 def test_fromkeys_operator_modifying_set_operand(self): 736 # test fix for seg fault reported in issue 27945 part 4b. 737 class X(int): 738 def __hash__(self): 739 return 13 740 741 def __eq__(self, other): 742 if len(d) > 1: 743 d.clear() 744 return False 745 746 d = {} # this is required to exist so that d can be constructed! 747 d = {X(1), X(2)} 748 try: 749 dict.fromkeys(d) # shouldn't crash 750 except RuntimeError: # implementation defined 751 pass 752 753 def test_dictitems_contains_use_after_free(self): 754 class X(object): 755 def __eq__(self, other): 756 d.clear() 757 return NotImplemented 758 759 __hash__ = object.__hash__ # silence Py3k warning 760 761 d = {0: set()} 762 try: 763 (0, X()) in d.iteritems() # shouldn't crash 764 except RuntimeError: # implementation defined 765 pass 766 767 def test_init_use_after_free(self): 768 class X(object): 769 def __hash__(self): 770 pair[:] = [] 771 return 13 772 773 pair = [X(), 123] 774 dict([pair]) 775 776 def test_oob_indexing_dictiter_iternextitem(self): 777 class X(int): 778 def __del__(self): 779 d.clear() 780 781 d = {i: X(i) for i in range(8)} 782 783 def iter_and_mutate(): 784 for result in d.iteritems(): 785 if result[0] == 2: 786 d[2] = None # free d[2] --> X(2).__del__ was called 787 788 self.assertRaises(RuntimeError, iter_and_mutate) 789 790 791from test import mapping_tests 792 793class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): 794 type2test = dict 795 796class Dict(dict): 797 pass 798 799class SubclassMappingTests(mapping_tests.BasicTestMappingProtocol): 800 type2test = Dict 801 802def test_main(): 803 with test_support.check_py3k_warnings( 804 ('dict(.has_key..| inequality comparisons) not supported in 3.x', 805 DeprecationWarning)): 806 test_support.run_unittest( 807 DictTest, 808 GeneralMappingTests, 809 SubclassMappingTests, 810 ) 811 812if __name__ == "__main__": 813 test_main() 814