Skip to content

Commit e656b34

Browse files
committed
chore: resolve review comment
1 parent 63a52d4 commit e656b34

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

Lib/test/test_ordered_dict.py

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -874,26 +874,6 @@ def side_effect(self):
874874
self.assertDictEqual(dict1, dict.fromkeys((0, 4.2)))
875875
self.assertDictEqual(dict2, dict.fromkeys((0, Key(), 4.2)))
876876

877-
def test_getitem_re_entrant_clear_during_copy(self):
878-
class Evil(self.OrderedDict):
879-
def __getitem__(self, key):
880-
super().clear()
881-
return None
882-
883-
evil_dict = Evil([(i, i) for i in range(4)])
884-
with self.assertRaises(RuntimeError):
885-
result = evil_dict.copy()
886-
887-
def test_getitem_re_entrant_modify_during_copy(self):
888-
class Modifier(self.OrderedDict):
889-
def __getitem__(self, key):
890-
self['new_key'] = 'new_value'
891-
return super().__getitem__(key)
892-
893-
original = Modifier([(1, 'one'), (2, 'two')])
894-
with self.assertRaises(RuntimeError):
895-
result = original.copy()
896-
897877

898878
@unittest.skipUnless(c_coll, 'requires the C version of the collections module')
899879
class CPythonOrderedDictTests(OrderedDictTests,
@@ -991,6 +971,77 @@ def test_weakref_list_is_not_traversed(self):
991971

992972
gc.collect()
993973

974+
def test_getitem_re_entrant_clear_during_copy(self):
975+
class Evil(self.OrderedDict):
976+
def __getitem__(self, key):
977+
super().clear()
978+
return None
979+
980+
evil_dict = Evil([(i, i) for i in range(4)])
981+
with self.assertRaises(RuntimeError):
982+
result = evil_dict.copy()
983+
984+
def test_getitem_re_entrant_modify_during_copy(self):
985+
class Modifier(self.OrderedDict):
986+
def __getitem__(self, key):
987+
self['new_key'] = 'new_value'
988+
return super().__getitem__(key)
989+
990+
original = Modifier([(1, 'one'), (2, 'two')])
991+
with self.assertRaises(RuntimeError):
992+
result = original.copy()
993+
994+
def test_getitem_re_entrant_delete_during_copy(self):
995+
class Deleter(self.OrderedDict):
996+
call_count = 0
997+
def __getitem__(self, key):
998+
Deleter.call_count += 1
999+
if Deleter.call_count == 1:
1000+
del self[3]
1001+
return super().__getitem__(key)
1002+
1003+
original = Deleter([(1, 'one'), (2, 'two'), (3, 'three')])
1004+
with self.assertRaises(RuntimeError):
1005+
result = original.copy()
1006+
1007+
def test_getitem_re_entrant_add_during_copy(self):
1008+
class MultiAdder(self.OrderedDict):
1009+
def __getitem__(self, key):
1010+
self['new_key1'] = 'new_value1'
1011+
return super().__getitem__(key)
1012+
1013+
original = MultiAdder([(1, 'one'), (2, 'two'), (3, 'three')])
1014+
with self.assertRaises(RuntimeError):
1015+
result = original.copy()
1016+
1017+
def test_getitem_re_entrant_pop_during_copy(self):
1018+
class Popper(self.OrderedDict):
1019+
call_count = 0
1020+
def __getitem__(self, key):
1021+
Popper.call_count += 1
1022+
if Popper.call_count == 1:
1023+
self.pop(3, None)
1024+
return super().__getitem__(key)
1025+
1026+
original = Popper([(1, 'one'), (2, 'two'), (3, 'three')])
1027+
with self.assertRaises(RuntimeError):
1028+
result = original.copy()
1029+
1030+
def test_getitem_re_entrant_mixed_mutation_during_copy(self):
1031+
class MixedMutator(self.OrderedDict):
1032+
call_count = 0
1033+
def __getitem__(self, key):
1034+
MixedMutator.call_count += 1
1035+
if MixedMutator.call_count == 1:
1036+
del self[3]
1037+
elif MixedMutator.call_count == 2:
1038+
self['new_key'] = 'new_value'
1039+
return super().__getitem__(key)
1040+
1041+
original = MixedMutator([(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')])
1042+
with self.assertRaises(RuntimeError):
1043+
result = original.copy()
1044+
9941045

9951046
class PurePythonOrderedDictSubclassTests(PurePythonOrderedDictTests):
9961047

Objects/odictobject.c

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1268,16 +1268,16 @@ OrderedDict_copy_impl(PyObject *od)
12681268
else {
12691269
PyODictObject *self = _PyODictObject_CAST(od);
12701270
size_t state = self->od_state;
1271-
_ODictNode *cur = _odict_FIRST(od);
1271+
_ODictNode *cur;
12721272

1273-
while (cur != NULL) {
1273+
_odict_FOREACH(od, cur) {
12741274
if (self->od_state != state) {
12751275
PyErr_SetString(PyExc_RuntimeError,
12761276
"OrderedDict mutated during iteration");
12771277
goto fail;
12781278
}
12791279
PyObject *key = Py_NewRef(_odictnode_KEY(cur));
1280-
PyObject *value = PyObject_GetItem((PyObject *)od, key);
1280+
PyObject *value = PyObject_GetItem(od, key);
12811281
if (value == NULL) {
12821282
Py_DECREF(key);
12831283
goto fail;
@@ -1289,15 +1289,12 @@ OrderedDict_copy_impl(PyObject *od)
12891289
"OrderedDict mutated during iteration");
12901290
goto fail;
12911291
}
1292-
if (PyObject_SetItem((PyObject *)od_copy, key, value) != 0) {
1293-
Py_DECREF(key);
1294-
Py_DECREF(value);
1295-
goto fail;
1296-
}
1292+
int rc = PyObject_SetItem(od_copy, key, value);
12971293
Py_DECREF(key);
12981294
Py_DECREF(value);
1299-
1300-
cur = _odictnode_NEXT(cur);
1295+
if (rc != 0) {
1296+
goto fail;
1297+
}
13011298
}
13021299
}
13031300
return od_copy;

0 commit comments

Comments
 (0)