gh-113212: Improve error message & document zero-arg super inside nested functions and generator expressions (GH-113307)

This commit is contained in:
Yan Yanchii 2023-12-22 16:12:08 +01:00 committed by GitHub
parent 237e2cff00
commit 4a3d2419bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 3 deletions

View File

@ -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
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
single inheritance, *super* can be used to refer to parent classes without
naming them explicitly, thus making the code more maintainable. This use

View File

@ -396,6 +396,33 @@ class TestSuper(unittest.TestCase):
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
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):
class C:
def method(self):

View File

@ -0,0 +1 @@
Improve :py:class:`super` error messages.

View File

@ -10404,9 +10404,22 @@ supercheck(PyTypeObject *type, PyObject *obj)
Py_XDECREF(class_attr);
}
PyErr_SetString(PyExc_TypeError,
"super(type, obj): "
"obj must be an instance or subtype of type");
const char *type_or_instance, *obj_str;
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;
}