gh-123446: Fix empty function names in `TypeError`s in `typeobject` (#123470)

This commit is contained in:
sobolevn 2024-08-30 10:36:51 +03:00 committed by GitHub
parent 32c7dbb2bc
commit f8a736b8e1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 63 additions and 11 deletions

View File

@ -4021,6 +4021,20 @@ class ClassPropertiesAndMethods(unittest.TestCase):
y = x ** 2 y = x ** 2
self.assertIn('unsupported operand type(s) for **', str(cm.exception)) self.assertIn('unsupported operand type(s) for **', str(cm.exception))
def test_pow_wrapper_error_messages(self):
self.assertRaisesRegex(TypeError,
'expected 1 or 2 arguments, got 0',
int().__pow__)
self.assertRaisesRegex(TypeError,
'expected 1 or 2 arguments, got 3',
int().__pow__, 1, 2, 3)
self.assertRaisesRegex(TypeError,
'expected 1 or 2 arguments, got 0',
int().__rpow__)
self.assertRaisesRegex(TypeError,
'expected 1 or 2 arguments, got 3',
int().__rpow__, 1, 2, 3)
def test_mutable_bases(self): def test_mutable_bases(self):
# Testing mutable bases... # Testing mutable bases...

View File

@ -0,0 +1,2 @@
Fix empty function name in :exc:`TypeError` when builtin magic methods are
used without the required args.

View File

@ -8678,6 +8678,27 @@ check_num_args(PyObject *ob, int n)
return 0; return 0;
} }
static Py_ssize_t
check_pow_args(PyObject *ob)
{
// Returns the argument count on success or `-1` on error.
int min = 1;
int max = 2;
if (!PyTuple_CheckExact(ob)) {
PyErr_SetString(PyExc_SystemError,
"PyArg_UnpackTuple() argument list is not a tuple");
return -1;
}
Py_ssize_t size = PyTuple_GET_SIZE(ob);
if (size >= min && size <= max) {
return size;
}
PyErr_Format(
PyExc_TypeError,
"expected %d or %d arguments, got %zd", min, max, PyTuple_GET_SIZE(ob));
return -1;
}
/* Generic wrappers for overloadable 'operators' such as __getitem__ */ /* Generic wrappers for overloadable 'operators' such as __getitem__ */
/* There's a wrapper *function* for each distinct function typedef used /* There's a wrapper *function* for each distinct function typedef used
@ -8759,8 +8780,15 @@ wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
/* Note: This wrapper only works for __pow__() */ /* Note: This wrapper only works for __pow__() */
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) Py_ssize_t size = check_pow_args(args);
if (size == -1) {
return NULL; return NULL;
}
other = PyTuple_GET_ITEM(args, 0);
if (size == 2) {
third = PyTuple_GET_ITEM(args, 1);
}
return (*func)(self, other, third); return (*func)(self, other, third);
} }
@ -8771,10 +8799,17 @@ wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
PyObject *other; PyObject *other;
PyObject *third = Py_None; PyObject *third = Py_None;
/* Note: This wrapper only works for __pow__() */ /* Note: This wrapper only works for __rpow__() */
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) Py_ssize_t size = check_pow_args(args);
if (size == -1) {
return NULL; return NULL;
}
other = PyTuple_GET_ITEM(args, 0);
if (size == 2) {
third = PyTuple_GET_ITEM(args, 1);
}
return (*func)(other, self, third); return (*func)(other, self, third);
} }
@ -8795,8 +8830,9 @@ wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped)
PyObject* o; PyObject* o;
Py_ssize_t i; Py_ssize_t i;
if (!PyArg_UnpackTuple(args, "", 1, 1, &o)) if (!check_num_args(args, 1))
return NULL; return NULL;
o = PyTuple_GET_ITEM(args, 0);
i = PyNumber_AsSsize_t(o, PyExc_OverflowError); i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
if (i == -1 && PyErr_Occurred()) if (i == -1 && PyErr_Occurred())
return NULL; return NULL;
@ -8852,7 +8888,7 @@ wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped)
int res; int res;
PyObject *arg, *value; PyObject *arg, *value;
if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value)) if (!PyArg_UnpackTuple(args, "__setitem__", 2, 2, &arg, &value))
return NULL; return NULL;
i = getindex(self, arg); i = getindex(self, arg);
if (i == -1 && PyErr_Occurred()) if (i == -1 && PyErr_Occurred())
@ -8908,7 +8944,7 @@ wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
int res; int res;
PyObject *key, *value; PyObject *key, *value;
if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value)) if (!PyArg_UnpackTuple(args, "__setitem__", 2, 2, &key, &value))
return NULL; return NULL;
res = (*func)(self, key, value); res = (*func)(self, key, value);
if (res == -1 && PyErr_Occurred()) if (res == -1 && PyErr_Occurred())
@ -9005,7 +9041,7 @@ wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
int res; int res;
PyObject *name, *value; PyObject *name, *value;
if (!PyArg_UnpackTuple(args, "", 2, 2, &name, &value)) if (!PyArg_UnpackTuple(args, "__setattr__", 2, 2, &name, &value))
return NULL; return NULL;
if (!hackcheck(self, func, "__setattr__")) if (!hackcheck(self, func, "__setattr__"))
return NULL; return NULL;
@ -9115,7 +9151,7 @@ wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
PyObject *obj; PyObject *obj;
PyObject *type = NULL; PyObject *type = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type)) if (!PyArg_UnpackTuple(args, "__get__", 1, 2, &obj, &type))
return NULL; return NULL;
if (obj == Py_None) if (obj == Py_None)
obj = NULL; obj = NULL;
@ -9136,7 +9172,7 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
PyObject *obj, *value; PyObject *obj, *value;
int ret; int ret;
if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value)) if (!PyArg_UnpackTuple(args, "__set__", 2, 2, &obj, &value))
return NULL; return NULL;
ret = (*func)(self, obj, value); ret = (*func)(self, obj, value);
if (ret < 0) if (ret < 0)
@ -9165,7 +9201,7 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
{ {
PyObject *arg = NULL; PyObject *arg = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) { if (!PyArg_UnpackTuple(args, "__buffer__", 1, 1, &arg)) {
return NULL; return NULL;
} }
Py_ssize_t flags = PyNumber_AsSsize_t(arg, PyExc_OverflowError); Py_ssize_t flags = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
@ -9186,7 +9222,7 @@ static PyObject *
wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped) wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped)
{ {
PyObject *arg = NULL; PyObject *arg = NULL;
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) { if (!PyArg_UnpackTuple(args, "__release_buffer__", 1, 1, &arg)) {
return NULL; return NULL;
} }
if (!PyMemoryView_Check(arg)) { if (!PyMemoryView_Check(arg)) {