17db96d56Sopenharmony_ciimport collections 27db96d56Sopenharmony_ciimport collections.abc 37db96d56Sopenharmony_ciimport gc 47db96d56Sopenharmony_ciimport pickle 57db96d56Sopenharmony_ciimport random 67db96d56Sopenharmony_ciimport string 77db96d56Sopenharmony_ciimport sys 87db96d56Sopenharmony_ciimport unittest 97db96d56Sopenharmony_ciimport weakref 107db96d56Sopenharmony_cifrom test import support 117db96d56Sopenharmony_cifrom test.support import import_helper 127db96d56Sopenharmony_ci 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ciclass DictTest(unittest.TestCase): 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ci def test_invalid_keyword_arguments(self): 177db96d56Sopenharmony_ci class Custom(dict): 187db96d56Sopenharmony_ci pass 197db96d56Sopenharmony_ci for invalid in {1 : 2}, Custom({1 : 2}): 207db96d56Sopenharmony_ci with self.assertRaises(TypeError): 217db96d56Sopenharmony_ci dict(**invalid) 227db96d56Sopenharmony_ci with self.assertRaises(TypeError): 237db96d56Sopenharmony_ci {}.update(**invalid) 247db96d56Sopenharmony_ci 257db96d56Sopenharmony_ci def test_constructor(self): 267db96d56Sopenharmony_ci # calling built-in types without argument must return empty 277db96d56Sopenharmony_ci self.assertEqual(dict(), {}) 287db96d56Sopenharmony_ci self.assertIsNot(dict(), {}) 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ci def test_literal_constructor(self): 317db96d56Sopenharmony_ci # check literal constructor for different sized dicts 327db96d56Sopenharmony_ci # (to exercise the BUILD_MAP oparg). 337db96d56Sopenharmony_ci for n in (0, 1, 6, 256, 400): 347db96d56Sopenharmony_ci items = [(''.join(random.sample(string.ascii_letters, 8)), i) 357db96d56Sopenharmony_ci for i in range(n)] 367db96d56Sopenharmony_ci random.shuffle(items) 377db96d56Sopenharmony_ci formatted_items = ('{!r}: {:d}'.format(k, v) for k, v in items) 387db96d56Sopenharmony_ci dictliteral = '{' + ', '.join(formatted_items) + '}' 397db96d56Sopenharmony_ci self.assertEqual(eval(dictliteral), dict(items)) 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci def test_merge_operator(self): 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci a = {0: 0, 1: 1, 2: 1} 447db96d56Sopenharmony_ci b = {1: 1, 2: 2, 3: 3} 457db96d56Sopenharmony_ci 467db96d56Sopenharmony_ci c = a.copy() 477db96d56Sopenharmony_ci c |= b 487db96d56Sopenharmony_ci 497db96d56Sopenharmony_ci self.assertEqual(a | b, {0: 0, 1: 1, 2: 2, 3: 3}) 507db96d56Sopenharmony_ci self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3}) 517db96d56Sopenharmony_ci 527db96d56Sopenharmony_ci c = b.copy() 537db96d56Sopenharmony_ci c |= a 547db96d56Sopenharmony_ci 557db96d56Sopenharmony_ci self.assertEqual(b | a, {1: 1, 2: 1, 3: 3, 0: 0}) 567db96d56Sopenharmony_ci self.assertEqual(c, {1: 1, 2: 1, 3: 3, 0: 0}) 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci c = a.copy() 597db96d56Sopenharmony_ci c |= [(1, 1), (2, 2), (3, 3)] 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3}) 627db96d56Sopenharmony_ci 637db96d56Sopenharmony_ci self.assertIs(a.__or__(None), NotImplemented) 647db96d56Sopenharmony_ci self.assertIs(a.__or__(()), NotImplemented) 657db96d56Sopenharmony_ci self.assertIs(a.__or__("BAD"), NotImplemented) 667db96d56Sopenharmony_ci self.assertIs(a.__or__(""), NotImplemented) 677db96d56Sopenharmony_ci 687db96d56Sopenharmony_ci self.assertRaises(TypeError, a.__ior__, None) 697db96d56Sopenharmony_ci self.assertEqual(a.__ior__(()), {0: 0, 1: 1, 2: 1}) 707db96d56Sopenharmony_ci self.assertRaises(ValueError, a.__ior__, "BAD") 717db96d56Sopenharmony_ci self.assertEqual(a.__ior__(""), {0: 0, 1: 1, 2: 1}) 727db96d56Sopenharmony_ci 737db96d56Sopenharmony_ci def test_bool(self): 747db96d56Sopenharmony_ci self.assertIs(not {}, True) 757db96d56Sopenharmony_ci self.assertTrue({1: 2}) 767db96d56Sopenharmony_ci self.assertIs(bool({}), False) 777db96d56Sopenharmony_ci self.assertIs(bool({1: 2}), True) 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci def test_keys(self): 807db96d56Sopenharmony_ci d = {} 817db96d56Sopenharmony_ci self.assertEqual(set(d.keys()), set()) 827db96d56Sopenharmony_ci d = {'a': 1, 'b': 2} 837db96d56Sopenharmony_ci k = d.keys() 847db96d56Sopenharmony_ci self.assertEqual(set(k), {'a', 'b'}) 857db96d56Sopenharmony_ci self.assertIn('a', k) 867db96d56Sopenharmony_ci self.assertIn('b', k) 877db96d56Sopenharmony_ci self.assertIn('a', d) 887db96d56Sopenharmony_ci self.assertIn('b', d) 897db96d56Sopenharmony_ci self.assertRaises(TypeError, d.keys, None) 907db96d56Sopenharmony_ci self.assertEqual(repr(dict(a=1).keys()), "dict_keys(['a'])") 917db96d56Sopenharmony_ci 927db96d56Sopenharmony_ci def test_values(self): 937db96d56Sopenharmony_ci d = {} 947db96d56Sopenharmony_ci self.assertEqual(set(d.values()), set()) 957db96d56Sopenharmony_ci d = {1:2} 967db96d56Sopenharmony_ci self.assertEqual(set(d.values()), {2}) 977db96d56Sopenharmony_ci self.assertRaises(TypeError, d.values, None) 987db96d56Sopenharmony_ci self.assertEqual(repr(dict(a=1).values()), "dict_values([1])") 997db96d56Sopenharmony_ci 1007db96d56Sopenharmony_ci def test_items(self): 1017db96d56Sopenharmony_ci d = {} 1027db96d56Sopenharmony_ci self.assertEqual(set(d.items()), set()) 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci d = {1:2} 1057db96d56Sopenharmony_ci self.assertEqual(set(d.items()), {(1, 2)}) 1067db96d56Sopenharmony_ci self.assertRaises(TypeError, d.items, None) 1077db96d56Sopenharmony_ci self.assertEqual(repr(dict(a=1).items()), "dict_items([('a', 1)])") 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci def test_views_mapping(self): 1107db96d56Sopenharmony_ci mappingproxy = type(type.__dict__) 1117db96d56Sopenharmony_ci class Dict(dict): 1127db96d56Sopenharmony_ci pass 1137db96d56Sopenharmony_ci for cls in [dict, Dict]: 1147db96d56Sopenharmony_ci d = cls() 1157db96d56Sopenharmony_ci m1 = d.keys().mapping 1167db96d56Sopenharmony_ci m2 = d.values().mapping 1177db96d56Sopenharmony_ci m3 = d.items().mapping 1187db96d56Sopenharmony_ci 1197db96d56Sopenharmony_ci for m in [m1, m2, m3]: 1207db96d56Sopenharmony_ci self.assertIsInstance(m, mappingproxy) 1217db96d56Sopenharmony_ci self.assertEqual(m, d) 1227db96d56Sopenharmony_ci 1237db96d56Sopenharmony_ci d["foo"] = "bar" 1247db96d56Sopenharmony_ci 1257db96d56Sopenharmony_ci for m in [m1, m2, m3]: 1267db96d56Sopenharmony_ci self.assertIsInstance(m, mappingproxy) 1277db96d56Sopenharmony_ci self.assertEqual(m, d) 1287db96d56Sopenharmony_ci 1297db96d56Sopenharmony_ci def test_contains(self): 1307db96d56Sopenharmony_ci d = {} 1317db96d56Sopenharmony_ci self.assertNotIn('a', d) 1327db96d56Sopenharmony_ci self.assertFalse('a' in d) 1337db96d56Sopenharmony_ci self.assertTrue('a' not in d) 1347db96d56Sopenharmony_ci d = {'a': 1, 'b': 2} 1357db96d56Sopenharmony_ci self.assertIn('a', d) 1367db96d56Sopenharmony_ci self.assertIn('b', d) 1377db96d56Sopenharmony_ci self.assertNotIn('c', d) 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci self.assertRaises(TypeError, d.__contains__) 1407db96d56Sopenharmony_ci 1417db96d56Sopenharmony_ci def test_len(self): 1427db96d56Sopenharmony_ci d = {} 1437db96d56Sopenharmony_ci self.assertEqual(len(d), 0) 1447db96d56Sopenharmony_ci d = {'a': 1, 'b': 2} 1457db96d56Sopenharmony_ci self.assertEqual(len(d), 2) 1467db96d56Sopenharmony_ci 1477db96d56Sopenharmony_ci def test_getitem(self): 1487db96d56Sopenharmony_ci d = {'a': 1, 'b': 2} 1497db96d56Sopenharmony_ci self.assertEqual(d['a'], 1) 1507db96d56Sopenharmony_ci self.assertEqual(d['b'], 2) 1517db96d56Sopenharmony_ci d['c'] = 3 1527db96d56Sopenharmony_ci d['a'] = 4 1537db96d56Sopenharmony_ci self.assertEqual(d['c'], 3) 1547db96d56Sopenharmony_ci self.assertEqual(d['a'], 4) 1557db96d56Sopenharmony_ci del d['b'] 1567db96d56Sopenharmony_ci self.assertEqual(d, {'a': 4, 'c': 3}) 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_ci self.assertRaises(TypeError, d.__getitem__) 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci class BadEq(object): 1617db96d56Sopenharmony_ci def __eq__(self, other): 1627db96d56Sopenharmony_ci raise Exc() 1637db96d56Sopenharmony_ci def __hash__(self): 1647db96d56Sopenharmony_ci return 24 1657db96d56Sopenharmony_ci 1667db96d56Sopenharmony_ci d = {} 1677db96d56Sopenharmony_ci d[BadEq()] = 42 1687db96d56Sopenharmony_ci self.assertRaises(KeyError, d.__getitem__, 23) 1697db96d56Sopenharmony_ci 1707db96d56Sopenharmony_ci class Exc(Exception): pass 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci class BadHash(object): 1737db96d56Sopenharmony_ci fail = False 1747db96d56Sopenharmony_ci def __hash__(self): 1757db96d56Sopenharmony_ci if self.fail: 1767db96d56Sopenharmony_ci raise Exc() 1777db96d56Sopenharmony_ci else: 1787db96d56Sopenharmony_ci return 42 1797db96d56Sopenharmony_ci 1807db96d56Sopenharmony_ci x = BadHash() 1817db96d56Sopenharmony_ci d[x] = 42 1827db96d56Sopenharmony_ci x.fail = True 1837db96d56Sopenharmony_ci self.assertRaises(Exc, d.__getitem__, x) 1847db96d56Sopenharmony_ci 1857db96d56Sopenharmony_ci def test_clear(self): 1867db96d56Sopenharmony_ci d = {1:1, 2:2, 3:3} 1877db96d56Sopenharmony_ci d.clear() 1887db96d56Sopenharmony_ci self.assertEqual(d, {}) 1897db96d56Sopenharmony_ci 1907db96d56Sopenharmony_ci self.assertRaises(TypeError, d.clear, None) 1917db96d56Sopenharmony_ci 1927db96d56Sopenharmony_ci def test_update(self): 1937db96d56Sopenharmony_ci d = {} 1947db96d56Sopenharmony_ci d.update({1:100}) 1957db96d56Sopenharmony_ci d.update({2:20}) 1967db96d56Sopenharmony_ci d.update({1:1, 2:2, 3:3}) 1977db96d56Sopenharmony_ci self.assertEqual(d, {1:1, 2:2, 3:3}) 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_ci d.update() 2007db96d56Sopenharmony_ci self.assertEqual(d, {1:1, 2:2, 3:3}) 2017db96d56Sopenharmony_ci 2027db96d56Sopenharmony_ci self.assertRaises((TypeError, AttributeError), d.update, None) 2037db96d56Sopenharmony_ci 2047db96d56Sopenharmony_ci class SimpleUserDict: 2057db96d56Sopenharmony_ci def __init__(self): 2067db96d56Sopenharmony_ci self.d = {1:1, 2:2, 3:3} 2077db96d56Sopenharmony_ci def keys(self): 2087db96d56Sopenharmony_ci return self.d.keys() 2097db96d56Sopenharmony_ci def __getitem__(self, i): 2107db96d56Sopenharmony_ci return self.d[i] 2117db96d56Sopenharmony_ci d.clear() 2127db96d56Sopenharmony_ci d.update(SimpleUserDict()) 2137db96d56Sopenharmony_ci self.assertEqual(d, {1:1, 2:2, 3:3}) 2147db96d56Sopenharmony_ci 2157db96d56Sopenharmony_ci class Exc(Exception): pass 2167db96d56Sopenharmony_ci 2177db96d56Sopenharmony_ci d.clear() 2187db96d56Sopenharmony_ci class FailingUserDict: 2197db96d56Sopenharmony_ci def keys(self): 2207db96d56Sopenharmony_ci raise Exc 2217db96d56Sopenharmony_ci self.assertRaises(Exc, d.update, FailingUserDict()) 2227db96d56Sopenharmony_ci 2237db96d56Sopenharmony_ci class FailingUserDict: 2247db96d56Sopenharmony_ci def keys(self): 2257db96d56Sopenharmony_ci class BogonIter: 2267db96d56Sopenharmony_ci def __init__(self): 2277db96d56Sopenharmony_ci self.i = 1 2287db96d56Sopenharmony_ci def __iter__(self): 2297db96d56Sopenharmony_ci return self 2307db96d56Sopenharmony_ci def __next__(self): 2317db96d56Sopenharmony_ci if self.i: 2327db96d56Sopenharmony_ci self.i = 0 2337db96d56Sopenharmony_ci return 'a' 2347db96d56Sopenharmony_ci raise Exc 2357db96d56Sopenharmony_ci return BogonIter() 2367db96d56Sopenharmony_ci def __getitem__(self, key): 2377db96d56Sopenharmony_ci return key 2387db96d56Sopenharmony_ci self.assertRaises(Exc, d.update, FailingUserDict()) 2397db96d56Sopenharmony_ci 2407db96d56Sopenharmony_ci class FailingUserDict: 2417db96d56Sopenharmony_ci def keys(self): 2427db96d56Sopenharmony_ci class BogonIter: 2437db96d56Sopenharmony_ci def __init__(self): 2447db96d56Sopenharmony_ci self.i = ord('a') 2457db96d56Sopenharmony_ci def __iter__(self): 2467db96d56Sopenharmony_ci return self 2477db96d56Sopenharmony_ci def __next__(self): 2487db96d56Sopenharmony_ci if self.i <= ord('z'): 2497db96d56Sopenharmony_ci rtn = chr(self.i) 2507db96d56Sopenharmony_ci self.i += 1 2517db96d56Sopenharmony_ci return rtn 2527db96d56Sopenharmony_ci raise StopIteration 2537db96d56Sopenharmony_ci return BogonIter() 2547db96d56Sopenharmony_ci def __getitem__(self, key): 2557db96d56Sopenharmony_ci raise Exc 2567db96d56Sopenharmony_ci self.assertRaises(Exc, d.update, FailingUserDict()) 2577db96d56Sopenharmony_ci 2587db96d56Sopenharmony_ci class badseq(object): 2597db96d56Sopenharmony_ci def __iter__(self): 2607db96d56Sopenharmony_ci return self 2617db96d56Sopenharmony_ci def __next__(self): 2627db96d56Sopenharmony_ci raise Exc() 2637db96d56Sopenharmony_ci 2647db96d56Sopenharmony_ci self.assertRaises(Exc, {}.update, badseq()) 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci self.assertRaises(ValueError, {}.update, [(1, 2, 3)]) 2677db96d56Sopenharmony_ci 2687db96d56Sopenharmony_ci def test_fromkeys(self): 2697db96d56Sopenharmony_ci self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 2707db96d56Sopenharmony_ci d = {} 2717db96d56Sopenharmony_ci self.assertIsNot(d.fromkeys('abc'), d) 2727db96d56Sopenharmony_ci self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) 2737db96d56Sopenharmony_ci self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) 2747db96d56Sopenharmony_ci self.assertEqual(d.fromkeys([]), {}) 2757db96d56Sopenharmony_ci def g(): 2767db96d56Sopenharmony_ci yield 1 2777db96d56Sopenharmony_ci self.assertEqual(d.fromkeys(g()), {1:None}) 2787db96d56Sopenharmony_ci self.assertRaises(TypeError, {}.fromkeys, 3) 2797db96d56Sopenharmony_ci class dictlike(dict): pass 2807db96d56Sopenharmony_ci self.assertEqual(dictlike.fromkeys('a'), {'a':None}) 2817db96d56Sopenharmony_ci self.assertEqual(dictlike().fromkeys('a'), {'a':None}) 2827db96d56Sopenharmony_ci self.assertIsInstance(dictlike.fromkeys('a'), dictlike) 2837db96d56Sopenharmony_ci self.assertIsInstance(dictlike().fromkeys('a'), dictlike) 2847db96d56Sopenharmony_ci class mydict(dict): 2857db96d56Sopenharmony_ci def __new__(cls): 2867db96d56Sopenharmony_ci return collections.UserDict() 2877db96d56Sopenharmony_ci ud = mydict.fromkeys('ab') 2887db96d56Sopenharmony_ci self.assertEqual(ud, {'a':None, 'b':None}) 2897db96d56Sopenharmony_ci self.assertIsInstance(ud, collections.UserDict) 2907db96d56Sopenharmony_ci self.assertRaises(TypeError, dict.fromkeys) 2917db96d56Sopenharmony_ci 2927db96d56Sopenharmony_ci class Exc(Exception): pass 2937db96d56Sopenharmony_ci 2947db96d56Sopenharmony_ci class baddict1(dict): 2957db96d56Sopenharmony_ci def __init__(self): 2967db96d56Sopenharmony_ci raise Exc() 2977db96d56Sopenharmony_ci 2987db96d56Sopenharmony_ci self.assertRaises(Exc, baddict1.fromkeys, [1]) 2997db96d56Sopenharmony_ci 3007db96d56Sopenharmony_ci class BadSeq(object): 3017db96d56Sopenharmony_ci def __iter__(self): 3027db96d56Sopenharmony_ci return self 3037db96d56Sopenharmony_ci def __next__(self): 3047db96d56Sopenharmony_ci raise Exc() 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci self.assertRaises(Exc, dict.fromkeys, BadSeq()) 3077db96d56Sopenharmony_ci 3087db96d56Sopenharmony_ci class baddict2(dict): 3097db96d56Sopenharmony_ci def __setitem__(self, key, value): 3107db96d56Sopenharmony_ci raise Exc() 3117db96d56Sopenharmony_ci 3127db96d56Sopenharmony_ci self.assertRaises(Exc, baddict2.fromkeys, [1]) 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci # test fast path for dictionary inputs 3157db96d56Sopenharmony_ci d = dict(zip(range(6), range(6))) 3167db96d56Sopenharmony_ci self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) 3177db96d56Sopenharmony_ci 3187db96d56Sopenharmony_ci class baddict3(dict): 3197db96d56Sopenharmony_ci def __new__(cls): 3207db96d56Sopenharmony_ci return d 3217db96d56Sopenharmony_ci d = {i : i for i in range(10)} 3227db96d56Sopenharmony_ci res = d.copy() 3237db96d56Sopenharmony_ci res.update(a=None, b=None, c=None) 3247db96d56Sopenharmony_ci self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci def test_copy(self): 3277db96d56Sopenharmony_ci d = {1: 1, 2: 2, 3: 3} 3287db96d56Sopenharmony_ci self.assertIsNot(d.copy(), d) 3297db96d56Sopenharmony_ci self.assertEqual(d.copy(), d) 3307db96d56Sopenharmony_ci self.assertEqual(d.copy(), {1: 1, 2: 2, 3: 3}) 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci copy = d.copy() 3337db96d56Sopenharmony_ci d[4] = 4 3347db96d56Sopenharmony_ci self.assertNotEqual(copy, d) 3357db96d56Sopenharmony_ci 3367db96d56Sopenharmony_ci self.assertEqual({}.copy(), {}) 3377db96d56Sopenharmony_ci self.assertRaises(TypeError, d.copy, None) 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci def test_copy_fuzz(self): 3407db96d56Sopenharmony_ci for dict_size in [10, 100, 1000, 10000, 100000]: 3417db96d56Sopenharmony_ci dict_size = random.randrange( 3427db96d56Sopenharmony_ci dict_size // 2, dict_size + dict_size // 2) 3437db96d56Sopenharmony_ci with self.subTest(dict_size=dict_size): 3447db96d56Sopenharmony_ci d = {} 3457db96d56Sopenharmony_ci for i in range(dict_size): 3467db96d56Sopenharmony_ci d[i] = i 3477db96d56Sopenharmony_ci 3487db96d56Sopenharmony_ci d2 = d.copy() 3497db96d56Sopenharmony_ci self.assertIsNot(d2, d) 3507db96d56Sopenharmony_ci self.assertEqual(d, d2) 3517db96d56Sopenharmony_ci d2['key'] = 'value' 3527db96d56Sopenharmony_ci self.assertNotEqual(d, d2) 3537db96d56Sopenharmony_ci self.assertEqual(len(d2), len(d) + 1) 3547db96d56Sopenharmony_ci 3557db96d56Sopenharmony_ci def test_copy_maintains_tracking(self): 3567db96d56Sopenharmony_ci class A: 3577db96d56Sopenharmony_ci pass 3587db96d56Sopenharmony_ci 3597db96d56Sopenharmony_ci key = A() 3607db96d56Sopenharmony_ci 3617db96d56Sopenharmony_ci for d in ({}, {'a': 1}, {key: 'val'}): 3627db96d56Sopenharmony_ci d2 = d.copy() 3637db96d56Sopenharmony_ci self.assertEqual(gc.is_tracked(d), gc.is_tracked(d2)) 3647db96d56Sopenharmony_ci 3657db96d56Sopenharmony_ci def test_copy_noncompact(self): 3667db96d56Sopenharmony_ci # Dicts don't compact themselves on del/pop operations. 3677db96d56Sopenharmony_ci # Copy will use a slow merging strategy that produces 3687db96d56Sopenharmony_ci # a compacted copy when roughly 33% of dict is a non-used 3697db96d56Sopenharmony_ci # keys-space (to optimize memory footprint). 3707db96d56Sopenharmony_ci # In this test we want to hit the slow/compacting 3717db96d56Sopenharmony_ci # branch of dict.copy() and make sure it works OK. 3727db96d56Sopenharmony_ci d = {k: k for k in range(1000)} 3737db96d56Sopenharmony_ci for k in range(950): 3747db96d56Sopenharmony_ci del d[k] 3757db96d56Sopenharmony_ci d2 = d.copy() 3767db96d56Sopenharmony_ci self.assertEqual(d2, d) 3777db96d56Sopenharmony_ci 3787db96d56Sopenharmony_ci def test_get(self): 3797db96d56Sopenharmony_ci d = {} 3807db96d56Sopenharmony_ci self.assertIs(d.get('c'), None) 3817db96d56Sopenharmony_ci self.assertEqual(d.get('c', 3), 3) 3827db96d56Sopenharmony_ci d = {'a': 1, 'b': 2} 3837db96d56Sopenharmony_ci self.assertIs(d.get('c'), None) 3847db96d56Sopenharmony_ci self.assertEqual(d.get('c', 3), 3) 3857db96d56Sopenharmony_ci self.assertEqual(d.get('a'), 1) 3867db96d56Sopenharmony_ci self.assertEqual(d.get('a', 3), 1) 3877db96d56Sopenharmony_ci self.assertRaises(TypeError, d.get) 3887db96d56Sopenharmony_ci self.assertRaises(TypeError, d.get, None, None, None) 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ci def test_setdefault(self): 3917db96d56Sopenharmony_ci # dict.setdefault() 3927db96d56Sopenharmony_ci d = {} 3937db96d56Sopenharmony_ci self.assertIs(d.setdefault('key0'), None) 3947db96d56Sopenharmony_ci d.setdefault('key0', []) 3957db96d56Sopenharmony_ci self.assertIs(d.setdefault('key0'), None) 3967db96d56Sopenharmony_ci d.setdefault('key', []).append(3) 3977db96d56Sopenharmony_ci self.assertEqual(d['key'][0], 3) 3987db96d56Sopenharmony_ci d.setdefault('key', []).append(4) 3997db96d56Sopenharmony_ci self.assertEqual(len(d['key']), 2) 4007db96d56Sopenharmony_ci self.assertRaises(TypeError, d.setdefault) 4017db96d56Sopenharmony_ci 4027db96d56Sopenharmony_ci class Exc(Exception): pass 4037db96d56Sopenharmony_ci 4047db96d56Sopenharmony_ci class BadHash(object): 4057db96d56Sopenharmony_ci fail = False 4067db96d56Sopenharmony_ci def __hash__(self): 4077db96d56Sopenharmony_ci if self.fail: 4087db96d56Sopenharmony_ci raise Exc() 4097db96d56Sopenharmony_ci else: 4107db96d56Sopenharmony_ci return 42 4117db96d56Sopenharmony_ci 4127db96d56Sopenharmony_ci x = BadHash() 4137db96d56Sopenharmony_ci d[x] = 42 4147db96d56Sopenharmony_ci x.fail = True 4157db96d56Sopenharmony_ci self.assertRaises(Exc, d.setdefault, x, []) 4167db96d56Sopenharmony_ci 4177db96d56Sopenharmony_ci def test_setdefault_atomic(self): 4187db96d56Sopenharmony_ci # Issue #13521: setdefault() calls __hash__ and __eq__ only once. 4197db96d56Sopenharmony_ci class Hashed(object): 4207db96d56Sopenharmony_ci def __init__(self): 4217db96d56Sopenharmony_ci self.hash_count = 0 4227db96d56Sopenharmony_ci self.eq_count = 0 4237db96d56Sopenharmony_ci def __hash__(self): 4247db96d56Sopenharmony_ci self.hash_count += 1 4257db96d56Sopenharmony_ci return 42 4267db96d56Sopenharmony_ci def __eq__(self, other): 4277db96d56Sopenharmony_ci self.eq_count += 1 4287db96d56Sopenharmony_ci return id(self) == id(other) 4297db96d56Sopenharmony_ci hashed1 = Hashed() 4307db96d56Sopenharmony_ci y = {hashed1: 5} 4317db96d56Sopenharmony_ci hashed2 = Hashed() 4327db96d56Sopenharmony_ci y.setdefault(hashed2, []) 4337db96d56Sopenharmony_ci self.assertEqual(hashed1.hash_count, 1) 4347db96d56Sopenharmony_ci self.assertEqual(hashed2.hash_count, 1) 4357db96d56Sopenharmony_ci self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1) 4367db96d56Sopenharmony_ci 4377db96d56Sopenharmony_ci def test_setitem_atomic_at_resize(self): 4387db96d56Sopenharmony_ci class Hashed(object): 4397db96d56Sopenharmony_ci def __init__(self): 4407db96d56Sopenharmony_ci self.hash_count = 0 4417db96d56Sopenharmony_ci self.eq_count = 0 4427db96d56Sopenharmony_ci def __hash__(self): 4437db96d56Sopenharmony_ci self.hash_count += 1 4447db96d56Sopenharmony_ci return 42 4457db96d56Sopenharmony_ci def __eq__(self, other): 4467db96d56Sopenharmony_ci self.eq_count += 1 4477db96d56Sopenharmony_ci return id(self) == id(other) 4487db96d56Sopenharmony_ci hashed1 = Hashed() 4497db96d56Sopenharmony_ci # 5 items 4507db96d56Sopenharmony_ci y = {hashed1: 5, 0: 0, 1: 1, 2: 2, 3: 3} 4517db96d56Sopenharmony_ci hashed2 = Hashed() 4527db96d56Sopenharmony_ci # 6th item forces a resize 4537db96d56Sopenharmony_ci y[hashed2] = [] 4547db96d56Sopenharmony_ci self.assertEqual(hashed1.hash_count, 1) 4557db96d56Sopenharmony_ci self.assertEqual(hashed2.hash_count, 1) 4567db96d56Sopenharmony_ci self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1) 4577db96d56Sopenharmony_ci 4587db96d56Sopenharmony_ci def test_popitem(self): 4597db96d56Sopenharmony_ci # dict.popitem() 4607db96d56Sopenharmony_ci for copymode in -1, +1: 4617db96d56Sopenharmony_ci # -1: b has same structure as a 4627db96d56Sopenharmony_ci # +1: b is a.copy() 4637db96d56Sopenharmony_ci for log2size in range(12): 4647db96d56Sopenharmony_ci size = 2**log2size 4657db96d56Sopenharmony_ci a = {} 4667db96d56Sopenharmony_ci b = {} 4677db96d56Sopenharmony_ci for i in range(size): 4687db96d56Sopenharmony_ci a[repr(i)] = i 4697db96d56Sopenharmony_ci if copymode < 0: 4707db96d56Sopenharmony_ci b[repr(i)] = i 4717db96d56Sopenharmony_ci if copymode > 0: 4727db96d56Sopenharmony_ci b = a.copy() 4737db96d56Sopenharmony_ci for i in range(size): 4747db96d56Sopenharmony_ci ka, va = ta = a.popitem() 4757db96d56Sopenharmony_ci self.assertEqual(va, int(ka)) 4767db96d56Sopenharmony_ci kb, vb = tb = b.popitem() 4777db96d56Sopenharmony_ci self.assertEqual(vb, int(kb)) 4787db96d56Sopenharmony_ci self.assertFalse(copymode < 0 and ta != tb) 4797db96d56Sopenharmony_ci self.assertFalse(a) 4807db96d56Sopenharmony_ci self.assertFalse(b) 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci d = {} 4837db96d56Sopenharmony_ci self.assertRaises(KeyError, d.popitem) 4847db96d56Sopenharmony_ci 4857db96d56Sopenharmony_ci def test_pop(self): 4867db96d56Sopenharmony_ci # Tests for pop with specified key 4877db96d56Sopenharmony_ci d = {} 4887db96d56Sopenharmony_ci k, v = 'abc', 'def' 4897db96d56Sopenharmony_ci d[k] = v 4907db96d56Sopenharmony_ci self.assertRaises(KeyError, d.pop, 'ghi') 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci self.assertEqual(d.pop(k), v) 4937db96d56Sopenharmony_ci self.assertEqual(len(d), 0) 4947db96d56Sopenharmony_ci 4957db96d56Sopenharmony_ci self.assertRaises(KeyError, d.pop, k) 4967db96d56Sopenharmony_ci 4977db96d56Sopenharmony_ci self.assertEqual(d.pop(k, v), v) 4987db96d56Sopenharmony_ci d[k] = v 4997db96d56Sopenharmony_ci self.assertEqual(d.pop(k, 1), v) 5007db96d56Sopenharmony_ci 5017db96d56Sopenharmony_ci self.assertRaises(TypeError, d.pop) 5027db96d56Sopenharmony_ci 5037db96d56Sopenharmony_ci class Exc(Exception): pass 5047db96d56Sopenharmony_ci 5057db96d56Sopenharmony_ci class BadHash(object): 5067db96d56Sopenharmony_ci fail = False 5077db96d56Sopenharmony_ci def __hash__(self): 5087db96d56Sopenharmony_ci if self.fail: 5097db96d56Sopenharmony_ci raise Exc() 5107db96d56Sopenharmony_ci else: 5117db96d56Sopenharmony_ci return 42 5127db96d56Sopenharmony_ci 5137db96d56Sopenharmony_ci x = BadHash() 5147db96d56Sopenharmony_ci d[x] = 42 5157db96d56Sopenharmony_ci x.fail = True 5167db96d56Sopenharmony_ci self.assertRaises(Exc, d.pop, x) 5177db96d56Sopenharmony_ci 5187db96d56Sopenharmony_ci def test_mutating_iteration(self): 5197db96d56Sopenharmony_ci # changing dict size during iteration 5207db96d56Sopenharmony_ci d = {} 5217db96d56Sopenharmony_ci d[1] = 1 5227db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 5237db96d56Sopenharmony_ci for i in d: 5247db96d56Sopenharmony_ci d[i+1] = 1 5257db96d56Sopenharmony_ci 5267db96d56Sopenharmony_ci def test_mutating_iteration_delete(self): 5277db96d56Sopenharmony_ci # change dict content during iteration 5287db96d56Sopenharmony_ci d = {} 5297db96d56Sopenharmony_ci d[0] = 0 5307db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 5317db96d56Sopenharmony_ci for i in d: 5327db96d56Sopenharmony_ci del d[0] 5337db96d56Sopenharmony_ci d[0] = 0 5347db96d56Sopenharmony_ci 5357db96d56Sopenharmony_ci def test_mutating_iteration_delete_over_values(self): 5367db96d56Sopenharmony_ci # change dict content during iteration 5377db96d56Sopenharmony_ci d = {} 5387db96d56Sopenharmony_ci d[0] = 0 5397db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 5407db96d56Sopenharmony_ci for i in d.values(): 5417db96d56Sopenharmony_ci del d[0] 5427db96d56Sopenharmony_ci d[0] = 0 5437db96d56Sopenharmony_ci 5447db96d56Sopenharmony_ci def test_mutating_iteration_delete_over_items(self): 5457db96d56Sopenharmony_ci # change dict content during iteration 5467db96d56Sopenharmony_ci d = {} 5477db96d56Sopenharmony_ci d[0] = 0 5487db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 5497db96d56Sopenharmony_ci for i in d.items(): 5507db96d56Sopenharmony_ci del d[0] 5517db96d56Sopenharmony_ci d[0] = 0 5527db96d56Sopenharmony_ci 5537db96d56Sopenharmony_ci def test_mutating_lookup(self): 5547db96d56Sopenharmony_ci # changing dict during a lookup (issue #14417) 5557db96d56Sopenharmony_ci class NastyKey: 5567db96d56Sopenharmony_ci mutate_dict = None 5577db96d56Sopenharmony_ci 5587db96d56Sopenharmony_ci def __init__(self, value): 5597db96d56Sopenharmony_ci self.value = value 5607db96d56Sopenharmony_ci 5617db96d56Sopenharmony_ci def __hash__(self): 5627db96d56Sopenharmony_ci # hash collision! 5637db96d56Sopenharmony_ci return 1 5647db96d56Sopenharmony_ci 5657db96d56Sopenharmony_ci def __eq__(self, other): 5667db96d56Sopenharmony_ci if NastyKey.mutate_dict: 5677db96d56Sopenharmony_ci mydict, key = NastyKey.mutate_dict 5687db96d56Sopenharmony_ci NastyKey.mutate_dict = None 5697db96d56Sopenharmony_ci del mydict[key] 5707db96d56Sopenharmony_ci return self.value == other.value 5717db96d56Sopenharmony_ci 5727db96d56Sopenharmony_ci key1 = NastyKey(1) 5737db96d56Sopenharmony_ci key2 = NastyKey(2) 5747db96d56Sopenharmony_ci d = {key1: 1} 5757db96d56Sopenharmony_ci NastyKey.mutate_dict = (d, key1) 5767db96d56Sopenharmony_ci d[key2] = 2 5777db96d56Sopenharmony_ci self.assertEqual(d, {key2: 2}) 5787db96d56Sopenharmony_ci 5797db96d56Sopenharmony_ci def test_repr(self): 5807db96d56Sopenharmony_ci d = {} 5817db96d56Sopenharmony_ci self.assertEqual(repr(d), '{}') 5827db96d56Sopenharmony_ci d[1] = 2 5837db96d56Sopenharmony_ci self.assertEqual(repr(d), '{1: 2}') 5847db96d56Sopenharmony_ci d = {} 5857db96d56Sopenharmony_ci d[1] = d 5867db96d56Sopenharmony_ci self.assertEqual(repr(d), '{1: {...}}') 5877db96d56Sopenharmony_ci 5887db96d56Sopenharmony_ci class Exc(Exception): pass 5897db96d56Sopenharmony_ci 5907db96d56Sopenharmony_ci class BadRepr(object): 5917db96d56Sopenharmony_ci def __repr__(self): 5927db96d56Sopenharmony_ci raise Exc() 5937db96d56Sopenharmony_ci 5947db96d56Sopenharmony_ci d = {1: BadRepr()} 5957db96d56Sopenharmony_ci self.assertRaises(Exc, repr, d) 5967db96d56Sopenharmony_ci 5977db96d56Sopenharmony_ci def test_repr_deep(self): 5987db96d56Sopenharmony_ci d = {} 5997db96d56Sopenharmony_ci for i in range(sys.getrecursionlimit() + 100): 6007db96d56Sopenharmony_ci d = {1: d} 6017db96d56Sopenharmony_ci self.assertRaises(RecursionError, repr, d) 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci def test_eq(self): 6047db96d56Sopenharmony_ci self.assertEqual({}, {}) 6057db96d56Sopenharmony_ci self.assertEqual({1: 2}, {1: 2}) 6067db96d56Sopenharmony_ci 6077db96d56Sopenharmony_ci class Exc(Exception): pass 6087db96d56Sopenharmony_ci 6097db96d56Sopenharmony_ci class BadCmp(object): 6107db96d56Sopenharmony_ci def __eq__(self, other): 6117db96d56Sopenharmony_ci raise Exc() 6127db96d56Sopenharmony_ci def __hash__(self): 6137db96d56Sopenharmony_ci return 1 6147db96d56Sopenharmony_ci 6157db96d56Sopenharmony_ci d1 = {BadCmp(): 1} 6167db96d56Sopenharmony_ci d2 = {1: 1} 6177db96d56Sopenharmony_ci 6187db96d56Sopenharmony_ci with self.assertRaises(Exc): 6197db96d56Sopenharmony_ci d1 == d2 6207db96d56Sopenharmony_ci 6217db96d56Sopenharmony_ci def test_keys_contained(self): 6227db96d56Sopenharmony_ci self.helper_keys_contained(lambda x: x.keys()) 6237db96d56Sopenharmony_ci self.helper_keys_contained(lambda x: x.items()) 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci def helper_keys_contained(self, fn): 6267db96d56Sopenharmony_ci # Test rich comparisons against dict key views, which should behave the 6277db96d56Sopenharmony_ci # same as sets. 6287db96d56Sopenharmony_ci empty = fn(dict()) 6297db96d56Sopenharmony_ci empty2 = fn(dict()) 6307db96d56Sopenharmony_ci smaller = fn({1:1, 2:2}) 6317db96d56Sopenharmony_ci larger = fn({1:1, 2:2, 3:3}) 6327db96d56Sopenharmony_ci larger2 = fn({1:1, 2:2, 3:3}) 6337db96d56Sopenharmony_ci larger3 = fn({4:1, 2:2, 3:3}) 6347db96d56Sopenharmony_ci 6357db96d56Sopenharmony_ci self.assertTrue(smaller < larger) 6367db96d56Sopenharmony_ci self.assertTrue(smaller <= larger) 6377db96d56Sopenharmony_ci self.assertTrue(larger > smaller) 6387db96d56Sopenharmony_ci self.assertTrue(larger >= smaller) 6397db96d56Sopenharmony_ci 6407db96d56Sopenharmony_ci self.assertFalse(smaller >= larger) 6417db96d56Sopenharmony_ci self.assertFalse(smaller > larger) 6427db96d56Sopenharmony_ci self.assertFalse(larger <= smaller) 6437db96d56Sopenharmony_ci self.assertFalse(larger < smaller) 6447db96d56Sopenharmony_ci 6457db96d56Sopenharmony_ci self.assertFalse(smaller < larger3) 6467db96d56Sopenharmony_ci self.assertFalse(smaller <= larger3) 6477db96d56Sopenharmony_ci self.assertFalse(larger3 > smaller) 6487db96d56Sopenharmony_ci self.assertFalse(larger3 >= smaller) 6497db96d56Sopenharmony_ci 6507db96d56Sopenharmony_ci # Inequality strictness 6517db96d56Sopenharmony_ci self.assertTrue(larger2 >= larger) 6527db96d56Sopenharmony_ci self.assertTrue(larger2 <= larger) 6537db96d56Sopenharmony_ci self.assertFalse(larger2 > larger) 6547db96d56Sopenharmony_ci self.assertFalse(larger2 < larger) 6557db96d56Sopenharmony_ci 6567db96d56Sopenharmony_ci self.assertTrue(larger == larger2) 6577db96d56Sopenharmony_ci self.assertTrue(smaller != larger) 6587db96d56Sopenharmony_ci 6597db96d56Sopenharmony_ci # There is an optimization on the zero-element case. 6607db96d56Sopenharmony_ci self.assertTrue(empty == empty2) 6617db96d56Sopenharmony_ci self.assertFalse(empty != empty2) 6627db96d56Sopenharmony_ci self.assertFalse(empty == smaller) 6637db96d56Sopenharmony_ci self.assertTrue(empty != smaller) 6647db96d56Sopenharmony_ci 6657db96d56Sopenharmony_ci # With the same size, an elementwise compare happens 6667db96d56Sopenharmony_ci self.assertTrue(larger != larger3) 6677db96d56Sopenharmony_ci self.assertFalse(larger == larger3) 6687db96d56Sopenharmony_ci 6697db96d56Sopenharmony_ci def test_errors_in_view_containment_check(self): 6707db96d56Sopenharmony_ci class C: 6717db96d56Sopenharmony_ci def __eq__(self, other): 6727db96d56Sopenharmony_ci raise RuntimeError 6737db96d56Sopenharmony_ci 6747db96d56Sopenharmony_ci d1 = {1: C()} 6757db96d56Sopenharmony_ci d2 = {1: C()} 6767db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6777db96d56Sopenharmony_ci d1.items() == d2.items() 6787db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6797db96d56Sopenharmony_ci d1.items() != d2.items() 6807db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6817db96d56Sopenharmony_ci d1.items() <= d2.items() 6827db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6837db96d56Sopenharmony_ci d1.items() >= d2.items() 6847db96d56Sopenharmony_ci 6857db96d56Sopenharmony_ci d3 = {1: C(), 2: C()} 6867db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6877db96d56Sopenharmony_ci d2.items() < d3.items() 6887db96d56Sopenharmony_ci with self.assertRaises(RuntimeError): 6897db96d56Sopenharmony_ci d3.items() > d2.items() 6907db96d56Sopenharmony_ci 6917db96d56Sopenharmony_ci def test_dictview_set_operations_on_keys(self): 6927db96d56Sopenharmony_ci k1 = {1:1, 2:2}.keys() 6937db96d56Sopenharmony_ci k2 = {1:1, 2:2, 3:3}.keys() 6947db96d56Sopenharmony_ci k3 = {4:4}.keys() 6957db96d56Sopenharmony_ci 6967db96d56Sopenharmony_ci self.assertEqual(k1 - k2, set()) 6977db96d56Sopenharmony_ci self.assertEqual(k1 - k3, {1,2}) 6987db96d56Sopenharmony_ci self.assertEqual(k2 - k1, {3}) 6997db96d56Sopenharmony_ci self.assertEqual(k3 - k1, {4}) 7007db96d56Sopenharmony_ci self.assertEqual(k1 & k2, {1,2}) 7017db96d56Sopenharmony_ci self.assertEqual(k1 & k3, set()) 7027db96d56Sopenharmony_ci self.assertEqual(k1 | k2, {1,2,3}) 7037db96d56Sopenharmony_ci self.assertEqual(k1 ^ k2, {3}) 7047db96d56Sopenharmony_ci self.assertEqual(k1 ^ k3, {1,2,4}) 7057db96d56Sopenharmony_ci 7067db96d56Sopenharmony_ci def test_dictview_set_operations_on_items(self): 7077db96d56Sopenharmony_ci k1 = {1:1, 2:2}.items() 7087db96d56Sopenharmony_ci k2 = {1:1, 2:2, 3:3}.items() 7097db96d56Sopenharmony_ci k3 = {4:4}.items() 7107db96d56Sopenharmony_ci 7117db96d56Sopenharmony_ci self.assertEqual(k1 - k2, set()) 7127db96d56Sopenharmony_ci self.assertEqual(k1 - k3, {(1,1), (2,2)}) 7137db96d56Sopenharmony_ci self.assertEqual(k2 - k1, {(3,3)}) 7147db96d56Sopenharmony_ci self.assertEqual(k3 - k1, {(4,4)}) 7157db96d56Sopenharmony_ci self.assertEqual(k1 & k2, {(1,1), (2,2)}) 7167db96d56Sopenharmony_ci self.assertEqual(k1 & k3, set()) 7177db96d56Sopenharmony_ci self.assertEqual(k1 | k2, {(1,1), (2,2), (3,3)}) 7187db96d56Sopenharmony_ci self.assertEqual(k1 ^ k2, {(3,3)}) 7197db96d56Sopenharmony_ci self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)}) 7207db96d56Sopenharmony_ci 7217db96d56Sopenharmony_ci def test_items_symmetric_difference(self): 7227db96d56Sopenharmony_ci rr = random.randrange 7237db96d56Sopenharmony_ci for _ in range(100): 7247db96d56Sopenharmony_ci left = {x:rr(3) for x in range(20) if rr(2)} 7257db96d56Sopenharmony_ci right = {x:rr(3) for x in range(20) if rr(2)} 7267db96d56Sopenharmony_ci with self.subTest(left=left, right=right): 7277db96d56Sopenharmony_ci expected = set(left.items()) ^ set(right.items()) 7287db96d56Sopenharmony_ci actual = left.items() ^ right.items() 7297db96d56Sopenharmony_ci self.assertEqual(actual, expected) 7307db96d56Sopenharmony_ci 7317db96d56Sopenharmony_ci def test_dictview_mixed_set_operations(self): 7327db96d56Sopenharmony_ci # Just a few for .keys() 7337db96d56Sopenharmony_ci self.assertTrue({1:1}.keys() == {1}) 7347db96d56Sopenharmony_ci self.assertTrue({1} == {1:1}.keys()) 7357db96d56Sopenharmony_ci self.assertEqual({1:1}.keys() | {2}, {1, 2}) 7367db96d56Sopenharmony_ci self.assertEqual({2} | {1:1}.keys(), {1, 2}) 7377db96d56Sopenharmony_ci # And a few for .items() 7387db96d56Sopenharmony_ci self.assertTrue({1:1}.items() == {(1,1)}) 7397db96d56Sopenharmony_ci self.assertTrue({(1,1)} == {1:1}.items()) 7407db96d56Sopenharmony_ci self.assertEqual({1:1}.items() | {2}, {(1,1), 2}) 7417db96d56Sopenharmony_ci self.assertEqual({2} | {1:1}.items(), {(1,1), 2}) 7427db96d56Sopenharmony_ci 7437db96d56Sopenharmony_ci def test_missing(self): 7447db96d56Sopenharmony_ci # Make sure dict doesn't have a __missing__ method 7457db96d56Sopenharmony_ci self.assertFalse(hasattr(dict, "__missing__")) 7467db96d56Sopenharmony_ci self.assertFalse(hasattr({}, "__missing__")) 7477db96d56Sopenharmony_ci # Test several cases: 7487db96d56Sopenharmony_ci # (D) subclass defines __missing__ method returning a value 7497db96d56Sopenharmony_ci # (E) subclass defines __missing__ method raising RuntimeError 7507db96d56Sopenharmony_ci # (F) subclass sets __missing__ instance variable (no effect) 7517db96d56Sopenharmony_ci # (G) subclass doesn't define __missing__ at all 7527db96d56Sopenharmony_ci class D(dict): 7537db96d56Sopenharmony_ci def __missing__(self, key): 7547db96d56Sopenharmony_ci return 42 7557db96d56Sopenharmony_ci d = D({1: 2, 3: 4}) 7567db96d56Sopenharmony_ci self.assertEqual(d[1], 2) 7577db96d56Sopenharmony_ci self.assertEqual(d[3], 4) 7587db96d56Sopenharmony_ci self.assertNotIn(2, d) 7597db96d56Sopenharmony_ci self.assertNotIn(2, d.keys()) 7607db96d56Sopenharmony_ci self.assertEqual(d[2], 42) 7617db96d56Sopenharmony_ci 7627db96d56Sopenharmony_ci class E(dict): 7637db96d56Sopenharmony_ci def __missing__(self, key): 7647db96d56Sopenharmony_ci raise RuntimeError(key) 7657db96d56Sopenharmony_ci e = E() 7667db96d56Sopenharmony_ci with self.assertRaises(RuntimeError) as c: 7677db96d56Sopenharmony_ci e[42] 7687db96d56Sopenharmony_ci self.assertEqual(c.exception.args, (42,)) 7697db96d56Sopenharmony_ci 7707db96d56Sopenharmony_ci class F(dict): 7717db96d56Sopenharmony_ci def __init__(self): 7727db96d56Sopenharmony_ci # An instance variable __missing__ should have no effect 7737db96d56Sopenharmony_ci self.__missing__ = lambda key: None 7747db96d56Sopenharmony_ci f = F() 7757db96d56Sopenharmony_ci with self.assertRaises(KeyError) as c: 7767db96d56Sopenharmony_ci f[42] 7777db96d56Sopenharmony_ci self.assertEqual(c.exception.args, (42,)) 7787db96d56Sopenharmony_ci 7797db96d56Sopenharmony_ci class G(dict): 7807db96d56Sopenharmony_ci pass 7817db96d56Sopenharmony_ci g = G() 7827db96d56Sopenharmony_ci with self.assertRaises(KeyError) as c: 7837db96d56Sopenharmony_ci g[42] 7847db96d56Sopenharmony_ci self.assertEqual(c.exception.args, (42,)) 7857db96d56Sopenharmony_ci 7867db96d56Sopenharmony_ci def test_tuple_keyerror(self): 7877db96d56Sopenharmony_ci # SF #1576657 7887db96d56Sopenharmony_ci d = {} 7897db96d56Sopenharmony_ci with self.assertRaises(KeyError) as c: 7907db96d56Sopenharmony_ci d[(1,)] 7917db96d56Sopenharmony_ci self.assertEqual(c.exception.args, ((1,),)) 7927db96d56Sopenharmony_ci 7937db96d56Sopenharmony_ci def test_bad_key(self): 7947db96d56Sopenharmony_ci # Dictionary lookups should fail if __eq__() raises an exception. 7957db96d56Sopenharmony_ci class CustomException(Exception): 7967db96d56Sopenharmony_ci pass 7977db96d56Sopenharmony_ci 7987db96d56Sopenharmony_ci class BadDictKey: 7997db96d56Sopenharmony_ci def __hash__(self): 8007db96d56Sopenharmony_ci return hash(self.__class__) 8017db96d56Sopenharmony_ci 8027db96d56Sopenharmony_ci def __eq__(self, other): 8037db96d56Sopenharmony_ci if isinstance(other, self.__class__): 8047db96d56Sopenharmony_ci raise CustomException 8057db96d56Sopenharmony_ci return other 8067db96d56Sopenharmony_ci 8077db96d56Sopenharmony_ci d = {} 8087db96d56Sopenharmony_ci x1 = BadDictKey() 8097db96d56Sopenharmony_ci x2 = BadDictKey() 8107db96d56Sopenharmony_ci d[x1] = 1 8117db96d56Sopenharmony_ci for stmt in ['d[x2] = 2', 8127db96d56Sopenharmony_ci 'z = d[x2]', 8137db96d56Sopenharmony_ci 'x2 in d', 8147db96d56Sopenharmony_ci 'd.get(x2)', 8157db96d56Sopenharmony_ci 'd.setdefault(x2, 42)', 8167db96d56Sopenharmony_ci 'd.pop(x2)', 8177db96d56Sopenharmony_ci 'd.update({x2: 2})']: 8187db96d56Sopenharmony_ci with self.assertRaises(CustomException): 8197db96d56Sopenharmony_ci exec(stmt, locals()) 8207db96d56Sopenharmony_ci 8217db96d56Sopenharmony_ci def test_resize1(self): 8227db96d56Sopenharmony_ci # Dict resizing bug, found by Jack Jansen in 2.2 CVS development. 8237db96d56Sopenharmony_ci # This version got an assert failure in debug build, infinite loop in 8247db96d56Sopenharmony_ci # release build. Unfortunately, provoking this kind of stuff requires 8257db96d56Sopenharmony_ci # a mix of inserts and deletes hitting exactly the right hash codes in 8267db96d56Sopenharmony_ci # exactly the right order, and I can't think of a randomized approach 8277db96d56Sopenharmony_ci # that would be *likely* to hit a failing case in reasonable time. 8287db96d56Sopenharmony_ci 8297db96d56Sopenharmony_ci d = {} 8307db96d56Sopenharmony_ci for i in range(5): 8317db96d56Sopenharmony_ci d[i] = i 8327db96d56Sopenharmony_ci for i in range(5): 8337db96d56Sopenharmony_ci del d[i] 8347db96d56Sopenharmony_ci for i in range(5, 9): # i==8 was the problem 8357db96d56Sopenharmony_ci d[i] = i 8367db96d56Sopenharmony_ci 8377db96d56Sopenharmony_ci def test_resize2(self): 8387db96d56Sopenharmony_ci # Another dict resizing bug (SF bug #1456209). 8397db96d56Sopenharmony_ci # This caused Segmentation faults or Illegal instructions. 8407db96d56Sopenharmony_ci 8417db96d56Sopenharmony_ci class X(object): 8427db96d56Sopenharmony_ci def __hash__(self): 8437db96d56Sopenharmony_ci return 5 8447db96d56Sopenharmony_ci def __eq__(self, other): 8457db96d56Sopenharmony_ci if resizing: 8467db96d56Sopenharmony_ci d.clear() 8477db96d56Sopenharmony_ci return False 8487db96d56Sopenharmony_ci d = {} 8497db96d56Sopenharmony_ci resizing = False 8507db96d56Sopenharmony_ci d[X()] = 1 8517db96d56Sopenharmony_ci d[X()] = 2 8527db96d56Sopenharmony_ci d[X()] = 3 8537db96d56Sopenharmony_ci d[X()] = 4 8547db96d56Sopenharmony_ci d[X()] = 5 8557db96d56Sopenharmony_ci # now trigger a resize 8567db96d56Sopenharmony_ci resizing = True 8577db96d56Sopenharmony_ci d[9] = 6 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci def test_empty_presized_dict_in_freelist(self): 8607db96d56Sopenharmony_ci # Bug #3537: if an empty but presized dict with a size larger 8617db96d56Sopenharmony_ci # than 7 was in the freelist, it triggered an assertion failure 8627db96d56Sopenharmony_ci with self.assertRaises(ZeroDivisionError): 8637db96d56Sopenharmony_ci d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None, 8647db96d56Sopenharmony_ci 'f': None, 'g': None, 'h': None} 8657db96d56Sopenharmony_ci d = {} 8667db96d56Sopenharmony_ci 8677db96d56Sopenharmony_ci def test_container_iterator(self): 8687db96d56Sopenharmony_ci # Bug #3680: tp_traverse was not implemented for dictiter and 8697db96d56Sopenharmony_ci # dictview objects. 8707db96d56Sopenharmony_ci class C(object): 8717db96d56Sopenharmony_ci pass 8727db96d56Sopenharmony_ci views = (dict.items, dict.values, dict.keys) 8737db96d56Sopenharmony_ci for v in views: 8747db96d56Sopenharmony_ci obj = C() 8757db96d56Sopenharmony_ci ref = weakref.ref(obj) 8767db96d56Sopenharmony_ci container = {obj: 1} 8777db96d56Sopenharmony_ci obj.v = v(container) 8787db96d56Sopenharmony_ci obj.x = iter(obj.v) 8797db96d56Sopenharmony_ci del obj, container 8807db96d56Sopenharmony_ci gc.collect() 8817db96d56Sopenharmony_ci self.assertIs(ref(), None, "Cycle was not collected") 8827db96d56Sopenharmony_ci 8837db96d56Sopenharmony_ci def _not_tracked(self, t): 8847db96d56Sopenharmony_ci # Nested containers can take several collections to untrack 8857db96d56Sopenharmony_ci gc.collect() 8867db96d56Sopenharmony_ci gc.collect() 8877db96d56Sopenharmony_ci self.assertFalse(gc.is_tracked(t), t) 8887db96d56Sopenharmony_ci 8897db96d56Sopenharmony_ci def _tracked(self, t): 8907db96d56Sopenharmony_ci self.assertTrue(gc.is_tracked(t), t) 8917db96d56Sopenharmony_ci gc.collect() 8927db96d56Sopenharmony_ci gc.collect() 8937db96d56Sopenharmony_ci self.assertTrue(gc.is_tracked(t), t) 8947db96d56Sopenharmony_ci 8957db96d56Sopenharmony_ci def test_string_keys_can_track_values(self): 8967db96d56Sopenharmony_ci # Test that this doesn't leak. 8977db96d56Sopenharmony_ci for i in range(10): 8987db96d56Sopenharmony_ci d = {} 8997db96d56Sopenharmony_ci for j in range(10): 9007db96d56Sopenharmony_ci d[str(j)] = j 9017db96d56Sopenharmony_ci d["foo"] = d 9027db96d56Sopenharmony_ci 9037db96d56Sopenharmony_ci @support.cpython_only 9047db96d56Sopenharmony_ci def test_track_literals(self): 9057db96d56Sopenharmony_ci # Test GC-optimization of dict literals 9067db96d56Sopenharmony_ci x, y, z, w = 1.5, "a", (1, None), [] 9077db96d56Sopenharmony_ci 9087db96d56Sopenharmony_ci self._not_tracked({}) 9097db96d56Sopenharmony_ci self._not_tracked({x:(), y:x, z:1}) 9107db96d56Sopenharmony_ci self._not_tracked({1: "a", "b": 2}) 9117db96d56Sopenharmony_ci self._not_tracked({1: 2, (None, True, False, ()): int}) 9127db96d56Sopenharmony_ci self._not_tracked({1: object()}) 9137db96d56Sopenharmony_ci 9147db96d56Sopenharmony_ci # Dicts with mutable elements are always tracked, even if those 9157db96d56Sopenharmony_ci # elements are not tracked right now. 9167db96d56Sopenharmony_ci self._tracked({1: []}) 9177db96d56Sopenharmony_ci self._tracked({1: ([],)}) 9187db96d56Sopenharmony_ci self._tracked({1: {}}) 9197db96d56Sopenharmony_ci self._tracked({1: set()}) 9207db96d56Sopenharmony_ci 9217db96d56Sopenharmony_ci @support.cpython_only 9227db96d56Sopenharmony_ci def test_track_dynamic(self): 9237db96d56Sopenharmony_ci # Test GC-optimization of dynamically-created dicts 9247db96d56Sopenharmony_ci class MyObject(object): 9257db96d56Sopenharmony_ci pass 9267db96d56Sopenharmony_ci x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject() 9277db96d56Sopenharmony_ci 9287db96d56Sopenharmony_ci d = dict() 9297db96d56Sopenharmony_ci self._not_tracked(d) 9307db96d56Sopenharmony_ci d[1] = "a" 9317db96d56Sopenharmony_ci self._not_tracked(d) 9327db96d56Sopenharmony_ci d[y] = 2 9337db96d56Sopenharmony_ci self._not_tracked(d) 9347db96d56Sopenharmony_ci d[z] = 3 9357db96d56Sopenharmony_ci self._not_tracked(d) 9367db96d56Sopenharmony_ci self._not_tracked(d.copy()) 9377db96d56Sopenharmony_ci d[4] = w 9387db96d56Sopenharmony_ci self._tracked(d) 9397db96d56Sopenharmony_ci self._tracked(d.copy()) 9407db96d56Sopenharmony_ci d[4] = None 9417db96d56Sopenharmony_ci self._not_tracked(d) 9427db96d56Sopenharmony_ci self._not_tracked(d.copy()) 9437db96d56Sopenharmony_ci 9447db96d56Sopenharmony_ci # dd isn't tracked right now, but it may mutate and therefore d 9457db96d56Sopenharmony_ci # which contains it must be tracked. 9467db96d56Sopenharmony_ci d = dict() 9477db96d56Sopenharmony_ci dd = dict() 9487db96d56Sopenharmony_ci d[1] = dd 9497db96d56Sopenharmony_ci self._not_tracked(dd) 9507db96d56Sopenharmony_ci self._tracked(d) 9517db96d56Sopenharmony_ci dd[1] = d 9527db96d56Sopenharmony_ci self._tracked(dd) 9537db96d56Sopenharmony_ci 9547db96d56Sopenharmony_ci d = dict.fromkeys([x, y, z]) 9557db96d56Sopenharmony_ci self._not_tracked(d) 9567db96d56Sopenharmony_ci dd = dict() 9577db96d56Sopenharmony_ci dd.update(d) 9587db96d56Sopenharmony_ci self._not_tracked(dd) 9597db96d56Sopenharmony_ci d = dict.fromkeys([x, y, z, o]) 9607db96d56Sopenharmony_ci self._tracked(d) 9617db96d56Sopenharmony_ci dd = dict() 9627db96d56Sopenharmony_ci dd.update(d) 9637db96d56Sopenharmony_ci self._tracked(dd) 9647db96d56Sopenharmony_ci 9657db96d56Sopenharmony_ci d = dict(x=x, y=y, z=z) 9667db96d56Sopenharmony_ci self._not_tracked(d) 9677db96d56Sopenharmony_ci d = dict(x=x, y=y, z=z, w=w) 9687db96d56Sopenharmony_ci self._tracked(d) 9697db96d56Sopenharmony_ci d = dict() 9707db96d56Sopenharmony_ci d.update(x=x, y=y, z=z) 9717db96d56Sopenharmony_ci self._not_tracked(d) 9727db96d56Sopenharmony_ci d.update(w=w) 9737db96d56Sopenharmony_ci self._tracked(d) 9747db96d56Sopenharmony_ci 9757db96d56Sopenharmony_ci d = dict([(x, y), (z, 1)]) 9767db96d56Sopenharmony_ci self._not_tracked(d) 9777db96d56Sopenharmony_ci d = dict([(x, y), (z, w)]) 9787db96d56Sopenharmony_ci self._tracked(d) 9797db96d56Sopenharmony_ci d = dict() 9807db96d56Sopenharmony_ci d.update([(x, y), (z, 1)]) 9817db96d56Sopenharmony_ci self._not_tracked(d) 9827db96d56Sopenharmony_ci d.update([(x, y), (z, w)]) 9837db96d56Sopenharmony_ci self._tracked(d) 9847db96d56Sopenharmony_ci 9857db96d56Sopenharmony_ci @support.cpython_only 9867db96d56Sopenharmony_ci def test_track_subtypes(self): 9877db96d56Sopenharmony_ci # Dict subtypes are always tracked 9887db96d56Sopenharmony_ci class MyDict(dict): 9897db96d56Sopenharmony_ci pass 9907db96d56Sopenharmony_ci self._tracked(MyDict()) 9917db96d56Sopenharmony_ci 9927db96d56Sopenharmony_ci def make_shared_key_dict(self, n): 9937db96d56Sopenharmony_ci class C: 9947db96d56Sopenharmony_ci pass 9957db96d56Sopenharmony_ci 9967db96d56Sopenharmony_ci dicts = [] 9977db96d56Sopenharmony_ci for i in range(n): 9987db96d56Sopenharmony_ci a = C() 9997db96d56Sopenharmony_ci a.x, a.y, a.z = 1, 2, 3 10007db96d56Sopenharmony_ci dicts.append(a.__dict__) 10017db96d56Sopenharmony_ci 10027db96d56Sopenharmony_ci return dicts 10037db96d56Sopenharmony_ci 10047db96d56Sopenharmony_ci @support.cpython_only 10057db96d56Sopenharmony_ci def test_splittable_setdefault(self): 10067db96d56Sopenharmony_ci """split table must keep correct insertion 10077db96d56Sopenharmony_ci order when attributes are adding using setdefault()""" 10087db96d56Sopenharmony_ci a, b = self.make_shared_key_dict(2) 10097db96d56Sopenharmony_ci 10107db96d56Sopenharmony_ci a['a'] = 1 10117db96d56Sopenharmony_ci size_a = sys.getsizeof(a) 10127db96d56Sopenharmony_ci a['b'] = 2 10137db96d56Sopenharmony_ci b.setdefault('b', 2) 10147db96d56Sopenharmony_ci size_b = sys.getsizeof(b) 10157db96d56Sopenharmony_ci b['a'] = 1 10167db96d56Sopenharmony_ci 10177db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b']) 10187db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a']) 10197db96d56Sopenharmony_ci 10207db96d56Sopenharmony_ci @support.cpython_only 10217db96d56Sopenharmony_ci def test_splittable_del(self): 10227db96d56Sopenharmony_ci """split table must be combined when del d[k]""" 10237db96d56Sopenharmony_ci a, b = self.make_shared_key_dict(2) 10247db96d56Sopenharmony_ci 10257db96d56Sopenharmony_ci orig_size = sys.getsizeof(a) 10267db96d56Sopenharmony_ci 10277db96d56Sopenharmony_ci del a['y'] # split table is combined 10287db96d56Sopenharmony_ci with self.assertRaises(KeyError): 10297db96d56Sopenharmony_ci del a['y'] 10307db96d56Sopenharmony_ci 10317db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'z']) 10327db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z']) 10337db96d56Sopenharmony_ci 10347db96d56Sopenharmony_ci # Two dicts have different insertion order. 10357db96d56Sopenharmony_ci a['y'] = 42 10367db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'z', 'y']) 10377db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z']) 10387db96d56Sopenharmony_ci 10397db96d56Sopenharmony_ci @support.cpython_only 10407db96d56Sopenharmony_ci def test_splittable_pop(self): 10417db96d56Sopenharmony_ci a, b = self.make_shared_key_dict(2) 10427db96d56Sopenharmony_ci 10437db96d56Sopenharmony_ci a.pop('y') 10447db96d56Sopenharmony_ci with self.assertRaises(KeyError): 10457db96d56Sopenharmony_ci a.pop('y') 10467db96d56Sopenharmony_ci 10477db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'z']) 10487db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z']) 10497db96d56Sopenharmony_ci 10507db96d56Sopenharmony_ci # Two dicts have different insertion order. 10517db96d56Sopenharmony_ci a['y'] = 42 10527db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'z', 'y']) 10537db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z']) 10547db96d56Sopenharmony_ci 10557db96d56Sopenharmony_ci @support.cpython_only 10567db96d56Sopenharmony_ci def test_splittable_pop_pending(self): 10577db96d56Sopenharmony_ci """pop a pending key in a split table should not crash""" 10587db96d56Sopenharmony_ci a, b = self.make_shared_key_dict(2) 10597db96d56Sopenharmony_ci 10607db96d56Sopenharmony_ci a['a'] = 4 10617db96d56Sopenharmony_ci with self.assertRaises(KeyError): 10627db96d56Sopenharmony_ci b.pop('a') 10637db96d56Sopenharmony_ci 10647db96d56Sopenharmony_ci @support.cpython_only 10657db96d56Sopenharmony_ci def test_splittable_popitem(self): 10667db96d56Sopenharmony_ci """split table must be combined when d.popitem()""" 10677db96d56Sopenharmony_ci a, b = self.make_shared_key_dict(2) 10687db96d56Sopenharmony_ci 10697db96d56Sopenharmony_ci orig_size = sys.getsizeof(a) 10707db96d56Sopenharmony_ci 10717db96d56Sopenharmony_ci item = a.popitem() # split table is combined 10727db96d56Sopenharmony_ci self.assertEqual(item, ('z', 3)) 10737db96d56Sopenharmony_ci with self.assertRaises(KeyError): 10747db96d56Sopenharmony_ci del a['z'] 10757db96d56Sopenharmony_ci 10767db96d56Sopenharmony_ci self.assertGreater(sys.getsizeof(a), orig_size) 10777db96d56Sopenharmony_ci self.assertEqual(list(a), ['x', 'y']) 10787db96d56Sopenharmony_ci self.assertEqual(list(b), ['x', 'y', 'z']) 10797db96d56Sopenharmony_ci 10807db96d56Sopenharmony_ci @support.cpython_only 10817db96d56Sopenharmony_ci def test_splittable_update(self): 10827db96d56Sopenharmony_ci """dict.update(other) must preserve order in other.""" 10837db96d56Sopenharmony_ci class C: 10847db96d56Sopenharmony_ci def __init__(self, order): 10857db96d56Sopenharmony_ci if order: 10867db96d56Sopenharmony_ci self.a, self.b, self.c = 1, 2, 3 10877db96d56Sopenharmony_ci else: 10887db96d56Sopenharmony_ci self.c, self.b, self.a = 1, 2, 3 10897db96d56Sopenharmony_ci o = C(True) 10907db96d56Sopenharmony_ci o = C(False) # o.__dict__ has reversed order. 10917db96d56Sopenharmony_ci self.assertEqual(list(o.__dict__), ["c", "b", "a"]) 10927db96d56Sopenharmony_ci 10937db96d56Sopenharmony_ci d = {} 10947db96d56Sopenharmony_ci d.update(o.__dict__) 10957db96d56Sopenharmony_ci self.assertEqual(list(d), ["c", "b", "a"]) 10967db96d56Sopenharmony_ci 10977db96d56Sopenharmony_ci def test_iterator_pickling(self): 10987db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 10997db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11007db96d56Sopenharmony_ci it = iter(data) 11017db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11027db96d56Sopenharmony_ci it = pickle.loads(d) 11037db96d56Sopenharmony_ci self.assertEqual(list(it), list(data)) 11047db96d56Sopenharmony_ci 11057db96d56Sopenharmony_ci it = pickle.loads(d) 11067db96d56Sopenharmony_ci try: 11077db96d56Sopenharmony_ci drop = next(it) 11087db96d56Sopenharmony_ci except StopIteration: 11097db96d56Sopenharmony_ci continue 11107db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11117db96d56Sopenharmony_ci it = pickle.loads(d) 11127db96d56Sopenharmony_ci del data[drop] 11137db96d56Sopenharmony_ci self.assertEqual(list(it), list(data)) 11147db96d56Sopenharmony_ci 11157db96d56Sopenharmony_ci def test_itemiterator_pickling(self): 11167db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 11177db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11187db96d56Sopenharmony_ci # dictviews aren't picklable, only their iterators 11197db96d56Sopenharmony_ci itorg = iter(data.items()) 11207db96d56Sopenharmony_ci d = pickle.dumps(itorg, proto) 11217db96d56Sopenharmony_ci it = pickle.loads(d) 11227db96d56Sopenharmony_ci # note that the type of the unpickled iterator 11237db96d56Sopenharmony_ci # is not necessarily the same as the original. It is 11247db96d56Sopenharmony_ci # merely an object supporting the iterator protocol, yielding 11257db96d56Sopenharmony_ci # the same objects as the original one. 11267db96d56Sopenharmony_ci # self.assertEqual(type(itorg), type(it)) 11277db96d56Sopenharmony_ci self.assertIsInstance(it, collections.abc.Iterator) 11287db96d56Sopenharmony_ci self.assertEqual(dict(it), data) 11297db96d56Sopenharmony_ci 11307db96d56Sopenharmony_ci it = pickle.loads(d) 11317db96d56Sopenharmony_ci drop = next(it) 11327db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11337db96d56Sopenharmony_ci it = pickle.loads(d) 11347db96d56Sopenharmony_ci del data[drop[0]] 11357db96d56Sopenharmony_ci self.assertEqual(dict(it), data) 11367db96d56Sopenharmony_ci 11377db96d56Sopenharmony_ci def test_valuesiterator_pickling(self): 11387db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 11397db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11407db96d56Sopenharmony_ci # data.values() isn't picklable, only its iterator 11417db96d56Sopenharmony_ci it = iter(data.values()) 11427db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11437db96d56Sopenharmony_ci it = pickle.loads(d) 11447db96d56Sopenharmony_ci self.assertEqual(list(it), list(data.values())) 11457db96d56Sopenharmony_ci 11467db96d56Sopenharmony_ci it = pickle.loads(d) 11477db96d56Sopenharmony_ci drop = next(it) 11487db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11497db96d56Sopenharmony_ci it = pickle.loads(d) 11507db96d56Sopenharmony_ci values = list(it) + [drop] 11517db96d56Sopenharmony_ci self.assertEqual(sorted(values), sorted(list(data.values()))) 11527db96d56Sopenharmony_ci 11537db96d56Sopenharmony_ci def test_reverseiterator_pickling(self): 11547db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 11557db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11567db96d56Sopenharmony_ci it = reversed(data) 11577db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11587db96d56Sopenharmony_ci it = pickle.loads(d) 11597db96d56Sopenharmony_ci self.assertEqual(list(it), list(reversed(data))) 11607db96d56Sopenharmony_ci 11617db96d56Sopenharmony_ci it = pickle.loads(d) 11627db96d56Sopenharmony_ci try: 11637db96d56Sopenharmony_ci drop = next(it) 11647db96d56Sopenharmony_ci except StopIteration: 11657db96d56Sopenharmony_ci continue 11667db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11677db96d56Sopenharmony_ci it = pickle.loads(d) 11687db96d56Sopenharmony_ci del data[drop] 11697db96d56Sopenharmony_ci self.assertEqual(list(it), list(reversed(data))) 11707db96d56Sopenharmony_ci 11717db96d56Sopenharmony_ci def test_reverseitemiterator_pickling(self): 11727db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 11737db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11747db96d56Sopenharmony_ci # dictviews aren't picklable, only their iterators 11757db96d56Sopenharmony_ci itorg = reversed(data.items()) 11767db96d56Sopenharmony_ci d = pickle.dumps(itorg, proto) 11777db96d56Sopenharmony_ci it = pickle.loads(d) 11787db96d56Sopenharmony_ci # note that the type of the unpickled iterator 11797db96d56Sopenharmony_ci # is not necessarily the same as the original. It is 11807db96d56Sopenharmony_ci # merely an object supporting the iterator protocol, yielding 11817db96d56Sopenharmony_ci # the same objects as the original one. 11827db96d56Sopenharmony_ci # self.assertEqual(type(itorg), type(it)) 11837db96d56Sopenharmony_ci self.assertIsInstance(it, collections.abc.Iterator) 11847db96d56Sopenharmony_ci self.assertEqual(dict(it), data) 11857db96d56Sopenharmony_ci 11867db96d56Sopenharmony_ci it = pickle.loads(d) 11877db96d56Sopenharmony_ci drop = next(it) 11887db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11897db96d56Sopenharmony_ci it = pickle.loads(d) 11907db96d56Sopenharmony_ci del data[drop[0]] 11917db96d56Sopenharmony_ci self.assertEqual(dict(it), data) 11927db96d56Sopenharmony_ci 11937db96d56Sopenharmony_ci def test_reversevaluesiterator_pickling(self): 11947db96d56Sopenharmony_ci for proto in range(pickle.HIGHEST_PROTOCOL + 1): 11957db96d56Sopenharmony_ci data = {1:"a", 2:"b", 3:"c"} 11967db96d56Sopenharmony_ci # data.values() isn't picklable, only its iterator 11977db96d56Sopenharmony_ci it = reversed(data.values()) 11987db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 11997db96d56Sopenharmony_ci it = pickle.loads(d) 12007db96d56Sopenharmony_ci self.assertEqual(list(it), list(reversed(data.values()))) 12017db96d56Sopenharmony_ci 12027db96d56Sopenharmony_ci it = pickle.loads(d) 12037db96d56Sopenharmony_ci drop = next(it) 12047db96d56Sopenharmony_ci d = pickle.dumps(it, proto) 12057db96d56Sopenharmony_ci it = pickle.loads(d) 12067db96d56Sopenharmony_ci values = list(it) + [drop] 12077db96d56Sopenharmony_ci self.assertEqual(sorted(values), sorted(data.values())) 12087db96d56Sopenharmony_ci 12097db96d56Sopenharmony_ci def test_instance_dict_getattr_str_subclass(self): 12107db96d56Sopenharmony_ci class Foo: 12117db96d56Sopenharmony_ci def __init__(self, msg): 12127db96d56Sopenharmony_ci self.msg = msg 12137db96d56Sopenharmony_ci f = Foo('123') 12147db96d56Sopenharmony_ci class _str(str): 12157db96d56Sopenharmony_ci pass 12167db96d56Sopenharmony_ci self.assertEqual(f.msg, getattr(f, _str('msg'))) 12177db96d56Sopenharmony_ci self.assertEqual(f.msg, f.__dict__[_str('msg')]) 12187db96d56Sopenharmony_ci 12197db96d56Sopenharmony_ci def test_object_set_item_single_instance_non_str_key(self): 12207db96d56Sopenharmony_ci class Foo: pass 12217db96d56Sopenharmony_ci f = Foo() 12227db96d56Sopenharmony_ci f.__dict__[1] = 1 12237db96d56Sopenharmony_ci f.a = 'a' 12247db96d56Sopenharmony_ci self.assertEqual(f.__dict__, {1:1, 'a':'a'}) 12257db96d56Sopenharmony_ci 12267db96d56Sopenharmony_ci def check_reentrant_insertion(self, mutate): 12277db96d56Sopenharmony_ci # This object will trigger mutation of the dict when replaced 12287db96d56Sopenharmony_ci # by another value. Note this relies on refcounting: the test 12297db96d56Sopenharmony_ci # won't achieve its purpose on fully-GCed Python implementations. 12307db96d56Sopenharmony_ci class Mutating: 12317db96d56Sopenharmony_ci def __del__(self): 12327db96d56Sopenharmony_ci mutate(d) 12337db96d56Sopenharmony_ci 12347db96d56Sopenharmony_ci d = {k: Mutating() for k in 'abcdefghijklmnopqr'} 12357db96d56Sopenharmony_ci for k in list(d): 12367db96d56Sopenharmony_ci d[k] = k 12377db96d56Sopenharmony_ci 12387db96d56Sopenharmony_ci def test_reentrant_insertion(self): 12397db96d56Sopenharmony_ci # Reentrant insertion shouldn't crash (see issue #22653) 12407db96d56Sopenharmony_ci def mutate(d): 12417db96d56Sopenharmony_ci d['b'] = 5 12427db96d56Sopenharmony_ci self.check_reentrant_insertion(mutate) 12437db96d56Sopenharmony_ci 12447db96d56Sopenharmony_ci def mutate(d): 12457db96d56Sopenharmony_ci d.update(self.__dict__) 12467db96d56Sopenharmony_ci d.clear() 12477db96d56Sopenharmony_ci self.check_reentrant_insertion(mutate) 12487db96d56Sopenharmony_ci 12497db96d56Sopenharmony_ci def mutate(d): 12507db96d56Sopenharmony_ci while d: 12517db96d56Sopenharmony_ci d.popitem() 12527db96d56Sopenharmony_ci self.check_reentrant_insertion(mutate) 12537db96d56Sopenharmony_ci 12547db96d56Sopenharmony_ci def test_merge_and_mutate(self): 12557db96d56Sopenharmony_ci class X: 12567db96d56Sopenharmony_ci def __hash__(self): 12577db96d56Sopenharmony_ci return 0 12587db96d56Sopenharmony_ci 12597db96d56Sopenharmony_ci def __eq__(self, o): 12607db96d56Sopenharmony_ci other.clear() 12617db96d56Sopenharmony_ci return False 12627db96d56Sopenharmony_ci 12637db96d56Sopenharmony_ci l = [(i,0) for i in range(1, 1337)] 12647db96d56Sopenharmony_ci other = dict(l) 12657db96d56Sopenharmony_ci other[X()] = 0 12667db96d56Sopenharmony_ci d = {X(): 0, 1: 1} 12677db96d56Sopenharmony_ci self.assertRaises(RuntimeError, d.update, other) 12687db96d56Sopenharmony_ci 12697db96d56Sopenharmony_ci def test_free_after_iterating(self): 12707db96d56Sopenharmony_ci support.check_free_after_iterating(self, iter, dict) 12717db96d56Sopenharmony_ci support.check_free_after_iterating(self, lambda d: iter(d.keys()), dict) 12727db96d56Sopenharmony_ci support.check_free_after_iterating(self, lambda d: iter(d.values()), dict) 12737db96d56Sopenharmony_ci support.check_free_after_iterating(self, lambda d: iter(d.items()), dict) 12747db96d56Sopenharmony_ci 12757db96d56Sopenharmony_ci def test_equal_operator_modifying_operand(self): 12767db96d56Sopenharmony_ci # test fix for seg fault reported in bpo-27945 part 3. 12777db96d56Sopenharmony_ci class X(): 12787db96d56Sopenharmony_ci def __del__(self): 12797db96d56Sopenharmony_ci dict_b.clear() 12807db96d56Sopenharmony_ci 12817db96d56Sopenharmony_ci def __eq__(self, other): 12827db96d56Sopenharmony_ci dict_a.clear() 12837db96d56Sopenharmony_ci return True 12847db96d56Sopenharmony_ci 12857db96d56Sopenharmony_ci def __hash__(self): 12867db96d56Sopenharmony_ci return 13 12877db96d56Sopenharmony_ci 12887db96d56Sopenharmony_ci dict_a = {X(): 0} 12897db96d56Sopenharmony_ci dict_b = {X(): X()} 12907db96d56Sopenharmony_ci self.assertTrue(dict_a == dict_b) 12917db96d56Sopenharmony_ci 12927db96d56Sopenharmony_ci # test fix for seg fault reported in bpo-38588 part 1. 12937db96d56Sopenharmony_ci class Y: 12947db96d56Sopenharmony_ci def __eq__(self, other): 12957db96d56Sopenharmony_ci dict_d.clear() 12967db96d56Sopenharmony_ci return True 12977db96d56Sopenharmony_ci 12987db96d56Sopenharmony_ci dict_c = {0: Y()} 12997db96d56Sopenharmony_ci dict_d = {0: set()} 13007db96d56Sopenharmony_ci self.assertTrue(dict_c == dict_d) 13017db96d56Sopenharmony_ci 13027db96d56Sopenharmony_ci def test_fromkeys_operator_modifying_dict_operand(self): 13037db96d56Sopenharmony_ci # test fix for seg fault reported in issue 27945 part 4a. 13047db96d56Sopenharmony_ci class X(int): 13057db96d56Sopenharmony_ci def __hash__(self): 13067db96d56Sopenharmony_ci return 13 13077db96d56Sopenharmony_ci 13087db96d56Sopenharmony_ci def __eq__(self, other): 13097db96d56Sopenharmony_ci if len(d) > 1: 13107db96d56Sopenharmony_ci d.clear() 13117db96d56Sopenharmony_ci return False 13127db96d56Sopenharmony_ci 13137db96d56Sopenharmony_ci d = {} # this is required to exist so that d can be constructed! 13147db96d56Sopenharmony_ci d = {X(1): 1, X(2): 2} 13157db96d56Sopenharmony_ci try: 13167db96d56Sopenharmony_ci dict.fromkeys(d) # shouldn't crash 13177db96d56Sopenharmony_ci except RuntimeError: # implementation defined 13187db96d56Sopenharmony_ci pass 13197db96d56Sopenharmony_ci 13207db96d56Sopenharmony_ci def test_fromkeys_operator_modifying_set_operand(self): 13217db96d56Sopenharmony_ci # test fix for seg fault reported in issue 27945 part 4b. 13227db96d56Sopenharmony_ci class X(int): 13237db96d56Sopenharmony_ci def __hash__(self): 13247db96d56Sopenharmony_ci return 13 13257db96d56Sopenharmony_ci 13267db96d56Sopenharmony_ci def __eq__(self, other): 13277db96d56Sopenharmony_ci if len(d) > 1: 13287db96d56Sopenharmony_ci d.clear() 13297db96d56Sopenharmony_ci return False 13307db96d56Sopenharmony_ci 13317db96d56Sopenharmony_ci d = {} # this is required to exist so that d can be constructed! 13327db96d56Sopenharmony_ci d = {X(1), X(2)} 13337db96d56Sopenharmony_ci try: 13347db96d56Sopenharmony_ci dict.fromkeys(d) # shouldn't crash 13357db96d56Sopenharmony_ci except RuntimeError: # implementation defined 13367db96d56Sopenharmony_ci pass 13377db96d56Sopenharmony_ci 13387db96d56Sopenharmony_ci def test_dictitems_contains_use_after_free(self): 13397db96d56Sopenharmony_ci class X: 13407db96d56Sopenharmony_ci def __eq__(self, other): 13417db96d56Sopenharmony_ci d.clear() 13427db96d56Sopenharmony_ci return NotImplemented 13437db96d56Sopenharmony_ci 13447db96d56Sopenharmony_ci d = {0: set()} 13457db96d56Sopenharmony_ci (0, X()) in d.items() 13467db96d56Sopenharmony_ci 13477db96d56Sopenharmony_ci def test_dict_contain_use_after_free(self): 13487db96d56Sopenharmony_ci # bpo-40489 13497db96d56Sopenharmony_ci class S(str): 13507db96d56Sopenharmony_ci def __eq__(self, other): 13517db96d56Sopenharmony_ci d.clear() 13527db96d56Sopenharmony_ci return NotImplemented 13537db96d56Sopenharmony_ci 13547db96d56Sopenharmony_ci def __hash__(self): 13557db96d56Sopenharmony_ci return hash('test') 13567db96d56Sopenharmony_ci 13577db96d56Sopenharmony_ci d = {S(): 'value'} 13587db96d56Sopenharmony_ci self.assertFalse('test' in d) 13597db96d56Sopenharmony_ci 13607db96d56Sopenharmony_ci def test_init_use_after_free(self): 13617db96d56Sopenharmony_ci class X: 13627db96d56Sopenharmony_ci def __hash__(self): 13637db96d56Sopenharmony_ci pair[:] = [] 13647db96d56Sopenharmony_ci return 13 13657db96d56Sopenharmony_ci 13667db96d56Sopenharmony_ci pair = [X(), 123] 13677db96d56Sopenharmony_ci dict([pair]) 13687db96d56Sopenharmony_ci 13697db96d56Sopenharmony_ci def test_oob_indexing_dictiter_iternextitem(self): 13707db96d56Sopenharmony_ci class X(int): 13717db96d56Sopenharmony_ci def __del__(self): 13727db96d56Sopenharmony_ci d.clear() 13737db96d56Sopenharmony_ci 13747db96d56Sopenharmony_ci d = {i: X(i) for i in range(8)} 13757db96d56Sopenharmony_ci 13767db96d56Sopenharmony_ci def iter_and_mutate(): 13777db96d56Sopenharmony_ci for result in d.items(): 13787db96d56Sopenharmony_ci if result[0] == 2: 13797db96d56Sopenharmony_ci d[2] = None # free d[2] --> X(2).__del__ was called 13807db96d56Sopenharmony_ci 13817db96d56Sopenharmony_ci self.assertRaises(RuntimeError, iter_and_mutate) 13827db96d56Sopenharmony_ci 13837db96d56Sopenharmony_ci def test_reversed(self): 13847db96d56Sopenharmony_ci d = {"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4} 13857db96d56Sopenharmony_ci del d["foo"] 13867db96d56Sopenharmony_ci r = reversed(d) 13877db96d56Sopenharmony_ci self.assertEqual(list(r), list('dcba')) 13887db96d56Sopenharmony_ci self.assertRaises(StopIteration, next, r) 13897db96d56Sopenharmony_ci 13907db96d56Sopenharmony_ci def test_reverse_iterator_for_empty_dict(self): 13917db96d56Sopenharmony_ci # bpo-38525: reversed iterator should work properly 13927db96d56Sopenharmony_ci 13937db96d56Sopenharmony_ci # empty dict is directly used for reference count test 13947db96d56Sopenharmony_ci self.assertEqual(list(reversed({})), []) 13957db96d56Sopenharmony_ci self.assertEqual(list(reversed({}.items())), []) 13967db96d56Sopenharmony_ci self.assertEqual(list(reversed({}.values())), []) 13977db96d56Sopenharmony_ci self.assertEqual(list(reversed({}.keys())), []) 13987db96d56Sopenharmony_ci 13997db96d56Sopenharmony_ci # dict() and {} don't trigger the same code path 14007db96d56Sopenharmony_ci self.assertEqual(list(reversed(dict())), []) 14017db96d56Sopenharmony_ci self.assertEqual(list(reversed(dict().items())), []) 14027db96d56Sopenharmony_ci self.assertEqual(list(reversed(dict().values())), []) 14037db96d56Sopenharmony_ci self.assertEqual(list(reversed(dict().keys())), []) 14047db96d56Sopenharmony_ci 14057db96d56Sopenharmony_ci def test_reverse_iterator_for_shared_shared_dicts(self): 14067db96d56Sopenharmony_ci class A: 14077db96d56Sopenharmony_ci def __init__(self, x, y): 14087db96d56Sopenharmony_ci if x: self.x = x 14097db96d56Sopenharmony_ci if y: self.y = y 14107db96d56Sopenharmony_ci 14117db96d56Sopenharmony_ci self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x']) 14127db96d56Sopenharmony_ci self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x']) 14137db96d56Sopenharmony_ci self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y']) 14147db96d56Sopenharmony_ci 14157db96d56Sopenharmony_ci def test_dict_copy_order(self): 14167db96d56Sopenharmony_ci # bpo-34320 14177db96d56Sopenharmony_ci od = collections.OrderedDict([('a', 1), ('b', 2)]) 14187db96d56Sopenharmony_ci od.move_to_end('a') 14197db96d56Sopenharmony_ci expected = list(od.items()) 14207db96d56Sopenharmony_ci 14217db96d56Sopenharmony_ci copy = dict(od) 14227db96d56Sopenharmony_ci self.assertEqual(list(copy.items()), expected) 14237db96d56Sopenharmony_ci 14247db96d56Sopenharmony_ci # dict subclass doesn't override __iter__ 14257db96d56Sopenharmony_ci class CustomDict(dict): 14267db96d56Sopenharmony_ci pass 14277db96d56Sopenharmony_ci 14287db96d56Sopenharmony_ci pairs = [('a', 1), ('b', 2), ('c', 3)] 14297db96d56Sopenharmony_ci 14307db96d56Sopenharmony_ci d = CustomDict(pairs) 14317db96d56Sopenharmony_ci self.assertEqual(pairs, list(dict(d).items())) 14327db96d56Sopenharmony_ci 14337db96d56Sopenharmony_ci class CustomReversedDict(dict): 14347db96d56Sopenharmony_ci def keys(self): 14357db96d56Sopenharmony_ci return reversed(list(dict.keys(self))) 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci __iter__ = keys 14387db96d56Sopenharmony_ci 14397db96d56Sopenharmony_ci def items(self): 14407db96d56Sopenharmony_ci return reversed(dict.items(self)) 14417db96d56Sopenharmony_ci 14427db96d56Sopenharmony_ci d = CustomReversedDict(pairs) 14437db96d56Sopenharmony_ci self.assertEqual(pairs[::-1], list(dict(d).items())) 14447db96d56Sopenharmony_ci 14457db96d56Sopenharmony_ci @support.cpython_only 14467db96d56Sopenharmony_ci def test_dict_items_result_gc(self): 14477db96d56Sopenharmony_ci # bpo-42536: dict.items's tuple-reuse speed trick breaks the GC's 14487db96d56Sopenharmony_ci # assumptions about what can be untracked. Make sure we re-track result 14497db96d56Sopenharmony_ci # tuples whenever we reuse them. 14507db96d56Sopenharmony_ci it = iter({None: []}.items()) 14517db96d56Sopenharmony_ci gc.collect() 14527db96d56Sopenharmony_ci # That GC collection probably untracked the recycled internal result 14537db96d56Sopenharmony_ci # tuple, which is initialized to (None, None). Make sure it's re-tracked 14547db96d56Sopenharmony_ci # when it's mutated and returned from __next__: 14557db96d56Sopenharmony_ci self.assertTrue(gc.is_tracked(next(it))) 14567db96d56Sopenharmony_ci 14577db96d56Sopenharmony_ci @support.cpython_only 14587db96d56Sopenharmony_ci def test_dict_items_result_gc_reversed(self): 14597db96d56Sopenharmony_ci # Same as test_dict_items_result_gc above, but reversed. 14607db96d56Sopenharmony_ci it = reversed({None: []}.items()) 14617db96d56Sopenharmony_ci gc.collect() 14627db96d56Sopenharmony_ci self.assertTrue(gc.is_tracked(next(it))) 14637db96d56Sopenharmony_ci 14647db96d56Sopenharmony_ci def test_str_nonstr(self): 14657db96d56Sopenharmony_ci # cpython uses a different lookup function if the dict only contains 14667db96d56Sopenharmony_ci # `str` keys. Make sure the unoptimized path is used when a non-`str` 14677db96d56Sopenharmony_ci # key appears. 14687db96d56Sopenharmony_ci 14697db96d56Sopenharmony_ci class StrSub(str): 14707db96d56Sopenharmony_ci pass 14717db96d56Sopenharmony_ci 14727db96d56Sopenharmony_ci eq_count = 0 14737db96d56Sopenharmony_ci # This class compares equal to the string 'key3' 14747db96d56Sopenharmony_ci class Key3: 14757db96d56Sopenharmony_ci def __hash__(self): 14767db96d56Sopenharmony_ci return hash('key3') 14777db96d56Sopenharmony_ci 14787db96d56Sopenharmony_ci def __eq__(self, other): 14797db96d56Sopenharmony_ci nonlocal eq_count 14807db96d56Sopenharmony_ci if isinstance(other, Key3) or isinstance(other, str) and other == 'key3': 14817db96d56Sopenharmony_ci eq_count += 1 14827db96d56Sopenharmony_ci return True 14837db96d56Sopenharmony_ci return False 14847db96d56Sopenharmony_ci 14857db96d56Sopenharmony_ci key3_1 = StrSub('key3') 14867db96d56Sopenharmony_ci key3_2 = Key3() 14877db96d56Sopenharmony_ci key3_3 = Key3() 14887db96d56Sopenharmony_ci 14897db96d56Sopenharmony_ci dicts = [] 14907db96d56Sopenharmony_ci 14917db96d56Sopenharmony_ci # Create dicts of the form `{'key1': 42, 'key2': 43, key3: 44}` in a 14927db96d56Sopenharmony_ci # bunch of different ways. In all cases, `key3` is not of type `str`. 14937db96d56Sopenharmony_ci # `key3_1` is a `str` subclass and `key3_2` is a completely unrelated 14947db96d56Sopenharmony_ci # type. 14957db96d56Sopenharmony_ci for key3 in (key3_1, key3_2): 14967db96d56Sopenharmony_ci # A literal 14977db96d56Sopenharmony_ci dicts.append({'key1': 42, 'key2': 43, key3: 44}) 14987db96d56Sopenharmony_ci 14997db96d56Sopenharmony_ci # key3 inserted via `dict.__setitem__` 15007db96d56Sopenharmony_ci d = {'key1': 42, 'key2': 43} 15017db96d56Sopenharmony_ci d[key3] = 44 15027db96d56Sopenharmony_ci dicts.append(d) 15037db96d56Sopenharmony_ci 15047db96d56Sopenharmony_ci # key3 inserted via `dict.setdefault` 15057db96d56Sopenharmony_ci d = {'key1': 42, 'key2': 43} 15067db96d56Sopenharmony_ci self.assertEqual(d.setdefault(key3, 44), 44) 15077db96d56Sopenharmony_ci dicts.append(d) 15087db96d56Sopenharmony_ci 15097db96d56Sopenharmony_ci # key3 inserted via `dict.update` 15107db96d56Sopenharmony_ci d = {'key1': 42, 'key2': 43} 15117db96d56Sopenharmony_ci d.update({key3: 44}) 15127db96d56Sopenharmony_ci dicts.append(d) 15137db96d56Sopenharmony_ci 15147db96d56Sopenharmony_ci # key3 inserted via `dict.__ior__` 15157db96d56Sopenharmony_ci d = {'key1': 42, 'key2': 43} 15167db96d56Sopenharmony_ci d |= {key3: 44} 15177db96d56Sopenharmony_ci dicts.append(d) 15187db96d56Sopenharmony_ci 15197db96d56Sopenharmony_ci # `dict(iterable)` 15207db96d56Sopenharmony_ci def make_pairs(): 15217db96d56Sopenharmony_ci yield ('key1', 42) 15227db96d56Sopenharmony_ci yield ('key2', 43) 15237db96d56Sopenharmony_ci yield (key3, 44) 15247db96d56Sopenharmony_ci d = dict(make_pairs()) 15257db96d56Sopenharmony_ci dicts.append(d) 15267db96d56Sopenharmony_ci 15277db96d56Sopenharmony_ci # `dict.copy` 15287db96d56Sopenharmony_ci d = d.copy() 15297db96d56Sopenharmony_ci dicts.append(d) 15307db96d56Sopenharmony_ci 15317db96d56Sopenharmony_ci # dict comprehension 15327db96d56Sopenharmony_ci d = {key: 42 + i for i,key in enumerate(['key1', 'key2', key3])} 15337db96d56Sopenharmony_ci dicts.append(d) 15347db96d56Sopenharmony_ci 15357db96d56Sopenharmony_ci for d in dicts: 15367db96d56Sopenharmony_ci with self.subTest(d=d): 15377db96d56Sopenharmony_ci self.assertEqual(d.get('key1'), 42) 15387db96d56Sopenharmony_ci 15397db96d56Sopenharmony_ci # Try to make an object that is of type `str` and is equal to 15407db96d56Sopenharmony_ci # `'key1'`, but (at least on cpython) is a different object. 15417db96d56Sopenharmony_ci noninterned_key1 = 'ke' 15427db96d56Sopenharmony_ci noninterned_key1 += 'y1' 15437db96d56Sopenharmony_ci if support.check_impl_detail(cpython=True): 15447db96d56Sopenharmony_ci # suppress a SyntaxWarning 15457db96d56Sopenharmony_ci interned_key1 = 'key1' 15467db96d56Sopenharmony_ci self.assertFalse(noninterned_key1 is interned_key1) 15477db96d56Sopenharmony_ci self.assertEqual(d.get(noninterned_key1), 42) 15487db96d56Sopenharmony_ci 15497db96d56Sopenharmony_ci self.assertEqual(d.get('key3'), 44) 15507db96d56Sopenharmony_ci self.assertEqual(d.get(key3_1), 44) 15517db96d56Sopenharmony_ci self.assertEqual(d.get(key3_2), 44) 15527db96d56Sopenharmony_ci 15537db96d56Sopenharmony_ci # `key3_3` itself is definitely not a dict key, so make sure 15547db96d56Sopenharmony_ci # that `__eq__` gets called. 15557db96d56Sopenharmony_ci # 15567db96d56Sopenharmony_ci # Note that this might not hold for `key3_1` and `key3_2` 15577db96d56Sopenharmony_ci # because they might be the same object as one of the dict keys, 15587db96d56Sopenharmony_ci # in which case implementations are allowed to skip the call to 15597db96d56Sopenharmony_ci # `__eq__`. 15607db96d56Sopenharmony_ci eq_count = 0 15617db96d56Sopenharmony_ci self.assertEqual(d.get(key3_3), 44) 15627db96d56Sopenharmony_ci self.assertGreaterEqual(eq_count, 1) 15637db96d56Sopenharmony_ci 15647db96d56Sopenharmony_ci 15657db96d56Sopenharmony_ciclass CAPITest(unittest.TestCase): 15667db96d56Sopenharmony_ci 15677db96d56Sopenharmony_ci # Test _PyDict_GetItem_KnownHash() 15687db96d56Sopenharmony_ci @support.cpython_only 15697db96d56Sopenharmony_ci def test_getitem_knownhash(self): 15707db96d56Sopenharmony_ci _testcapi = import_helper.import_module('_testcapi') 15717db96d56Sopenharmony_ci dict_getitem_knownhash = _testcapi.dict_getitem_knownhash 15727db96d56Sopenharmony_ci 15737db96d56Sopenharmony_ci d = {'x': 1, 'y': 2, 'z': 3} 15747db96d56Sopenharmony_ci self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1) 15757db96d56Sopenharmony_ci self.assertEqual(dict_getitem_knownhash(d, 'y', hash('y')), 2) 15767db96d56Sopenharmony_ci self.assertEqual(dict_getitem_knownhash(d, 'z', hash('z')), 3) 15777db96d56Sopenharmony_ci 15787db96d56Sopenharmony_ci # not a dict 15797db96d56Sopenharmony_ci self.assertRaises(SystemError, dict_getitem_knownhash, [], 1, hash(1)) 15807db96d56Sopenharmony_ci # key does not exist 15817db96d56Sopenharmony_ci self.assertRaises(KeyError, dict_getitem_knownhash, {}, 1, hash(1)) 15827db96d56Sopenharmony_ci 15837db96d56Sopenharmony_ci class Exc(Exception): pass 15847db96d56Sopenharmony_ci class BadEq: 15857db96d56Sopenharmony_ci def __eq__(self, other): 15867db96d56Sopenharmony_ci raise Exc 15877db96d56Sopenharmony_ci def __hash__(self): 15887db96d56Sopenharmony_ci return 7 15897db96d56Sopenharmony_ci 15907db96d56Sopenharmony_ci k1, k2 = BadEq(), BadEq() 15917db96d56Sopenharmony_ci d = {k1: 1} 15927db96d56Sopenharmony_ci self.assertEqual(dict_getitem_knownhash(d, k1, hash(k1)), 1) 15937db96d56Sopenharmony_ci self.assertRaises(Exc, dict_getitem_knownhash, d, k2, hash(k2)) 15947db96d56Sopenharmony_ci 15957db96d56Sopenharmony_ci 15967db96d56Sopenharmony_cifrom test import mapping_tests 15977db96d56Sopenharmony_ci 15987db96d56Sopenharmony_ciclass GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): 15997db96d56Sopenharmony_ci type2test = dict 16007db96d56Sopenharmony_ci 16017db96d56Sopenharmony_ciclass Dict(dict): 16027db96d56Sopenharmony_ci pass 16037db96d56Sopenharmony_ci 16047db96d56Sopenharmony_ciclass SubclassMappingTests(mapping_tests.BasicTestMappingProtocol): 16057db96d56Sopenharmony_ci type2test = Dict 16067db96d56Sopenharmony_ci 16077db96d56Sopenharmony_ci 16087db96d56Sopenharmony_ciif __name__ == "__main__": 16097db96d56Sopenharmony_ci unittest.main() 1610