Kaydet (Commit) 3f345c39 authored tarafından Jeroen Demeyer's avatar Jeroen Demeyer Kaydeden (comit) Petr Viktorin

bpo-37151: simplify classmethoddescr_call (GH-13340)

üst 307d4cb9
...@@ -1613,8 +1613,8 @@ order (MRO) for bases """ ...@@ -1613,8 +1613,8 @@ order (MRO) for bases """
spam_cm(spam.spamlist()) spam_cm(spam.spamlist())
self.assertEqual( self.assertEqual(
str(cm.exception), str(cm.exception),
"descriptor 'classmeth' requires a type " "descriptor 'classmeth' for type 'xxsubtype.spamlist' "
"but received a 'xxsubtype.spamlist' instance") "needs a type, not a 'xxsubtype.spamlist' as arg 2")
with self.assertRaises(TypeError) as cm: with self.assertRaises(TypeError) as cm:
spam_cm(list) spam_cm(list)
......
...@@ -300,16 +300,19 @@ _PyMethodDescr_Vectorcall(PyObject *descrobj, ...@@ -300,16 +300,19 @@ _PyMethodDescr_Vectorcall(PyObject *descrobj,
return result; 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 * static PyObject *
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
PyObject *kwds) PyObject *kwds)
{ {
Py_ssize_t argc; Py_ssize_t argc = PyTuple_GET_SIZE(args);
PyObject *self, *result;
/* Make sure that the first argument is acceptable as 'self' */
assert(PyTuple_Check(args));
argc = PyTuple_GET_SIZE(args);
if (argc < 1) { if (argc < 1) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"descriptor '%V' of '%.100s' " "descriptor '%V' of '%.100s' "
...@@ -318,30 +321,15 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, ...@@ -318,30 +321,15 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
PyDescr_TYPE(descr)->tp_name); PyDescr_TYPE(descr)->tp_name);
return NULL; return NULL;
} }
self = PyTuple_GET_ITEM(args, 0); PyObject *self = PyTuple_GET_ITEM(args, 0);
if (!PyType_Check(self)) { PyObject *bound = classmethod_get(descr, NULL, self);
PyErr_Format(PyExc_TypeError, if (bound == NULL) {
"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);
return NULL; return NULL;
} }
PyObject *res = _PyObject_FastCallDict(bound, _PyTuple_ITEMS(args)+1,
result = _PyMethodDef_RawFastCallDict(descr->d_method, self, argc-1, kwds);
&_PyTuple_ITEMS(args)[1], argc - 1, Py_DECREF(bound);
kwds); return res;
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
return result;
} }
Py_LOCAL_INLINE(PyObject *) Py_LOCAL_INLINE(PyObject *)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment