mirror of https://github.com/python/cpython
gh-113212: Improve error message & document zero-arg super inside nested functions and generator expressions (GH-113307)
This commit is contained in:
parent
237e2cff00
commit
4a3d2419bb
|
@ -1800,6 +1800,13 @@ are always available. They are listed here in alphabetical order.
|
||||||
the second argument is a type, ``issubclass(type2, type)`` must be true (this
|
the second argument is a type, ``issubclass(type2, type)`` must be true (this
|
||||||
is useful for classmethods).
|
is useful for classmethods).
|
||||||
|
|
||||||
|
When called directly within an ordinary method of a class, both arguments may
|
||||||
|
be omitted ("zero-argument :func:`!super`"). In this case, *type* will be the
|
||||||
|
enclosing class, and *obj* will be the first argument of the immediately
|
||||||
|
enclosing function (typically ``self``). (This means that zero-argument
|
||||||
|
:func:`!super` will not work as expected within nested functions, including
|
||||||
|
generator expressions, which implicitly create nested functions.)
|
||||||
|
|
||||||
There are two typical use cases for *super*. In a class hierarchy with
|
There are two typical use cases for *super*. In a class hierarchy with
|
||||||
single inheritance, *super* can be used to refer to parent classes without
|
single inheritance, *super* can be used to refer to parent classes without
|
||||||
naming them explicitly, thus making the code more maintainable. This use
|
naming them explicitly, thus making the code more maintainable. This use
|
||||||
|
|
|
@ -396,6 +396,33 @@ class TestSuper(unittest.TestCase):
|
||||||
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
|
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
|
||||||
C().method()
|
C().method()
|
||||||
|
|
||||||
|
def test_supercheck_fail(self):
|
||||||
|
class C:
|
||||||
|
def method(self, type_, obj):
|
||||||
|
return super(type_, obj).method()
|
||||||
|
|
||||||
|
c = C()
|
||||||
|
err_msg = (
|
||||||
|
r"super\(type, obj\): obj \({} {}\) is not "
|
||||||
|
r"an instance or subtype of type \({}\)."
|
||||||
|
)
|
||||||
|
|
||||||
|
cases = (
|
||||||
|
(int, c, int.__name__, C.__name__, "instance of"),
|
||||||
|
# obj is instance of type
|
||||||
|
(C, list(), C.__name__, list.__name__, "instance of"),
|
||||||
|
# obj is type itself
|
||||||
|
(C, list, C.__name__, list.__name__, "type"),
|
||||||
|
)
|
||||||
|
|
||||||
|
for case in cases:
|
||||||
|
with self.subTest(case=case):
|
||||||
|
type_, obj, type_str, obj_str, instance_or_type = case
|
||||||
|
regex = err_msg.format(instance_or_type, obj_str, type_str)
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError, regex):
|
||||||
|
c.method(type_, obj)
|
||||||
|
|
||||||
def test_super___class__(self):
|
def test_super___class__(self):
|
||||||
class C:
|
class C:
|
||||||
def method(self):
|
def method(self):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve :py:class:`super` error messages.
|
|
@ -10404,9 +10404,22 @@ supercheck(PyTypeObject *type, PyObject *obj)
|
||||||
Py_XDECREF(class_attr);
|
Py_XDECREF(class_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
const char *type_or_instance, *obj_str;
|
||||||
"super(type, obj): "
|
|
||||||
"obj must be an instance or subtype of type");
|
if (PyType_Check(obj)) {
|
||||||
|
type_or_instance = "type";
|
||||||
|
obj_str = ((PyTypeObject*)obj)->tp_name;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type_or_instance = "instance of";
|
||||||
|
obj_str = Py_TYPE(obj)->tp_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"super(type, obj): obj (%s %.200s) is not "
|
||||||
|
"an instance or subtype of type (%.200s).",
|
||||||
|
type_or_instance, obj_str, type->tp_name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue