python (3.12.0)

(root)/
lib/
python3.12/
test/
test_dict.py
       1  import collections
       2  import collections.abc
       3  import gc
       4  import pickle
       5  import random
       6  import string
       7  import sys
       8  import unittest
       9  import weakref
      10  from test import support
      11  from test.support import import_helper, C_RECURSION_LIMIT
      12  
      13  
      14  class ESC[4;38;5;81mDictTest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
      15  
      16      def test_invalid_keyword_arguments(self):
      17          class ESC[4;38;5;81mCustom(ESC[4;38;5;149mdict):
      18              pass
      19          for invalid in {1 : 2}, Custom({1 : 2}):
      20              with self.assertRaises(TypeError):
      21                  dict(**invalid)
      22              with self.assertRaises(TypeError):
      23                  {}.update(**invalid)
      24  
      25      def test_constructor(self):
      26          # calling built-in types without argument must return empty
      27          self.assertEqual(dict(), {})
      28          self.assertIsNot(dict(), {})
      29  
      30      def test_literal_constructor(self):
      31          # check literal constructor for different sized dicts
      32          # (to exercise the BUILD_MAP oparg).
      33          for n in (0, 1, 6, 256, 400):
      34              items = [(''.join(random.sample(string.ascii_letters, 8)), i)
      35                       for i in range(n)]
      36              random.shuffle(items)
      37              formatted_items = ('{!r}: {:d}'.format(k, v) for k, v in items)
      38              dictliteral = '{' + ', '.join(formatted_items) + '}'
      39              self.assertEqual(eval(dictliteral), dict(items))
      40  
      41      def test_merge_operator(self):
      42  
      43          a = {0: 0, 1: 1, 2: 1}
      44          b = {1: 1, 2: 2, 3: 3}
      45  
      46          c = a.copy()
      47          c |= b
      48  
      49          self.assertEqual(a | b, {0: 0, 1: 1, 2: 2, 3: 3})
      50          self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3})
      51  
      52          c = b.copy()
      53          c |= a
      54  
      55          self.assertEqual(b | a, {1: 1, 2: 1, 3: 3, 0: 0})
      56          self.assertEqual(c, {1: 1, 2: 1, 3: 3, 0: 0})
      57  
      58          c = a.copy()
      59          c |= [(1, 1), (2, 2), (3, 3)]
      60  
      61          self.assertEqual(c, {0: 0, 1: 1, 2: 2, 3: 3})
      62  
      63          self.assertIs(a.__or__(None), NotImplemented)
      64          self.assertIs(a.__or__(()), NotImplemented)
      65          self.assertIs(a.__or__("BAD"), NotImplemented)
      66          self.assertIs(a.__or__(""), NotImplemented)
      67  
      68          self.assertRaises(TypeError, a.__ior__, None)
      69          self.assertEqual(a.__ior__(()), {0: 0, 1: 1, 2: 1})
      70          self.assertRaises(ValueError, a.__ior__, "BAD")
      71          self.assertEqual(a.__ior__(""), {0: 0, 1: 1, 2: 1})
      72  
      73      def test_bool(self):
      74          self.assertIs(not {}, True)
      75          self.assertTrue({1: 2})
      76          self.assertIs(bool({}), False)
      77          self.assertIs(bool({1: 2}), True)
      78  
      79      def test_keys(self):
      80          d = {}
      81          self.assertEqual(set(d.keys()), set())
      82          d = {'a': 1, 'b': 2}
      83          k = d.keys()
      84          self.assertEqual(set(k), {'a', 'b'})
      85          self.assertIn('a', k)
      86          self.assertIn('b', k)
      87          self.assertIn('a', d)
      88          self.assertIn('b', d)
      89          self.assertRaises(TypeError, d.keys, None)
      90          self.assertEqual(repr(dict(a=1).keys()), "dict_keys(['a'])")
      91  
      92      def test_values(self):
      93          d = {}
      94          self.assertEqual(set(d.values()), set())
      95          d = {1:2}
      96          self.assertEqual(set(d.values()), {2})
      97          self.assertRaises(TypeError, d.values, None)
      98          self.assertEqual(repr(dict(a=1).values()), "dict_values([1])")
      99  
     100      def test_items(self):
     101          d = {}
     102          self.assertEqual(set(d.items()), set())
     103  
     104          d = {1:2}
     105          self.assertEqual(set(d.items()), {(1, 2)})
     106          self.assertRaises(TypeError, d.items, None)
     107          self.assertEqual(repr(dict(a=1).items()), "dict_items([('a', 1)])")
     108  
     109      def test_views_mapping(self):
     110          mappingproxy = type(type.__dict__)
     111          class ESC[4;38;5;81mDict(ESC[4;38;5;149mdict):
     112              pass
     113          for cls in [dict, Dict]:
     114              d = cls()
     115              m1 = d.keys().mapping
     116              m2 = d.values().mapping
     117              m3 = d.items().mapping
     118  
     119              for m in [m1, m2, m3]:
     120                  self.assertIsInstance(m, mappingproxy)
     121                  self.assertEqual(m, d)
     122  
     123              d["foo"] = "bar"
     124  
     125              for m in [m1, m2, m3]:
     126                  self.assertIsInstance(m, mappingproxy)
     127                  self.assertEqual(m, d)
     128  
     129      def test_contains(self):
     130          d = {}
     131          self.assertNotIn('a', d)
     132          self.assertFalse('a' in d)
     133          self.assertTrue('a' not in d)
     134          d = {'a': 1, 'b': 2}
     135          self.assertIn('a', d)
     136          self.assertIn('b', d)
     137          self.assertNotIn('c', d)
     138  
     139          self.assertRaises(TypeError, d.__contains__)
     140  
     141      def test_len(self):
     142          d = {}
     143          self.assertEqual(len(d), 0)
     144          d = {'a': 1, 'b': 2}
     145          self.assertEqual(len(d), 2)
     146  
     147      def test_getitem(self):
     148          d = {'a': 1, 'b': 2}
     149          self.assertEqual(d['a'], 1)
     150          self.assertEqual(d['b'], 2)
     151          d['c'] = 3
     152          d['a'] = 4
     153          self.assertEqual(d['c'], 3)
     154          self.assertEqual(d['a'], 4)
     155          del d['b']
     156          self.assertEqual(d, {'a': 4, 'c': 3})
     157  
     158          self.assertRaises(TypeError, d.__getitem__)
     159  
     160          class ESC[4;38;5;81mBadEq(ESC[4;38;5;149mobject):
     161              def __eq__(self, other):
     162                  raise Exc()
     163              def __hash__(self):
     164                  return 24
     165  
     166          d = {}
     167          d[BadEq()] = 42
     168          self.assertRaises(KeyError, d.__getitem__, 23)
     169  
     170          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     171  
     172          class ESC[4;38;5;81mBadHash(ESC[4;38;5;149mobject):
     173              fail = False
     174              def __hash__(self):
     175                  if self.fail:
     176                      raise Exc()
     177                  else:
     178                      return 42
     179  
     180          x = BadHash()
     181          d[x] = 42
     182          x.fail = True
     183          self.assertRaises(Exc, d.__getitem__, x)
     184  
     185      def test_clear(self):
     186          d = {1:1, 2:2, 3:3}
     187          d.clear()
     188          self.assertEqual(d, {})
     189  
     190          self.assertRaises(TypeError, d.clear, None)
     191  
     192      def test_update(self):
     193          d = {}
     194          d.update({1:100})
     195          d.update({2:20})
     196          d.update({1:1, 2:2, 3:3})
     197          self.assertEqual(d, {1:1, 2:2, 3:3})
     198  
     199          d.update()
     200          self.assertEqual(d, {1:1, 2:2, 3:3})
     201  
     202          self.assertRaises((TypeError, AttributeError), d.update, None)
     203  
     204          class ESC[4;38;5;81mSimpleUserDict:
     205              def __init__(self):
     206                  self.d = {1:1, 2:2, 3:3}
     207              def keys(self):
     208                  return self.d.keys()
     209              def __getitem__(self, i):
     210                  return self.d[i]
     211          d.clear()
     212          d.update(SimpleUserDict())
     213          self.assertEqual(d, {1:1, 2:2, 3:3})
     214  
     215          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     216  
     217          d.clear()
     218          class ESC[4;38;5;81mFailingUserDict:
     219              def keys(self):
     220                  raise Exc
     221          self.assertRaises(Exc, d.update, FailingUserDict())
     222  
     223          class ESC[4;38;5;81mFailingUserDict:
     224              def keys(self):
     225                  class ESC[4;38;5;81mBogonIter:
     226                      def __init__(self):
     227                          self.i = 1
     228                      def __iter__(self):
     229                          return self
     230                      def __next__(self):
     231                          if self.i:
     232                              self.i = 0
     233                              return 'a'
     234                          raise Exc
     235                  return BogonIter()
     236              def __getitem__(self, key):
     237                  return key
     238          self.assertRaises(Exc, d.update, FailingUserDict())
     239  
     240          class ESC[4;38;5;81mFailingUserDict:
     241              def keys(self):
     242                  class ESC[4;38;5;81mBogonIter:
     243                      def __init__(self):
     244                          self.i = ord('a')
     245                      def __iter__(self):
     246                          return self
     247                      def __next__(self):
     248                          if self.i <= ord('z'):
     249                              rtn = chr(self.i)
     250                              self.i += 1
     251                              return rtn
     252                          raise StopIteration
     253                  return BogonIter()
     254              def __getitem__(self, key):
     255                  raise Exc
     256          self.assertRaises(Exc, d.update, FailingUserDict())
     257  
     258          class ESC[4;38;5;81mbadseq(ESC[4;38;5;149mobject):
     259              def __iter__(self):
     260                  return self
     261              def __next__(self):
     262                  raise Exc()
     263  
     264          self.assertRaises(Exc, {}.update, badseq())
     265  
     266          self.assertRaises(ValueError, {}.update, [(1, 2, 3)])
     267  
     268      def test_fromkeys(self):
     269          self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
     270          d = {}
     271          self.assertIsNot(d.fromkeys('abc'), d)
     272          self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None})
     273          self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0})
     274          self.assertEqual(d.fromkeys([]), {})
     275          def g():
     276              yield 1
     277          self.assertEqual(d.fromkeys(g()), {1:None})
     278          self.assertRaises(TypeError, {}.fromkeys, 3)
     279          class ESC[4;38;5;81mdictlike(ESC[4;38;5;149mdict): pass
     280          self.assertEqual(dictlike.fromkeys('a'), {'a':None})
     281          self.assertEqual(dictlike().fromkeys('a'), {'a':None})
     282          self.assertIsInstance(dictlike.fromkeys('a'), dictlike)
     283          self.assertIsInstance(dictlike().fromkeys('a'), dictlike)
     284          class ESC[4;38;5;81mmydict(ESC[4;38;5;149mdict):
     285              def __new__(cls):
     286                  return collections.UserDict()
     287          ud = mydict.fromkeys('ab')
     288          self.assertEqual(ud, {'a':None, 'b':None})
     289          self.assertIsInstance(ud, collections.UserDict)
     290          self.assertRaises(TypeError, dict.fromkeys)
     291  
     292          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     293  
     294          class ESC[4;38;5;81mbaddict1(ESC[4;38;5;149mdict):
     295              def __init__(self):
     296                  raise Exc()
     297  
     298          self.assertRaises(Exc, baddict1.fromkeys, [1])
     299  
     300          class ESC[4;38;5;81mBadSeq(ESC[4;38;5;149mobject):
     301              def __iter__(self):
     302                  return self
     303              def __next__(self):
     304                  raise Exc()
     305  
     306          self.assertRaises(Exc, dict.fromkeys, BadSeq())
     307  
     308          class ESC[4;38;5;81mbaddict2(ESC[4;38;5;149mdict):
     309              def __setitem__(self, key, value):
     310                  raise Exc()
     311  
     312          self.assertRaises(Exc, baddict2.fromkeys, [1])
     313  
     314          # test fast path for dictionary inputs
     315          d = dict(zip(range(6), range(6)))
     316          self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6)))
     317  
     318          class ESC[4;38;5;81mbaddict3(ESC[4;38;5;149mdict):
     319              def __new__(cls):
     320                  return d
     321          d = {i : i for i in range(10)}
     322          res = d.copy()
     323          res.update(a=None, b=None, c=None)
     324          self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res)
     325  
     326      def test_copy(self):
     327          d = {1: 1, 2: 2, 3: 3}
     328          self.assertIsNot(d.copy(), d)
     329          self.assertEqual(d.copy(), d)
     330          self.assertEqual(d.copy(), {1: 1, 2: 2, 3: 3})
     331  
     332          copy = d.copy()
     333          d[4] = 4
     334          self.assertNotEqual(copy, d)
     335  
     336          self.assertEqual({}.copy(), {})
     337          self.assertRaises(TypeError, d.copy, None)
     338  
     339      def test_copy_fuzz(self):
     340          for dict_size in [10, 100, 1000, 10000, 100000]:
     341              dict_size = random.randrange(
     342                  dict_size // 2, dict_size + dict_size // 2)
     343              with self.subTest(dict_size=dict_size):
     344                  d = {}
     345                  for i in range(dict_size):
     346                      d[i] = i
     347  
     348                  d2 = d.copy()
     349                  self.assertIsNot(d2, d)
     350                  self.assertEqual(d, d2)
     351                  d2['key'] = 'value'
     352                  self.assertNotEqual(d, d2)
     353                  self.assertEqual(len(d2), len(d) + 1)
     354  
     355      def test_copy_maintains_tracking(self):
     356          class ESC[4;38;5;81mA:
     357              pass
     358  
     359          key = A()
     360  
     361          for d in ({}, {'a': 1}, {key: 'val'}):
     362              d2 = d.copy()
     363              self.assertEqual(gc.is_tracked(d), gc.is_tracked(d2))
     364  
     365      def test_copy_noncompact(self):
     366          # Dicts don't compact themselves on del/pop operations.
     367          # Copy will use a slow merging strategy that produces
     368          # a compacted copy when roughly 33% of dict is a non-used
     369          # keys-space (to optimize memory footprint).
     370          # In this test we want to hit the slow/compacting
     371          # branch of dict.copy() and make sure it works OK.
     372          d = {k: k for k in range(1000)}
     373          for k in range(950):
     374              del d[k]
     375          d2 = d.copy()
     376          self.assertEqual(d2, d)
     377  
     378      def test_get(self):
     379          d = {}
     380          self.assertIs(d.get('c'), None)
     381          self.assertEqual(d.get('c', 3), 3)
     382          d = {'a': 1, 'b': 2}
     383          self.assertIs(d.get('c'), None)
     384          self.assertEqual(d.get('c', 3), 3)
     385          self.assertEqual(d.get('a'), 1)
     386          self.assertEqual(d.get('a', 3), 1)
     387          self.assertRaises(TypeError, d.get)
     388          self.assertRaises(TypeError, d.get, None, None, None)
     389  
     390      def test_setdefault(self):
     391          # dict.setdefault()
     392          d = {}
     393          self.assertIs(d.setdefault('key0'), None)
     394          d.setdefault('key0', [])
     395          self.assertIs(d.setdefault('key0'), None)
     396          d.setdefault('key', []).append(3)
     397          self.assertEqual(d['key'][0], 3)
     398          d.setdefault('key', []).append(4)
     399          self.assertEqual(len(d['key']), 2)
     400          self.assertRaises(TypeError, d.setdefault)
     401  
     402          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     403  
     404          class ESC[4;38;5;81mBadHash(ESC[4;38;5;149mobject):
     405              fail = False
     406              def __hash__(self):
     407                  if self.fail:
     408                      raise Exc()
     409                  else:
     410                      return 42
     411  
     412          x = BadHash()
     413          d[x] = 42
     414          x.fail = True
     415          self.assertRaises(Exc, d.setdefault, x, [])
     416  
     417      def test_setdefault_atomic(self):
     418          # Issue #13521: setdefault() calls __hash__ and __eq__ only once.
     419          class ESC[4;38;5;81mHashed(ESC[4;38;5;149mobject):
     420              def __init__(self):
     421                  self.hash_count = 0
     422                  self.eq_count = 0
     423              def __hash__(self):
     424                  self.hash_count += 1
     425                  return 42
     426              def __eq__(self, other):
     427                  self.eq_count += 1
     428                  return id(self) == id(other)
     429          hashed1 = Hashed()
     430          y = {hashed1: 5}
     431          hashed2 = Hashed()
     432          y.setdefault(hashed2, [])
     433          self.assertEqual(hashed1.hash_count, 1)
     434          self.assertEqual(hashed2.hash_count, 1)
     435          self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
     436  
     437      def test_setitem_atomic_at_resize(self):
     438          class ESC[4;38;5;81mHashed(ESC[4;38;5;149mobject):
     439              def __init__(self):
     440                  self.hash_count = 0
     441                  self.eq_count = 0
     442              def __hash__(self):
     443                  self.hash_count += 1
     444                  return 42
     445              def __eq__(self, other):
     446                  self.eq_count += 1
     447                  return id(self) == id(other)
     448          hashed1 = Hashed()
     449          # 5 items
     450          y = {hashed1: 5, 0: 0, 1: 1, 2: 2, 3: 3}
     451          hashed2 = Hashed()
     452          # 6th item forces a resize
     453          y[hashed2] = []
     454          self.assertEqual(hashed1.hash_count, 1)
     455          self.assertEqual(hashed2.hash_count, 1)
     456          self.assertEqual(hashed1.eq_count + hashed2.eq_count, 1)
     457  
     458      def test_popitem(self):
     459          # dict.popitem()
     460          for copymode in -1, +1:
     461              # -1: b has same structure as a
     462              # +1: b is a.copy()
     463              for log2size in range(12):
     464                  size = 2**log2size
     465                  a = {}
     466                  b = {}
     467                  for i in range(size):
     468                      a[repr(i)] = i
     469                      if copymode < 0:
     470                          b[repr(i)] = i
     471                  if copymode > 0:
     472                      b = a.copy()
     473                  for i in range(size):
     474                      ka, va = ta = a.popitem()
     475                      self.assertEqual(va, int(ka))
     476                      kb, vb = tb = b.popitem()
     477                      self.assertEqual(vb, int(kb))
     478                      self.assertFalse(copymode < 0 and ta != tb)
     479                  self.assertFalse(a)
     480                  self.assertFalse(b)
     481  
     482          d = {}
     483          self.assertRaises(KeyError, d.popitem)
     484  
     485      def test_pop(self):
     486          # Tests for pop with specified key
     487          d = {}
     488          k, v = 'abc', 'def'
     489          d[k] = v
     490          self.assertRaises(KeyError, d.pop, 'ghi')
     491  
     492          self.assertEqual(d.pop(k), v)
     493          self.assertEqual(len(d), 0)
     494  
     495          self.assertRaises(KeyError, d.pop, k)
     496  
     497          self.assertEqual(d.pop(k, v), v)
     498          d[k] = v
     499          self.assertEqual(d.pop(k, 1), v)
     500  
     501          self.assertRaises(TypeError, d.pop)
     502  
     503          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     504  
     505          class ESC[4;38;5;81mBadHash(ESC[4;38;5;149mobject):
     506              fail = False
     507              def __hash__(self):
     508                  if self.fail:
     509                      raise Exc()
     510                  else:
     511                      return 42
     512  
     513          x = BadHash()
     514          d[x] = 42
     515          x.fail = True
     516          self.assertRaises(Exc, d.pop, x)
     517  
     518      def test_mutating_iteration(self):
     519          # changing dict size during iteration
     520          d = {}
     521          d[1] = 1
     522          with self.assertRaises(RuntimeError):
     523              for i in d:
     524                  d[i+1] = 1
     525  
     526      def test_mutating_iteration_delete(self):
     527          # change dict content during iteration
     528          d = {}
     529          d[0] = 0
     530          with self.assertRaises(RuntimeError):
     531              for i in d:
     532                  del d[0]
     533                  d[0] = 0
     534  
     535      def test_mutating_iteration_delete_over_values(self):
     536          # change dict content during iteration
     537          d = {}
     538          d[0] = 0
     539          with self.assertRaises(RuntimeError):
     540              for i in d.values():
     541                  del d[0]
     542                  d[0] = 0
     543  
     544      def test_mutating_iteration_delete_over_items(self):
     545          # change dict content during iteration
     546          d = {}
     547          d[0] = 0
     548          with self.assertRaises(RuntimeError):
     549              for i in d.items():
     550                  del d[0]
     551                  d[0] = 0
     552  
     553      def test_mutating_lookup(self):
     554          # changing dict during a lookup (issue #14417)
     555          class ESC[4;38;5;81mNastyKey:
     556              mutate_dict = None
     557  
     558              def __init__(self, value):
     559                  self.value = value
     560  
     561              def __hash__(self):
     562                  # hash collision!
     563                  return 1
     564  
     565              def __eq__(self, other):
     566                  if NastyKey.mutate_dict:
     567                      mydict, key = NastyKey.mutate_dict
     568                      NastyKey.mutate_dict = None
     569                      del mydict[key]
     570                  return self.value == other.value
     571  
     572          key1 = NastyKey(1)
     573          key2 = NastyKey(2)
     574          d = {key1: 1}
     575          NastyKey.mutate_dict = (d, key1)
     576          d[key2] = 2
     577          self.assertEqual(d, {key2: 2})
     578  
     579      def test_repr(self):
     580          d = {}
     581          self.assertEqual(repr(d), '{}')
     582          d[1] = 2
     583          self.assertEqual(repr(d), '{1: 2}')
     584          d = {}
     585          d[1] = d
     586          self.assertEqual(repr(d), '{1: {...}}')
     587  
     588          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     589  
     590          class ESC[4;38;5;81mBadRepr(ESC[4;38;5;149mobject):
     591              def __repr__(self):
     592                  raise Exc()
     593  
     594          d = {1: BadRepr()}
     595          self.assertRaises(Exc, repr, d)
     596  
     597      def test_repr_deep(self):
     598          d = {}
     599          for i in range(C_RECURSION_LIMIT + 1):
     600              d = {1: d}
     601          self.assertRaises(RecursionError, repr, d)
     602  
     603      def test_eq(self):
     604          self.assertEqual({}, {})
     605          self.assertEqual({1: 2}, {1: 2})
     606  
     607          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
     608  
     609          class ESC[4;38;5;81mBadCmp(ESC[4;38;5;149mobject):
     610              def __eq__(self, other):
     611                  raise Exc()
     612              def __hash__(self):
     613                  return 1
     614  
     615          d1 = {BadCmp(): 1}
     616          d2 = {1: 1}
     617  
     618          with self.assertRaises(Exc):
     619              d1 == d2
     620  
     621      def test_keys_contained(self):
     622          self.helper_keys_contained(lambda x: x.keys())
     623          self.helper_keys_contained(lambda x: x.items())
     624  
     625      def helper_keys_contained(self, fn):
     626          # Test rich comparisons against dict key views, which should behave the
     627          # same as sets.
     628          empty = fn(dict())
     629          empty2 = fn(dict())
     630          smaller = fn({1:1, 2:2})
     631          larger = fn({1:1, 2:2, 3:3})
     632          larger2 = fn({1:1, 2:2, 3:3})
     633          larger3 = fn({4:1, 2:2, 3:3})
     634  
     635          self.assertTrue(smaller <  larger)
     636          self.assertTrue(smaller <= larger)
     637          self.assertTrue(larger >  smaller)
     638          self.assertTrue(larger >= smaller)
     639  
     640          self.assertFalse(smaller >= larger)
     641          self.assertFalse(smaller >  larger)
     642          self.assertFalse(larger  <= smaller)
     643          self.assertFalse(larger  <  smaller)
     644  
     645          self.assertFalse(smaller <  larger3)
     646          self.assertFalse(smaller <= larger3)
     647          self.assertFalse(larger3 >  smaller)
     648          self.assertFalse(larger3 >= smaller)
     649  
     650          # Inequality strictness
     651          self.assertTrue(larger2 >= larger)
     652          self.assertTrue(larger2 <= larger)
     653          self.assertFalse(larger2 > larger)
     654          self.assertFalse(larger2 < larger)
     655  
     656          self.assertTrue(larger == larger2)
     657          self.assertTrue(smaller != larger)
     658  
     659          # There is an optimization on the zero-element case.
     660          self.assertTrue(empty == empty2)
     661          self.assertFalse(empty != empty2)
     662          self.assertFalse(empty == smaller)
     663          self.assertTrue(empty != smaller)
     664  
     665          # With the same size, an elementwise compare happens
     666          self.assertTrue(larger != larger3)
     667          self.assertFalse(larger == larger3)
     668  
     669      def test_errors_in_view_containment_check(self):
     670          class ESC[4;38;5;81mC:
     671              def __eq__(self, other):
     672                  raise RuntimeError
     673  
     674          d1 = {1: C()}
     675          d2 = {1: C()}
     676          with self.assertRaises(RuntimeError):
     677              d1.items() == d2.items()
     678          with self.assertRaises(RuntimeError):
     679              d1.items() != d2.items()
     680          with self.assertRaises(RuntimeError):
     681              d1.items() <= d2.items()
     682          with self.assertRaises(RuntimeError):
     683              d1.items() >= d2.items()
     684  
     685          d3 = {1: C(), 2: C()}
     686          with self.assertRaises(RuntimeError):
     687              d2.items() < d3.items()
     688          with self.assertRaises(RuntimeError):
     689              d3.items() > d2.items()
     690  
     691      def test_dictview_set_operations_on_keys(self):
     692          k1 = {1:1, 2:2}.keys()
     693          k2 = {1:1, 2:2, 3:3}.keys()
     694          k3 = {4:4}.keys()
     695  
     696          self.assertEqual(k1 - k2, set())
     697          self.assertEqual(k1 - k3, {1,2})
     698          self.assertEqual(k2 - k1, {3})
     699          self.assertEqual(k3 - k1, {4})
     700          self.assertEqual(k1 & k2, {1,2})
     701          self.assertEqual(k1 & k3, set())
     702          self.assertEqual(k1 | k2, {1,2,3})
     703          self.assertEqual(k1 ^ k2, {3})
     704          self.assertEqual(k1 ^ k3, {1,2,4})
     705  
     706      def test_dictview_set_operations_on_items(self):
     707          k1 = {1:1, 2:2}.items()
     708          k2 = {1:1, 2:2, 3:3}.items()
     709          k3 = {4:4}.items()
     710  
     711          self.assertEqual(k1 - k2, set())
     712          self.assertEqual(k1 - k3, {(1,1), (2,2)})
     713          self.assertEqual(k2 - k1, {(3,3)})
     714          self.assertEqual(k3 - k1, {(4,4)})
     715          self.assertEqual(k1 & k2, {(1,1), (2,2)})
     716          self.assertEqual(k1 & k3, set())
     717          self.assertEqual(k1 | k2, {(1,1), (2,2), (3,3)})
     718          self.assertEqual(k1 ^ k2, {(3,3)})
     719          self.assertEqual(k1 ^ k3, {(1,1), (2,2), (4,4)})
     720  
     721      def test_items_symmetric_difference(self):
     722          rr = random.randrange
     723          for _ in range(100):
     724              left = {x:rr(3) for x in range(20) if rr(2)}
     725              right = {x:rr(3) for x in range(20) if rr(2)}
     726              with self.subTest(left=left, right=right):
     727                  expected = set(left.items()) ^ set(right.items())
     728                  actual = left.items() ^ right.items()
     729                  self.assertEqual(actual, expected)
     730  
     731      def test_dictview_mixed_set_operations(self):
     732          # Just a few for .keys()
     733          self.assertTrue({1:1}.keys() == {1})
     734          self.assertTrue({1} == {1:1}.keys())
     735          self.assertEqual({1:1}.keys() | {2}, {1, 2})
     736          self.assertEqual({2} | {1:1}.keys(), {1, 2})
     737          # And a few for .items()
     738          self.assertTrue({1:1}.items() == {(1,1)})
     739          self.assertTrue({(1,1)} == {1:1}.items())
     740          self.assertEqual({1:1}.items() | {2}, {(1,1), 2})
     741          self.assertEqual({2} | {1:1}.items(), {(1,1), 2})
     742  
     743      def test_missing(self):
     744          # Make sure dict doesn't have a __missing__ method
     745          self.assertFalse(hasattr(dict, "__missing__"))
     746          self.assertFalse(hasattr({}, "__missing__"))
     747          # Test several cases:
     748          # (D) subclass defines __missing__ method returning a value
     749          # (E) subclass defines __missing__ method raising RuntimeError
     750          # (F) subclass sets __missing__ instance variable (no effect)
     751          # (G) subclass doesn't define __missing__ at all
     752          class ESC[4;38;5;81mD(ESC[4;38;5;149mdict):
     753              def __missing__(self, key):
     754                  return 42
     755          d = D({1: 2, 3: 4})
     756          self.assertEqual(d[1], 2)
     757          self.assertEqual(d[3], 4)
     758          self.assertNotIn(2, d)
     759          self.assertNotIn(2, d.keys())
     760          self.assertEqual(d[2], 42)
     761  
     762          class ESC[4;38;5;81mE(ESC[4;38;5;149mdict):
     763              def __missing__(self, key):
     764                  raise RuntimeError(key)
     765          e = E()
     766          with self.assertRaises(RuntimeError) as c:
     767              e[42]
     768          self.assertEqual(c.exception.args, (42,))
     769  
     770          class ESC[4;38;5;81mF(ESC[4;38;5;149mdict):
     771              def __init__(self):
     772                  # An instance variable __missing__ should have no effect
     773                  self.__missing__ = lambda key: None
     774          f = F()
     775          with self.assertRaises(KeyError) as c:
     776              f[42]
     777          self.assertEqual(c.exception.args, (42,))
     778  
     779          class ESC[4;38;5;81mG(ESC[4;38;5;149mdict):
     780              pass
     781          g = G()
     782          with self.assertRaises(KeyError) as c:
     783              g[42]
     784          self.assertEqual(c.exception.args, (42,))
     785  
     786      def test_tuple_keyerror(self):
     787          # SF #1576657
     788          d = {}
     789          with self.assertRaises(KeyError) as c:
     790              d[(1,)]
     791          self.assertEqual(c.exception.args, ((1,),))
     792  
     793      def test_bad_key(self):
     794          # Dictionary lookups should fail if __eq__() raises an exception.
     795          class ESC[4;38;5;81mCustomException(ESC[4;38;5;149mException):
     796              pass
     797  
     798          class ESC[4;38;5;81mBadDictKey:
     799              def __hash__(self):
     800                  return hash(self.__class__)
     801  
     802              def __eq__(self, other):
     803                  if isinstance(other, self.__class__):
     804                      raise CustomException
     805                  return other
     806  
     807          d = {}
     808          x1 = BadDictKey()
     809          x2 = BadDictKey()
     810          d[x1] = 1
     811          for stmt in ['d[x2] = 2',
     812                       'z = d[x2]',
     813                       'x2 in d',
     814                       'd.get(x2)',
     815                       'd.setdefault(x2, 42)',
     816                       'd.pop(x2)',
     817                       'd.update({x2: 2})']:
     818              with self.assertRaises(CustomException):
     819                  exec(stmt, locals())
     820  
     821      def test_resize1(self):
     822          # Dict resizing bug, found by Jack Jansen in 2.2 CVS development.
     823          # This version got an assert failure in debug build, infinite loop in
     824          # release build.  Unfortunately, provoking this kind of stuff requires
     825          # a mix of inserts and deletes hitting exactly the right hash codes in
     826          # exactly the right order, and I can't think of a randomized approach
     827          # that would be *likely* to hit a failing case in reasonable time.
     828  
     829          d = {}
     830          for i in range(5):
     831              d[i] = i
     832          for i in range(5):
     833              del d[i]
     834          for i in range(5, 9):  # i==8 was the problem
     835              d[i] = i
     836  
     837      def test_resize2(self):
     838          # Another dict resizing bug (SF bug #1456209).
     839          # This caused Segmentation faults or Illegal instructions.
     840  
     841          class ESC[4;38;5;81mX(ESC[4;38;5;149mobject):
     842              def __hash__(self):
     843                  return 5
     844              def __eq__(self, other):
     845                  if resizing:
     846                      d.clear()
     847                  return False
     848          d = {}
     849          resizing = False
     850          d[X()] = 1
     851          d[X()] = 2
     852          d[X()] = 3
     853          d[X()] = 4
     854          d[X()] = 5
     855          # now trigger a resize
     856          resizing = True
     857          d[9] = 6
     858  
     859      def test_empty_presized_dict_in_freelist(self):
     860          # Bug #3537: if an empty but presized dict with a size larger
     861          # than 7 was in the freelist, it triggered an assertion failure
     862          with self.assertRaises(ZeroDivisionError):
     863              d = {'a': 1 // 0, 'b': None, 'c': None, 'd': None, 'e': None,
     864                   'f': None, 'g': None, 'h': None}
     865          d = {}
     866  
     867      def test_container_iterator(self):
     868          # Bug #3680: tp_traverse was not implemented for dictiter and
     869          # dictview objects.
     870          class ESC[4;38;5;81mC(ESC[4;38;5;149mobject):
     871              pass
     872          views = (dict.items, dict.values, dict.keys)
     873          for v in views:
     874              obj = C()
     875              ref = weakref.ref(obj)
     876              container = {obj: 1}
     877              obj.v = v(container)
     878              obj.x = iter(obj.v)
     879              del obj, container
     880              gc.collect()
     881              self.assertIs(ref(), None, "Cycle was not collected")
     882  
     883      def _not_tracked(self, t):
     884          # Nested containers can take several collections to untrack
     885          gc.collect()
     886          gc.collect()
     887          self.assertFalse(gc.is_tracked(t), t)
     888  
     889      def _tracked(self, t):
     890          self.assertTrue(gc.is_tracked(t), t)
     891          gc.collect()
     892          gc.collect()
     893          self.assertTrue(gc.is_tracked(t), t)
     894  
     895      def test_string_keys_can_track_values(self):
     896          # Test that this doesn't leak.
     897          for i in range(10):
     898              d = {}
     899              for j in range(10):
     900                  d[str(j)] = j
     901              d["foo"] = d
     902  
     903      @support.cpython_only
     904      def test_track_literals(self):
     905          # Test GC-optimization of dict literals
     906          x, y, z, w = 1.5, "a", (1, None), []
     907  
     908          self._not_tracked({})
     909          self._not_tracked({x:(), y:x, z:1})
     910          self._not_tracked({1: "a", "b": 2})
     911          self._not_tracked({1: 2, (None, True, False, ()): int})
     912          self._not_tracked({1: object()})
     913  
     914          # Dicts with mutable elements are always tracked, even if those
     915          # elements are not tracked right now.
     916          self._tracked({1: []})
     917          self._tracked({1: ([],)})
     918          self._tracked({1: {}})
     919          self._tracked({1: set()})
     920  
     921      @support.cpython_only
     922      def test_track_dynamic(self):
     923          # Test GC-optimization of dynamically-created dicts
     924          class ESC[4;38;5;81mMyObject(ESC[4;38;5;149mobject):
     925              pass
     926          x, y, z, w, o = 1.5, "a", (1, object()), [], MyObject()
     927  
     928          d = dict()
     929          self._not_tracked(d)
     930          d[1] = "a"
     931          self._not_tracked(d)
     932          d[y] = 2
     933          self._not_tracked(d)
     934          d[z] = 3
     935          self._not_tracked(d)
     936          self._not_tracked(d.copy())
     937          d[4] = w
     938          self._tracked(d)
     939          self._tracked(d.copy())
     940          d[4] = None
     941          self._not_tracked(d)
     942          self._not_tracked(d.copy())
     943  
     944          # dd isn't tracked right now, but it may mutate and therefore d
     945          # which contains it must be tracked.
     946          d = dict()
     947          dd = dict()
     948          d[1] = dd
     949          self._not_tracked(dd)
     950          self._tracked(d)
     951          dd[1] = d
     952          self._tracked(dd)
     953  
     954          d = dict.fromkeys([x, y, z])
     955          self._not_tracked(d)
     956          dd = dict()
     957          dd.update(d)
     958          self._not_tracked(dd)
     959          d = dict.fromkeys([x, y, z, o])
     960          self._tracked(d)
     961          dd = dict()
     962          dd.update(d)
     963          self._tracked(dd)
     964  
     965          d = dict(x=x, y=y, z=z)
     966          self._not_tracked(d)
     967          d = dict(x=x, y=y, z=z, w=w)
     968          self._tracked(d)
     969          d = dict()
     970          d.update(x=x, y=y, z=z)
     971          self._not_tracked(d)
     972          d.update(w=w)
     973          self._tracked(d)
     974  
     975          d = dict([(x, y), (z, 1)])
     976          self._not_tracked(d)
     977          d = dict([(x, y), (z, w)])
     978          self._tracked(d)
     979          d = dict()
     980          d.update([(x, y), (z, 1)])
     981          self._not_tracked(d)
     982          d.update([(x, y), (z, w)])
     983          self._tracked(d)
     984  
     985      @support.cpython_only
     986      def test_track_subtypes(self):
     987          # Dict subtypes are always tracked
     988          class ESC[4;38;5;81mMyDict(ESC[4;38;5;149mdict):
     989              pass
     990          self._tracked(MyDict())
     991  
     992      def make_shared_key_dict(self, n):
     993          class ESC[4;38;5;81mC:
     994              pass
     995  
     996          dicts = []
     997          for i in range(n):
     998              a = C()
     999              a.x, a.y, a.z = 1, 2, 3
    1000              dicts.append(a.__dict__)
    1001  
    1002          return dicts
    1003  
    1004      @support.cpython_only
    1005      def test_splittable_setdefault(self):
    1006          """split table must keep correct insertion
    1007          order when attributes are adding using setdefault()"""
    1008          a, b = self.make_shared_key_dict(2)
    1009  
    1010          a['a'] = 1
    1011          size_a = sys.getsizeof(a)
    1012          a['b'] = 2
    1013          b.setdefault('b', 2)
    1014          size_b = sys.getsizeof(b)
    1015          b['a'] = 1
    1016  
    1017          self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b'])
    1018          self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a'])
    1019  
    1020      @support.cpython_only
    1021      def test_splittable_del(self):
    1022          """split table must be combined when del d[k]"""
    1023          a, b = self.make_shared_key_dict(2)
    1024  
    1025          orig_size = sys.getsizeof(a)
    1026  
    1027          del a['y']  # split table is combined
    1028          with self.assertRaises(KeyError):
    1029              del a['y']
    1030  
    1031          self.assertEqual(list(a), ['x', 'z'])
    1032          self.assertEqual(list(b), ['x', 'y', 'z'])
    1033  
    1034          # Two dicts have different insertion order.
    1035          a['y'] = 42
    1036          self.assertEqual(list(a), ['x', 'z', 'y'])
    1037          self.assertEqual(list(b), ['x', 'y', 'z'])
    1038  
    1039      @support.cpython_only
    1040      def test_splittable_pop(self):
    1041          a, b = self.make_shared_key_dict(2)
    1042  
    1043          a.pop('y')
    1044          with self.assertRaises(KeyError):
    1045              a.pop('y')
    1046  
    1047          self.assertEqual(list(a), ['x', 'z'])
    1048          self.assertEqual(list(b), ['x', 'y', 'z'])
    1049  
    1050          # Two dicts have different insertion order.
    1051          a['y'] = 42
    1052          self.assertEqual(list(a), ['x', 'z', 'y'])
    1053          self.assertEqual(list(b), ['x', 'y', 'z'])
    1054  
    1055      @support.cpython_only
    1056      def test_splittable_pop_pending(self):
    1057          """pop a pending key in a split table should not crash"""
    1058          a, b = self.make_shared_key_dict(2)
    1059  
    1060          a['a'] = 4
    1061          with self.assertRaises(KeyError):
    1062              b.pop('a')
    1063  
    1064      @support.cpython_only
    1065      def test_splittable_popitem(self):
    1066          """split table must be combined when d.popitem()"""
    1067          a, b = self.make_shared_key_dict(2)
    1068  
    1069          orig_size = sys.getsizeof(a)
    1070  
    1071          item = a.popitem()  # split table is combined
    1072          self.assertEqual(item, ('z', 3))
    1073          with self.assertRaises(KeyError):
    1074              del a['z']
    1075  
    1076          self.assertGreater(sys.getsizeof(a), orig_size)
    1077          self.assertEqual(list(a), ['x', 'y'])
    1078          self.assertEqual(list(b), ['x', 'y', 'z'])
    1079  
    1080      @support.cpython_only
    1081      def test_splittable_update(self):
    1082          """dict.update(other) must preserve order in other."""
    1083          class ESC[4;38;5;81mC:
    1084              def __init__(self, order):
    1085                  if order:
    1086                      self.a, self.b, self.c = 1, 2, 3
    1087                  else:
    1088                      self.c, self.b, self.a = 1, 2, 3
    1089          o = C(True)
    1090          o = C(False)  # o.__dict__ has reversed order.
    1091          self.assertEqual(list(o.__dict__), ["c", "b", "a"])
    1092  
    1093          d = {}
    1094          d.update(o.__dict__)
    1095          self.assertEqual(list(d), ["c", "b", "a"])
    1096  
    1097      @support.cpython_only
    1098      def test_splittable_to_generic_combinedtable(self):
    1099          """split table must be correctly resized and converted to generic combined table"""
    1100          class ESC[4;38;5;81mC:
    1101              pass
    1102  
    1103          a = C()
    1104          a.x = 1
    1105          d = a.__dict__
    1106          before_resize = sys.getsizeof(d)
    1107          d[2] = 2 # split table is resized to a generic combined table
    1108  
    1109          self.assertGreater(sys.getsizeof(d), before_resize)
    1110          self.assertEqual(list(d), ['x', 2])
    1111  
    1112      def test_iterator_pickling(self):
    1113          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1114              data = {1:"a", 2:"b", 3:"c"}
    1115              it = iter(data)
    1116              d = pickle.dumps(it, proto)
    1117              it = pickle.loads(d)
    1118              self.assertEqual(list(it), list(data))
    1119  
    1120              it = pickle.loads(d)
    1121              try:
    1122                  drop = next(it)
    1123              except StopIteration:
    1124                  continue
    1125              d = pickle.dumps(it, proto)
    1126              it = pickle.loads(d)
    1127              del data[drop]
    1128              self.assertEqual(list(it), list(data))
    1129  
    1130      def test_itemiterator_pickling(self):
    1131          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1132              data = {1:"a", 2:"b", 3:"c"}
    1133              # dictviews aren't picklable, only their iterators
    1134              itorg = iter(data.items())
    1135              d = pickle.dumps(itorg, proto)
    1136              it = pickle.loads(d)
    1137              # note that the type of the unpickled iterator
    1138              # is not necessarily the same as the original.  It is
    1139              # merely an object supporting the iterator protocol, yielding
    1140              # the same objects as the original one.
    1141              # self.assertEqual(type(itorg), type(it))
    1142              self.assertIsInstance(it, collections.abc.Iterator)
    1143              self.assertEqual(dict(it), data)
    1144  
    1145              it = pickle.loads(d)
    1146              drop = next(it)
    1147              d = pickle.dumps(it, proto)
    1148              it = pickle.loads(d)
    1149              del data[drop[0]]
    1150              self.assertEqual(dict(it), data)
    1151  
    1152      def test_valuesiterator_pickling(self):
    1153          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1154              data = {1:"a", 2:"b", 3:"c"}
    1155              # data.values() isn't picklable, only its iterator
    1156              it = iter(data.values())
    1157              d = pickle.dumps(it, proto)
    1158              it = pickle.loads(d)
    1159              self.assertEqual(list(it), list(data.values()))
    1160  
    1161              it = pickle.loads(d)
    1162              drop = next(it)
    1163              d = pickle.dumps(it, proto)
    1164              it = pickle.loads(d)
    1165              values = list(it) + [drop]
    1166              self.assertEqual(sorted(values), sorted(list(data.values())))
    1167  
    1168      def test_reverseiterator_pickling(self):
    1169          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1170              data = {1:"a", 2:"b", 3:"c"}
    1171              it = reversed(data)
    1172              d = pickle.dumps(it, proto)
    1173              it = pickle.loads(d)
    1174              self.assertEqual(list(it), list(reversed(data)))
    1175  
    1176              it = pickle.loads(d)
    1177              try:
    1178                  drop = next(it)
    1179              except StopIteration:
    1180                  continue
    1181              d = pickle.dumps(it, proto)
    1182              it = pickle.loads(d)
    1183              del data[drop]
    1184              self.assertEqual(list(it), list(reversed(data)))
    1185  
    1186      def test_reverseitemiterator_pickling(self):
    1187          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1188              data = {1:"a", 2:"b", 3:"c"}
    1189              # dictviews aren't picklable, only their iterators
    1190              itorg = reversed(data.items())
    1191              d = pickle.dumps(itorg, proto)
    1192              it = pickle.loads(d)
    1193              # note that the type of the unpickled iterator
    1194              # is not necessarily the same as the original.  It is
    1195              # merely an object supporting the iterator protocol, yielding
    1196              # the same objects as the original one.
    1197              # self.assertEqual(type(itorg), type(it))
    1198              self.assertIsInstance(it, collections.abc.Iterator)
    1199              self.assertEqual(dict(it), data)
    1200  
    1201              it = pickle.loads(d)
    1202              drop = next(it)
    1203              d = pickle.dumps(it, proto)
    1204              it = pickle.loads(d)
    1205              del data[drop[0]]
    1206              self.assertEqual(dict(it), data)
    1207  
    1208      def test_reversevaluesiterator_pickling(self):
    1209          for proto in range(pickle.HIGHEST_PROTOCOL + 1):
    1210              data = {1:"a", 2:"b", 3:"c"}
    1211              # data.values() isn't picklable, only its iterator
    1212              it = reversed(data.values())
    1213              d = pickle.dumps(it, proto)
    1214              it = pickle.loads(d)
    1215              self.assertEqual(list(it), list(reversed(data.values())))
    1216  
    1217              it = pickle.loads(d)
    1218              drop = next(it)
    1219              d = pickle.dumps(it, proto)
    1220              it = pickle.loads(d)
    1221              values = list(it) + [drop]
    1222              self.assertEqual(sorted(values), sorted(data.values()))
    1223  
    1224      def test_instance_dict_getattr_str_subclass(self):
    1225          class ESC[4;38;5;81mFoo:
    1226              def __init__(self, msg):
    1227                  self.msg = msg
    1228          f = Foo('123')
    1229          class ESC[4;38;5;81m_str(ESC[4;38;5;149mstr):
    1230              pass
    1231          self.assertEqual(f.msg, getattr(f, _str('msg')))
    1232          self.assertEqual(f.msg, f.__dict__[_str('msg')])
    1233  
    1234      def test_object_set_item_single_instance_non_str_key(self):
    1235          class ESC[4;38;5;81mFoo: pass
    1236          f = Foo()
    1237          f.__dict__[1] = 1
    1238          f.a = 'a'
    1239          self.assertEqual(f.__dict__, {1:1, 'a':'a'})
    1240  
    1241      def check_reentrant_insertion(self, mutate):
    1242          # This object will trigger mutation of the dict when replaced
    1243          # by another value.  Note this relies on refcounting: the test
    1244          # won't achieve its purpose on fully-GCed Python implementations.
    1245          class ESC[4;38;5;81mMutating:
    1246              def __del__(self):
    1247                  mutate(d)
    1248  
    1249          d = {k: Mutating() for k in 'abcdefghijklmnopqr'}
    1250          for k in list(d):
    1251              d[k] = k
    1252  
    1253      def test_reentrant_insertion(self):
    1254          # Reentrant insertion shouldn't crash (see issue #22653)
    1255          def mutate(d):
    1256              d['b'] = 5
    1257          self.check_reentrant_insertion(mutate)
    1258  
    1259          def mutate(d):
    1260              d.update(self.__dict__)
    1261              d.clear()
    1262          self.check_reentrant_insertion(mutate)
    1263  
    1264          def mutate(d):
    1265              while d:
    1266                  d.popitem()
    1267          self.check_reentrant_insertion(mutate)
    1268  
    1269      def test_merge_and_mutate(self):
    1270          class ESC[4;38;5;81mX:
    1271              def __hash__(self):
    1272                  return 0
    1273  
    1274              def __eq__(self, o):
    1275                  other.clear()
    1276                  return False
    1277  
    1278          l = [(i,0) for i in range(1, 1337)]
    1279          other = dict(l)
    1280          other[X()] = 0
    1281          d = {X(): 0, 1: 1}
    1282          self.assertRaises(RuntimeError, d.update, other)
    1283  
    1284      def test_free_after_iterating(self):
    1285          support.check_free_after_iterating(self, iter, dict)
    1286          support.check_free_after_iterating(self, lambda d: iter(d.keys()), dict)
    1287          support.check_free_after_iterating(self, lambda d: iter(d.values()), dict)
    1288          support.check_free_after_iterating(self, lambda d: iter(d.items()), dict)
    1289  
    1290      def test_equal_operator_modifying_operand(self):
    1291          # test fix for seg fault reported in bpo-27945 part 3.
    1292          class ESC[4;38;5;81mX():
    1293              def __del__(self):
    1294                  dict_b.clear()
    1295  
    1296              def __eq__(self, other):
    1297                  dict_a.clear()
    1298                  return True
    1299  
    1300              def __hash__(self):
    1301                  return 13
    1302  
    1303          dict_a = {X(): 0}
    1304          dict_b = {X(): X()}
    1305          self.assertTrue(dict_a == dict_b)
    1306  
    1307          # test fix for seg fault reported in bpo-38588 part 1.
    1308          class ESC[4;38;5;81mY:
    1309              def __eq__(self, other):
    1310                  dict_d.clear()
    1311                  return True
    1312  
    1313          dict_c = {0: Y()}
    1314          dict_d = {0: set()}
    1315          self.assertTrue(dict_c == dict_d)
    1316  
    1317      def test_fromkeys_operator_modifying_dict_operand(self):
    1318          # test fix for seg fault reported in issue 27945 part 4a.
    1319          class ESC[4;38;5;81mX(ESC[4;38;5;149mint):
    1320              def __hash__(self):
    1321                  return 13
    1322  
    1323              def __eq__(self, other):
    1324                  if len(d) > 1:
    1325                      d.clear()
    1326                  return False
    1327  
    1328          d = {}  # this is required to exist so that d can be constructed!
    1329          d = {X(1): 1, X(2): 2}
    1330          try:
    1331              dict.fromkeys(d)  # shouldn't crash
    1332          except RuntimeError:  # implementation defined
    1333              pass
    1334  
    1335      def test_fromkeys_operator_modifying_set_operand(self):
    1336          # test fix for seg fault reported in issue 27945 part 4b.
    1337          class ESC[4;38;5;81mX(ESC[4;38;5;149mint):
    1338              def __hash__(self):
    1339                  return 13
    1340  
    1341              def __eq__(self, other):
    1342                  if len(d) > 1:
    1343                      d.clear()
    1344                  return False
    1345  
    1346          d = {}  # this is required to exist so that d can be constructed!
    1347          d = {X(1), X(2)}
    1348          try:
    1349              dict.fromkeys(d)  # shouldn't crash
    1350          except RuntimeError:  # implementation defined
    1351              pass
    1352  
    1353      def test_dictitems_contains_use_after_free(self):
    1354          class ESC[4;38;5;81mX:
    1355              def __eq__(self, other):
    1356                  d.clear()
    1357                  return NotImplemented
    1358  
    1359          d = {0: set()}
    1360          (0, X()) in d.items()
    1361  
    1362      def test_dict_contain_use_after_free(self):
    1363          # bpo-40489
    1364          class ESC[4;38;5;81mS(ESC[4;38;5;149mstr):
    1365              def __eq__(self, other):
    1366                  d.clear()
    1367                  return NotImplemented
    1368  
    1369              def __hash__(self):
    1370                  return hash('test')
    1371  
    1372          d = {S(): 'value'}
    1373          self.assertFalse('test' in d)
    1374  
    1375      def test_init_use_after_free(self):
    1376          class ESC[4;38;5;81mX:
    1377              def __hash__(self):
    1378                  pair[:] = []
    1379                  return 13
    1380  
    1381          pair = [X(), 123]
    1382          dict([pair])
    1383  
    1384      def test_oob_indexing_dictiter_iternextitem(self):
    1385          class ESC[4;38;5;81mX(ESC[4;38;5;149mint):
    1386              def __del__(self):
    1387                  d.clear()
    1388  
    1389          d = {i: X(i) for i in range(8)}
    1390  
    1391          def iter_and_mutate():
    1392              for result in d.items():
    1393                  if result[0] == 2:
    1394                      d[2] = None # free d[2] --> X(2).__del__ was called
    1395  
    1396          self.assertRaises(RuntimeError, iter_and_mutate)
    1397  
    1398      def test_reversed(self):
    1399          d = {"a": 1, "b": 2, "foo": 0, "c": 3, "d": 4}
    1400          del d["foo"]
    1401          r = reversed(d)
    1402          self.assertEqual(list(r), list('dcba'))
    1403          self.assertRaises(StopIteration, next, r)
    1404  
    1405      def test_reverse_iterator_for_empty_dict(self):
    1406          # bpo-38525: reversed iterator should work properly
    1407  
    1408          # empty dict is directly used for reference count test
    1409          self.assertEqual(list(reversed({})), [])
    1410          self.assertEqual(list(reversed({}.items())), [])
    1411          self.assertEqual(list(reversed({}.values())), [])
    1412          self.assertEqual(list(reversed({}.keys())), [])
    1413  
    1414          # dict() and {} don't trigger the same code path
    1415          self.assertEqual(list(reversed(dict())), [])
    1416          self.assertEqual(list(reversed(dict().items())), [])
    1417          self.assertEqual(list(reversed(dict().values())), [])
    1418          self.assertEqual(list(reversed(dict().keys())), [])
    1419  
    1420      def test_reverse_iterator_for_shared_shared_dicts(self):
    1421          class ESC[4;38;5;81mA:
    1422              def __init__(self, x, y):
    1423                  if x: self.x = x
    1424                  if y: self.y = y
    1425  
    1426          self.assertEqual(list(reversed(A(1, 2).__dict__)), ['y', 'x'])
    1427          self.assertEqual(list(reversed(A(1, 0).__dict__)), ['x'])
    1428          self.assertEqual(list(reversed(A(0, 1).__dict__)), ['y'])
    1429  
    1430      def test_dict_copy_order(self):
    1431          # bpo-34320
    1432          od = collections.OrderedDict([('a', 1), ('b', 2)])
    1433          od.move_to_end('a')
    1434          expected = list(od.items())
    1435  
    1436          copy = dict(od)
    1437          self.assertEqual(list(copy.items()), expected)
    1438  
    1439          # dict subclass doesn't override __iter__
    1440          class ESC[4;38;5;81mCustomDict(ESC[4;38;5;149mdict):
    1441              pass
    1442  
    1443          pairs = [('a', 1), ('b', 2), ('c', 3)]
    1444  
    1445          d = CustomDict(pairs)
    1446          self.assertEqual(pairs, list(dict(d).items()))
    1447  
    1448          class ESC[4;38;5;81mCustomReversedDict(ESC[4;38;5;149mdict):
    1449              def keys(self):
    1450                  return reversed(list(dict.keys(self)))
    1451  
    1452              __iter__ = keys
    1453  
    1454              def items(self):
    1455                  return reversed(dict.items(self))
    1456  
    1457          d = CustomReversedDict(pairs)
    1458          self.assertEqual(pairs[::-1], list(dict(d).items()))
    1459  
    1460      @support.cpython_only
    1461      def test_dict_items_result_gc(self):
    1462          # bpo-42536: dict.items's tuple-reuse speed trick breaks the GC's
    1463          # assumptions about what can be untracked. Make sure we re-track result
    1464          # tuples whenever we reuse them.
    1465          it = iter({None: []}.items())
    1466          gc.collect()
    1467          # That GC collection probably untracked the recycled internal result
    1468          # tuple, which is initialized to (None, None). Make sure it's re-tracked
    1469          # when it's mutated and returned from __next__:
    1470          self.assertTrue(gc.is_tracked(next(it)))
    1471  
    1472      @support.cpython_only
    1473      def test_dict_items_result_gc_reversed(self):
    1474          # Same as test_dict_items_result_gc above, but reversed.
    1475          it = reversed({None: []}.items())
    1476          gc.collect()
    1477          self.assertTrue(gc.is_tracked(next(it)))
    1478  
    1479      def test_str_nonstr(self):
    1480          # cpython uses a different lookup function if the dict only contains
    1481          # `str` keys. Make sure the unoptimized path is used when a non-`str`
    1482          # key appears.
    1483  
    1484          class ESC[4;38;5;81mStrSub(ESC[4;38;5;149mstr):
    1485              pass
    1486  
    1487          eq_count = 0
    1488          # This class compares equal to the string 'key3'
    1489          class ESC[4;38;5;81mKey3:
    1490              def __hash__(self):
    1491                  return hash('key3')
    1492  
    1493              def __eq__(self, other):
    1494                  nonlocal eq_count
    1495                  if isinstance(other, Key3) or isinstance(other, str) and other == 'key3':
    1496                      eq_count += 1
    1497                      return True
    1498                  return False
    1499  
    1500          key3_1 = StrSub('key3')
    1501          key3_2 = Key3()
    1502          key3_3 = Key3()
    1503  
    1504          dicts = []
    1505  
    1506          # Create dicts of the form `{'key1': 42, 'key2': 43, key3: 44}` in a
    1507          # bunch of different ways. In all cases, `key3` is not of type `str`.
    1508          # `key3_1` is a `str` subclass and `key3_2` is a completely unrelated
    1509          # type.
    1510          for key3 in (key3_1, key3_2):
    1511              # A literal
    1512              dicts.append({'key1': 42, 'key2': 43, key3: 44})
    1513  
    1514              # key3 inserted via `dict.__setitem__`
    1515              d = {'key1': 42, 'key2': 43}
    1516              d[key3] = 44
    1517              dicts.append(d)
    1518  
    1519              # key3 inserted via `dict.setdefault`
    1520              d = {'key1': 42, 'key2': 43}
    1521              self.assertEqual(d.setdefault(key3, 44), 44)
    1522              dicts.append(d)
    1523  
    1524              # key3 inserted via `dict.update`
    1525              d = {'key1': 42, 'key2': 43}
    1526              d.update({key3: 44})
    1527              dicts.append(d)
    1528  
    1529              # key3 inserted via `dict.__ior__`
    1530              d = {'key1': 42, 'key2': 43}
    1531              d |= {key3: 44}
    1532              dicts.append(d)
    1533  
    1534              # `dict(iterable)`
    1535              def make_pairs():
    1536                  yield ('key1', 42)
    1537                  yield ('key2', 43)
    1538                  yield (key3, 44)
    1539              d = dict(make_pairs())
    1540              dicts.append(d)
    1541  
    1542              # `dict.copy`
    1543              d = d.copy()
    1544              dicts.append(d)
    1545  
    1546              # dict comprehension
    1547              d = {key: 42 + i for i,key in enumerate(['key1', 'key2', key3])}
    1548              dicts.append(d)
    1549  
    1550          for d in dicts:
    1551              with self.subTest(d=d):
    1552                  self.assertEqual(d.get('key1'), 42)
    1553  
    1554                  # Try to make an object that is of type `str` and is equal to
    1555                  # `'key1'`, but (at least on cpython) is a different object.
    1556                  noninterned_key1 = 'ke'
    1557                  noninterned_key1 += 'y1'
    1558                  if support.check_impl_detail(cpython=True):
    1559                      # suppress a SyntaxWarning
    1560                      interned_key1 = 'key1'
    1561                      self.assertFalse(noninterned_key1 is interned_key1)
    1562                  self.assertEqual(d.get(noninterned_key1), 42)
    1563  
    1564                  self.assertEqual(d.get('key3'), 44)
    1565                  self.assertEqual(d.get(key3_1), 44)
    1566                  self.assertEqual(d.get(key3_2), 44)
    1567  
    1568                  # `key3_3` itself is definitely not a dict key, so make sure
    1569                  # that `__eq__` gets called.
    1570                  #
    1571                  # Note that this might not hold for `key3_1` and `key3_2`
    1572                  # because they might be the same object as one of the dict keys,
    1573                  # in which case implementations are allowed to skip the call to
    1574                  # `__eq__`.
    1575                  eq_count = 0
    1576                  self.assertEqual(d.get(key3_3), 44)
    1577                  self.assertGreaterEqual(eq_count, 1)
    1578  
    1579  
    1580  class ESC[4;38;5;81mCAPITest(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
    1581  
    1582      # Test _PyDict_GetItem_KnownHash()
    1583      @support.cpython_only
    1584      def test_getitem_knownhash(self):
    1585          _testcapi = import_helper.import_module('_testcapi')
    1586          dict_getitem_knownhash = _testcapi.dict_getitem_knownhash
    1587  
    1588          d = {'x': 1, 'y': 2, 'z': 3}
    1589          self.assertEqual(dict_getitem_knownhash(d, 'x', hash('x')), 1)
    1590          self.assertEqual(dict_getitem_knownhash(d, 'y', hash('y')), 2)
    1591          self.assertEqual(dict_getitem_knownhash(d, 'z', hash('z')), 3)
    1592  
    1593          # not a dict
    1594          self.assertRaises(SystemError, dict_getitem_knownhash, [], 1, hash(1))
    1595          # key does not exist
    1596          self.assertRaises(KeyError, dict_getitem_knownhash, {}, 1, hash(1))
    1597  
    1598          class ESC[4;38;5;81mExc(ESC[4;38;5;149mException): pass
    1599          class ESC[4;38;5;81mBadEq:
    1600              def __eq__(self, other):
    1601                  raise Exc
    1602              def __hash__(self):
    1603                  return 7
    1604  
    1605          k1, k2 = BadEq(), BadEq()
    1606          d = {k1: 1}
    1607          self.assertEqual(dict_getitem_knownhash(d, k1, hash(k1)), 1)
    1608          self.assertRaises(Exc, dict_getitem_knownhash, d, k2, hash(k2))
    1609  
    1610  
    1611  from test import mapping_tests
    1612  
    1613  class ESC[4;38;5;81mGeneralMappingTests(ESC[4;38;5;149mmapping_testsESC[4;38;5;149m.ESC[4;38;5;149mBasicTestMappingProtocol):
    1614      type2test = dict
    1615  
    1616  class ESC[4;38;5;81mDict(ESC[4;38;5;149mdict):
    1617      pass
    1618  
    1619  class ESC[4;38;5;81mSubclassMappingTests(ESC[4;38;5;149mmapping_testsESC[4;38;5;149m.ESC[4;38;5;149mBasicTestMappingProtocol):
    1620      type2test = Dict
    1621  
    1622  
    1623  if __name__ == "__main__":
    1624      unittest.main()