mirror of https://github.com/python/cpython
bpo-36026: make descr error message consistent (GH-11930)
set.add(0) and set.add.__get__(0) now raise TypeError with same error message.
This commit is contained in:
parent
42a139ed88
commit
62f9588663
|
@ -1614,10 +1614,14 @@ order (MRO) for bases """
|
|||
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
spam_cm(list)
|
||||
self.assertEqual(
|
||||
str(cm.exception),
|
||||
expected_errmsg = (
|
||||
"descriptor 'classmeth' requires a subtype of 'xxsubtype.spamlist' "
|
||||
"but received 'list'")
|
||||
self.assertEqual(str(cm.exception), expected_errmsg)
|
||||
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
spam_cm.__get__(None, list)
|
||||
self.assertEqual(str(cm.exception), expected_errmsg)
|
||||
|
||||
def test_staticmethods(self):
|
||||
# Testing static methods...
|
||||
|
@ -1952,6 +1956,29 @@ order (MRO) for bases """
|
|||
self.assertEqual(E().foo.__func__, C.foo) # i.e., unbound
|
||||
self.assertTrue(repr(C.foo.__get__(C(1))).startswith("<bound method "))
|
||||
|
||||
@support.impl_detail("testing error message from implementation")
|
||||
def test_methods_in_c(self):
|
||||
# This test checks error messages in builtin method descriptor.
|
||||
# It is allowed that other Python implementations use
|
||||
# different error messages.
|
||||
set_add = set.add
|
||||
|
||||
expected_errmsg = "descriptor 'add' of 'set' object needs an argument"
|
||||
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
set_add()
|
||||
self.assertEqual(cm.exception.args[0], expected_errmsg)
|
||||
|
||||
expected_errmsg = "descriptor 'add' for 'set' objects doesn't apply to a 'int' object"
|
||||
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
set_add(0)
|
||||
self.assertEqual(cm.exception.args[0], expected_errmsg)
|
||||
|
||||
with self.assertRaises(TypeError) as cm:
|
||||
set_add.__get__(0)
|
||||
self.assertEqual(cm.exception.args[0], expected_errmsg)
|
||||
|
||||
def test_special_method_lookup(self):
|
||||
# The lookup of special methods bypasses __getattr__ and
|
||||
# __getattribute__, but they still can be descriptors.
|
||||
|
|
|
@ -78,8 +78,8 @@ descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres)
|
|||
}
|
||||
if (!PyObject_TypeCheck(obj, descr->d_type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' for '%s' objects "
|
||||
"doesn't apply to '%s' object",
|
||||
"descriptor '%V' for '%.100s' objects "
|
||||
"doesn't apply to a '%.100s' object",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
descr->d_type->tp_name,
|
||||
obj->ob_type->tp_name);
|
||||
|
@ -99,7 +99,7 @@ classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
|
|||
else {
|
||||
/* Wot - no type?! */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' for type '%s' "
|
||||
"descriptor '%V' for type '%.100s' "
|
||||
"needs either an object or a type",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
PyDescr_TYPE(descr)->tp_name);
|
||||
|
@ -108,8 +108,8 @@ classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
|
|||
}
|
||||
if (!PyType_Check(type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' for type '%s' "
|
||||
"needs a type, not a '%s' as arg 2",
|
||||
"descriptor '%V' for type '%.100s' "
|
||||
"needs a type, not a '%.100s' as arg 2",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
PyDescr_TYPE(descr)->tp_name,
|
||||
type->ob_type->tp_name);
|
||||
|
@ -117,8 +117,8 @@ classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type)
|
|||
}
|
||||
if (!PyType_IsSubtype((PyTypeObject *)type, PyDescr_TYPE(descr))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' for type '%s' "
|
||||
"doesn't apply to type '%s'",
|
||||
"descriptor '%V' requires a subtype of '%.100s' "
|
||||
"but received '%.100s'",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
PyDescr_TYPE(descr)->tp_name,
|
||||
((PyTypeObject *)type)->tp_name);
|
||||
|
@ -181,7 +181,7 @@ descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value,
|
|||
if (!PyObject_TypeCheck(obj, descr->d_type)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' for '%.100s' objects "
|
||||
"doesn't apply to '%.100s' object",
|
||||
"doesn't apply to a '%.100s' object",
|
||||
descr_name(descr), "?",
|
||||
descr->d_type->tp_name,
|
||||
obj->ob_type->tp_name);
|
||||
|
@ -239,9 +239,8 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
|
|||
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
|
||||
(PyObject *)PyDescr_TYPE(descr))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' "
|
||||
"requires a '%.100s' object "
|
||||
"but received a '%.100s'",
|
||||
"descriptor '%V' for '%.100s' objects "
|
||||
"doesn't apply to a '%.100s' object",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
PyDescr_TYPE(descr)->tp_name,
|
||||
self->ob_type->tp_name);
|
||||
|
@ -278,9 +277,8 @@ _PyMethodDescr_FastCallKeywords(PyObject *descrobj,
|
|||
if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self),
|
||||
(PyObject *)PyDescr_TYPE(descr))) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"descriptor '%V' "
|
||||
"requires a '%.100s' object "
|
||||
"but received a '%.100s'",
|
||||
"descriptor '%V' for '%.100s' objects "
|
||||
"doesn't apply to a '%.100s' object",
|
||||
descr_name((PyDescrObject *)descr), "?",
|
||||
PyDescr_TYPE(descr)->tp_name,
|
||||
self->ob_type->tp_name);
|
||||
|
|
Loading…
Reference in New Issue