Skip to content

Commit

Permalink
pythongh-113212: Improve error message & document zero-arg super insi…
Browse files Browse the repository at this point in the history
…de nested functions and generator expressions (pythonGH-113307)
  • Loading branch information
WolframAlph authored and aisk committed Feb 11, 2024
1 parent a93ff6e commit d9c6bb1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 3 deletions.
7 changes: 7 additions & 0 deletions Doc/library/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions Lib/test/test_super.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,33 @@ def method(self):
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):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Improve :py:class:`super` error messages.
19 changes: 16 additions & 3 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit d9c6bb1

Please sign in to comment.