From 06aed90a1fe6fa48919ff0f1f39181e886df9efc Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 9 Sep 2016 11:59:08 -0700 Subject: [PATCH] Issue #27576: Fix call order in OrderedDict.__init__(). --- Lib/test/test_ordered_dict.py | 13 +++++++++++++ Misc/NEWS | 2 ++ Objects/odictobject.c | 17 +++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ordered_dict.py b/Lib/test/test_ordered_dict.py index d6e72a6ed29..2da36d3032e 100644 --- a/Lib/test/test_ordered_dict.py +++ b/Lib/test/test_ordered_dict.py @@ -98,6 +98,19 @@ class OrderedDictTests: self.assertRaises(TypeError, OrderedDict().update, (), ()) self.assertRaises(TypeError, OrderedDict.update) + def test_init_calls(self): + calls = [] + class Spam: + def keys(self): + calls.append('keys') + return () + def items(self): + calls.append('items') + return () + + self.OrderedDict(Spam()) + self.assertEqual(calls, ['keys']) + def test_fromkeys(self): OrderedDict = self.OrderedDict od = OrderedDict.fromkeys('abc') diff --git a/Misc/NEWS b/Misc/NEWS index f99ca495ffc..1e29158d96b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -113,6 +113,8 @@ Core and Builtins Library ------- +- Issue #27576: Fix call order in OrderedDict.__init__(). + - email.generator.DecodedGenerator now supports the policy keyword. - Issue #28027: Remove undocumented modules from ``Lib/plat-*``: IN, CDROM, diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 5968e3f5d5a..22b1f1dfed9 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -2356,8 +2356,7 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) 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 */ + if PyDict_CheckExact(other) { PyObject *items; if (PyDict_CheckExact(other)) items = PyDict_Items(other); @@ -2400,6 +2399,20 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) if (res != 0 || PyErr_Occurred()) return NULL; } + else if (_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 { res = mutablemapping_add_pairs(self, other); Py_DECREF(other);