mirror of
https://github.com/python/cpython.git
synced 2025-11-02 03:01:58 +00:00
bpo-37645: add new function _PyObject_FunctionStr() (GH-14890)
Additional note: the `method_check_args` function in `Objects/descrobject.c` is written in such a way that it applies to all kinds of descriptors. In particular, a future re-implementation of `wrapper_descriptor` could use that code. CC @vstinner @encukou https://bugs.python.org/issue37645 Automerge-Triggered-By: @encukou
This commit is contained in:
parent
b3966639d2
commit
bf17d41826
11 changed files with 171 additions and 94 deletions
|
|
@ -231,45 +231,38 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value)
|
|||
*
|
||||
* First, common helpers
|
||||
*/
|
||||
static const char *
|
||||
get_name(PyObject *func) {
|
||||
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
|
||||
return ((PyMethodDescrObject *)func)->d_method->ml_name;
|
||||
}
|
||||
|
||||
typedef void (*funcptr)(void);
|
||||
|
||||
static inline int
|
||||
method_check_args(PyObject *func, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||
{
|
||||
assert(!PyErr_Occurred());
|
||||
assert(PyObject_TypeCheck(func, &PyMethodDescr_Type));
|
||||
if (nargs < 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' of '%.100s' "
|
||||
"object needs an argument",
|
||||
get_name(func), PyDescr_TYPE(func)->tp_name);
|
||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||
if (funcstr != NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"unbound method %U needs an argument", funcstr);
|
||||
Py_DECREF(funcstr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
PyObject *self = args[0];
|
||||
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
|
||||
(PyObject *)PyDescr_TYPE(func)))
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%.200s' for '%.100s' objects "
|
||||
"doesn't apply to a '%.100s' object",
|
||||
get_name(func), PyDescr_TYPE(func)->tp_name,
|
||||
Py_TYPE(self)->tp_name);
|
||||
PyObject *dummy;
|
||||
if (descr_check((PyDescrObject *)func, self, &dummy)) {
|
||||
return -1;
|
||||
}
|
||||
if (kwnames && PyTuple_GET_SIZE(kwnames)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no keyword arguments", get_name(func));
|
||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||
if (funcstr != NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%U takes no keyword arguments", funcstr);
|
||||
Py_DECREF(funcstr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef void (*funcptr)(void);
|
||||
|
||||
static inline funcptr
|
||||
method_enter_call(PyThreadState *tstate, PyObject *func)
|
||||
{
|
||||
|
|
@ -387,8 +380,12 @@ method_vectorcall_NOARGS(
|
|||
return NULL;
|
||||
}
|
||||
if (nargs != 1) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes no arguments (%zd given)", get_name(func), nargs-1);
|
||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||
if (funcstr != NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%U takes no arguments (%zd given)", funcstr, nargs-1);
|
||||
Py_DECREF(funcstr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
|
||||
|
|
@ -410,9 +407,13 @@ method_vectorcall_O(
|
|||
return NULL;
|
||||
}
|
||||
if (nargs != 2) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s() takes exactly one argument (%zd given)",
|
||||
get_name(func), nargs-1);
|
||||
PyObject *funcstr = _PyObject_FunctionStr(func);
|
||||
if (funcstr != NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%U takes exactly one argument (%zd given)",
|
||||
funcstr, nargs-1);
|
||||
Py_DECREF(funcstr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
PyCFunction meth = (PyCFunction)method_enter_call(tstate, func);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue