From 60c3d3551a96febac7b6016fb44605643842c686 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 11 Nov 2017 16:19:56 +0200 Subject: [PATCH] bpo-31572: Get rid of _PyObject_HasAttrId() in dict and OrderedDict. (#3728) Silence only AttributeError when get "key" and "items" attributes in the constructor and the update() method of dict and OrderedDict . --- Objects/dictobject.c | 17 ++++++++++---- Objects/odictobject.c | 53 ++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 779746a31aa..b20b85c909e 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2183,16 +2183,25 @@ dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, PyObject *arg = NULL; int result = 0; - if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) + if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) { result = -1; - + } else if (arg != NULL) { _Py_IDENTIFIER(keys); - if (_PyObject_HasAttrId(arg, &PyId_keys)) + PyObject *func = _PyObject_GetAttrId(arg, &PyId_keys); + if (func != NULL) { + Py_DECREF(func); result = PyDict_Merge(self, arg, 1); - else + } + else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); result = PyDict_MergeFromSeq2(self, arg, 1); + } + else { + result = -1; + } } + if (result == 0 && kwds != NULL) { if (PyArg_ValidateKeywordArguments(kwds)) result = PyDict_Merge(self, kwds, 1); diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 5d22ce71588..218aa2c5d9c 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -2343,15 +2343,12 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) } if (len) { + PyObject *func; PyObject *other = PyTuple_GET_ITEM(args, 0); /* borrowed reference */ assert(other != NULL); Py_INCREF(other); - if PyDict_CheckExact(other) { - PyObject *items; - if (PyDict_CheckExact(other)) - items = PyDict_Items(other); - else - items = _PyObject_CallMethodId(other, &PyId_items, NULL); + if (PyDict_CheckExact(other)) { + PyObject *items = PyDict_Items(other); Py_DECREF(other); if (items == NULL) return NULL; @@ -2359,10 +2356,14 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) Py_DECREF(items); if (res == -1) return NULL; + goto handle_kwargs; } - else if (_PyObject_HasAttrId(other, &PyId_keys)) { /* never fails */ + + func = _PyObject_GetAttrId(other, &PyId_keys); + if (func != NULL) { PyObject *keys, *iterator, *key; - keys = _PyObject_CallMethodIdObjArgs(other, &PyId_keys, NULL); + keys = _PyObject_CallNoArg(func); + Py_DECREF(func); if (keys == NULL) { Py_DECREF(other); return NULL; @@ -2388,29 +2389,45 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) Py_DECREF(iterator); if (res != 0 || PyErr_Occurred()) return NULL; + goto handle_kwargs; } - 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); + else if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { Py_DECREF(other); + return NULL; + } + else { + PyErr_Clear(); + } + + func = _PyObject_GetAttrId(other, &PyId_items); + if (func != NULL) { + PyObject *items; + Py_DECREF(other); + items = _PyObject_CallNoArg(func); + Py_DECREF(func); if (items == NULL) return NULL; res = mutablemapping_add_pairs(self, items); Py_DECREF(items); if (res == -1) return NULL; + goto handle_kwargs; + } + else if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(other); + return NULL; } else { - res = mutablemapping_add_pairs(self, other); - Py_DECREF(other); - if (res != 0) - return NULL; + PyErr_Clear(); } + + res = mutablemapping_add_pairs(self, other); + Py_DECREF(other); + if (res != 0) + return NULL; } + handle_kwargs: /* now handle kwargs */ assert(kwargs == NULL || PyDict_Check(kwargs)); if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) {