diff -r 5c76f787e695 Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py Mon Jul 25 00:31:54 2016 -0400 +++ b/Lib/test/test_ordered_dict.py Mon Jul 25 22:10:54 2016 +0800 @@ -97,6 +97,40 @@ self.assertRaises(TypeError, OrderedDict().update, (), ()) self.assertRaises(TypeError, OrderedDict.update) + # Make sure update obeys MutableMapping.update's invoking sequence + class X: + def __init__(self): + self.seq = pairs + self.index = 0 + def __getitem__(self, key): + for item in self.seq: + if key == item[0]: + return item[1] + raise KeyError + def __iter__(self): + return self + def __next__(self): + if self.index == len(self.seq): + raise StopIteration + else: + result = self.seq[self.index] + self.index += 1 + return result + def keys(self): + return [item[0] for item in self.seq[:-1]] + # should not be invoked, issue #27576 + def items(self): + return self.seq[:1] + # invoking .keys() first + od = OrderedDict() + od.update(X()) + self.assertEqual(list(od.items()), pairs[:-1]) + # if no .keys(), treat as pair input + od = OrderedDict() + del X.keys + od.update(X()) + self.assertEqual(list(od.items()), pairs) + def test_fromkeys(self): OrderedDict = self.OrderedDict od = OrderedDict.fromkeys('abc') diff -r 5c76f787e695 Objects/odictobject.c --- a/Objects/odictobject.c Mon Jul 25 00:31:54 2016 -0400 +++ b/Objects/odictobject.c Mon Jul 25 22:10:54 2016 +0800 @@ -2337,7 +2337,6 @@ { int res = 0; Py_ssize_t len; - _Py_IDENTIFIER(items); _Py_IDENTIFIER(keys); /* first handle args, if any */ @@ -2353,22 +2352,7 @@ PyObject *other = PyTuple_GET_ITEM(args, 0); /* borrowed reference */ assert(other != NULL); Py_INCREF(other); - if (PyDict_CheckExact(other) || - _PyObject_HasAttrId(other, &PyId_items)) { /* never fails */ - PyObject *items; - if (PyDict_CheckExact(other)) - items = PyDict_Items(other); - else - items = _PyObject_CallMethodId(other, &PyId_items, NULL); - Py_DECREF(other); - if (items == NULL) - return NULL; - res = mutablemapping_add_pairs(self, items); - Py_DECREF(items); - if (res == -1) - return NULL; - } - else if (_PyObject_HasAttrId(other, &PyId_keys)) { /* never fails */ + if (_PyObject_HasAttrId(other, &PyId_keys)) { /* never fails */ PyObject *keys, *iterator, *key; keys = _PyObject_CallMethodIdObjArgs(other, &PyId_keys, NULL); if (keys == NULL) {