@@ -971,13 +971,16 @@ def test_weakref_list_is_not_traversed(self):
971971 gc .collect ()
972972
973973 def test_copy_concurrent_clear_in__getitem__ (self ):
974+ # Prevent crashes when a copy mutates the OrderedDict.
975+ # Regression tests for github.com/python/cpython/issues/142734.
974976 class MyOD (self .OrderedDict ):
975977 def __getitem__ (self , key ):
976978 super ().clear ()
977979 return None
978980
979- od = MyOD ([(i , i ) for i in range (4 )])
980- self .assertRaises (RuntimeError , od .copy )
981+ od = MyOD (enumerate (range (5 )))
982+ msg = "OrderedDict mutated during iteration"
983+ self .assertRaisesRegex (RuntimeError , msg , od .copy )
981984
982985 def test_copy_concurrent_insertion_in__getitem__ (self ):
983986 class MyOD (self .OrderedDict ):
@@ -986,7 +989,8 @@ def __getitem__(self, key):
986989 return super ().__getitem__ (key )
987990
988991 od = MyOD ([(1 , 'one' ), (2 , 'two' )])
989- self .assertRaises (RuntimeError , od .copy )
992+ msg = "OrderedDict mutated during iteration"
993+ self .assertRaisesRegex (RuntimeError , msg , od .copy )
990994
991995 def test_copy_concurrent_deletion_by_del_in__getitem__ (self ):
992996 class MyOD (self .OrderedDict ):
@@ -998,7 +1002,8 @@ def __getitem__(self, key):
9981002 return super ().__getitem__ (key )
9991003
10001004 od = MyOD ([(1 , 'one' ), (2 , 'two' ), (3 , 'three' )])
1001- self .assertRaises (RuntimeError , od .copy )
1005+ msg = "OrderedDict mutated during iteration"
1006+ self .assertRaisesRegex (RuntimeError , msg , od .copy )
10021007
10031008 def test_copy_concurrent_deletion_by_pop_in__getitem__ (self ):
10041009 class MyOD (self .OrderedDict ):
@@ -1010,16 +1015,15 @@ def __getitem__(self, key):
10101015 return super ().__getitem__ (key )
10111016
10121017 od = MyOD ([(1 , 'one' ), (2 , 'two' ), (3 , 'three' )])
1013- self .assertRaises (RuntimeError , od .copy )
1018+ msg = "OrderedDict mutated during iteration"
1019+ self .assertRaisesRegex (RuntimeError , msg , od .copy )
10141020
10151021 def test_copy_concurrent_deletion_and_set_in__getitem__ (self ):
10161022 class MyOD (self .OrderedDict ):
10171023 call_count = 0
1018- instance_count = 0
10191024
10201025 def __init__ (self , * args , ** kwargs ):
10211026 super ().__init__ (* args , ** kwargs )
1022- MyOD .instance_count += 1
10231027
10241028 def __getitem__ (self , key ):
10251029 self .call_count += 1
@@ -1030,12 +1034,13 @@ def __getitem__(self, key):
10301034 return super ().__getitem__ (key )
10311035
10321036 od = MyOD ([(1 , 'one' ), (2 , 'two' ), (3 , 'three' ), (4 , 'four' )])
1033- self . assertRaises ( RuntimeError , od . copy )
1034- self .assertEqual ( MyOD . instance_count , 2 )
1037+ msg = "OrderedDict mutated during iteration"
1038+ self .assertRaisesRegex ( RuntimeError , msg , od . copy )
10351039
10361040 def test_copy_concurrent_mutation_in__setitem__ (self ):
1037- od = None
10381041 class MyOD (self .OrderedDict ):
1042+ # When calling `__getitem__` on the source dict, `instance_count` is 1.
1043+ # When calling `__setitem__` on the target dict, `instance_count` is 2.
10391044 instance_count = 0
10401045
10411046 def __init__ (self , * args , ** kwargs ):
@@ -1048,7 +1053,8 @@ def __setitem__(self, key, value):
10481053 return super ().__setitem__ (key , value )
10491054
10501055 od = MyOD ([(1 , 'one' ), (2 , 'two' ), (3 , 'three' )])
1051- self .assertRaises (RuntimeError , od .copy )
1056+ msg = "OrderedDict mutated during iteration"
1057+ self .assertRaisesRegex (RuntimeError , msg , od .copy )
10521058 self .assertEqual (MyOD .instance_count , 2 )
10531059
10541060
0 commit comments