diff options
author | Jeroen Demeyer <J.Demeyer@UGent.be> | 2019-06-07 10:20:24 (GMT) |
---|---|---|
committer | Petr Viktorin <encukou@gmail.com> | 2019-06-07 10:20:23 (GMT) |
commit | 3f345c39255dc3823dd989d4e3c93b12d18c44e0 (patch) | |
tree | 3c6780c3b01ff77f57df5bed426ec08cac68b586 | |
parent | 307d4cb957b9d34fdbbb40730f738c61c2e49be9 (diff) | |
download | cpython-3f345c39255dc3823dd989d4e3c93b12d18c44e0.zip cpython-3f345c39255dc3823dd989d4e3c93b12d18c44e0.tar.gz cpython-3f345c39255dc3823dd989d4e3c93b12d18c44e0.tar.bz2 |
bpo-37151: simplify classmethoddescr_call (GH-13340)
-rw-r--r-- | Lib/test/test_descr.py | 4 | ||||
-rw-r--r-- | Objects/descrobject.c | 44 |
2 files changed, 18 insertions, 30 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 6b018cc..301a2d2 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1613,8 +1613,8 @@ order (MRO) for bases """ spam_cm(spam.spamlist()) self.assertEqual( str(cm.exception), - "descriptor 'classmeth' requires a type " - "but received a 'xxsubtype.spamlist' instance") + "descriptor 'classmeth' for type 'xxsubtype.spamlist' " + "needs a type, not a 'xxsubtype.spamlist' as arg 2") with self.assertRaises(TypeError) as cm: spam_cm(list) diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 6c95a87..806c0af 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -300,16 +300,19 @@ _PyMethodDescr_Vectorcall(PyObject *descrobj, return result; } +/* Instances of classmethod_descriptor are unlikely to be called directly. + For one, the analogous class "classmethod" (for Python classes) is not + callable. Second, users are not likely to access a classmethod_descriptor + directly, since it means pulling it from the class __dict__. + + This is just an excuse to say that this doesn't need to be optimized: + we implement this simply by calling __get__ and then calling the result. +*/ static PyObject * classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { - Py_ssize_t argc; - PyObject *self, *result; - - /* Make sure that the first argument is acceptable as 'self' */ - assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); + Py_ssize_t argc = PyTuple_GET_SIZE(args); if (argc < 1) { PyErr_Format(PyExc_TypeError, "descriptor '%V' of '%.100s' " @@ -318,30 +321,15 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyDescr_TYPE(descr)->tp_name); return NULL; } - self = PyTuple_GET_ITEM(args, 0); - if (!PyType_Check(self)) { - PyErr_Format(PyExc_TypeError, - "descriptor '%V' requires a type " - "but received a '%.100s' instance", - descr_name((PyDescrObject *)descr), "?", - self->ob_type->tp_name); - return NULL; - } - if (!PyType_IsSubtype((PyTypeObject *)self, PyDescr_TYPE(descr))) { - PyErr_Format(PyExc_TypeError, - "descriptor '%V' requires a subtype of '%.100s' " - "but received '%.100s'", - descr_name((PyDescrObject *)descr), "?", - PyDescr_TYPE(descr)->tp_name, - ((PyTypeObject*)self)->tp_name); + PyObject *self = PyTuple_GET_ITEM(args, 0); + PyObject *bound = classmethod_get(descr, NULL, self); + if (bound == NULL) { return NULL; } - - result = _PyMethodDef_RawFastCallDict(descr->d_method, self, - &_PyTuple_ITEMS(args)[1], argc - 1, - kwds); - result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL); - return result; + PyObject *res = _PyObject_FastCallDict(bound, _PyTuple_ITEMS(args)+1, + argc-1, kwds); + Py_DECREF(bound); + return res; } Py_LOCAL_INLINE(PyObject *) |