Skip to content

Commit 2b32747

Browse files
committed
bpo-37151: simplify classmethoddescr_call
1 parent 8565f6b commit 2b32747

File tree

2 files changed

+18
-30
lines changed

2 files changed

+18
-30
lines changed

Lib/test/test_descr.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,8 +1613,8 @@ class SubSpam(spam.spamlist): pass
16131613
spam_cm(spam.spamlist())
16141614
self.assertEqual(
16151615
str(cm.exception),
1616-
"descriptor 'classmeth' requires a type "
1617-
"but received a 'xxsubtype.spamlist' instance")
1616+
"descriptor 'classmeth' for type 'xxsubtype.spamlist' "
1617+
"needs a type, not a 'xxsubtype.spamlist' as arg 2")
16181618

16191619
with self.assertRaises(TypeError) as cm:
16201620
spam_cm(list)

Objects/descrobject.c

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,19 @@ _PyMethodDescr_Vectorcall(PyObject *descrobj,
300300
return result;
301301
}
302302

303+
/* Instances of classmethod_descriptor are unlikely to be called directly.
304+
For one, the analogous class "classmethod" (for Python classes) is not
305+
callable. Second, users are not likely to access a classmethod_descriptor
306+
directly, since it means pulling it from the class __dict__.
307+
308+
This is just an excuse to say that this doesn't need to be optimized:
309+
we implement this simply by calling __get__ and then calling the result.
310+
*/
303311
static PyObject *
304312
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
305313
PyObject *kwds)
306314
{
307-
Py_ssize_t argc;
308-
PyObject *self, *result;
309-
310-
/* Make sure that the first argument is acceptable as 'self' */
311-
assert(PyTuple_Check(args));
312-
argc = PyTuple_GET_SIZE(args);
315+
Py_ssize_t argc = PyTuple_GET_SIZE(args);
313316
if (argc < 1) {
314317
PyErr_Format(PyExc_TypeError,
315318
"descriptor '%V' of '%.100s' "
@@ -318,30 +321,15 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
318321
PyDescr_TYPE(descr)->tp_name);
319322
return NULL;
320323
}
321-
self = PyTuple_GET_ITEM(args, 0);
322-
if (!PyType_Check(self)) {
323-
PyErr_Format(PyExc_TypeError,
324-
"descriptor '%V' requires a type "
325-
"but received a '%.100s' instance",
326-
descr_name((PyDescrObject *)descr), "?",
327-
self->ob_type->tp_name);
328-
return NULL;
329-
}
330-
if (!PyType_IsSubtype((PyTypeObject *)self, PyDescr_TYPE(descr))) {
331-
PyErr_Format(PyExc_TypeError,
332-
"descriptor '%V' requires a subtype of '%.100s' "
333-
"but received '%.100s'",
334-
descr_name((PyDescrObject *)descr), "?",
335-
PyDescr_TYPE(descr)->tp_name,
336-
((PyTypeObject*)self)->tp_name);
324+
PyObject *self = PyTuple_GET_ITEM(args, 0);
325+
PyObject *bound = classmethod_get(descr, NULL, self);
326+
if (bound == NULL) {
337327
return NULL;
338328
}
339-
340-
result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
341-
&_PyTuple_ITEMS(args)[1], argc - 1,
342-
kwds);
343-
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
344-
return result;
329+
PyObject *res = _PyObject_FastCallDict(bound, _PyTuple_ITEMS(args)+1,
330+
argc-1, kwds);
331+
Py_DECREF(bound);
332+
return res;
345333
}
346334

347335
Py_LOCAL_INLINE(PyObject *)

0 commit comments

Comments
 (0)