__qualname__ and nested class naming fixes (#1171)
A few fixes related to how we set `__qualname__` and how we show the
type name in function signatures:
- `__qualname__` isn't supposed to have the module name at the
beginning, but we've been putting it there. This removes it, while
keeping the `Nested.Class` name chaining.
- print `__module__.__qualname__` rather than `type->tp_name`; the
latter doesn't work properly for nested classes, so we would get
`module.B` rather than `module.A.B` for a class `B` with parent `A`.
This also unifies the Python 3 and PyPy code. Fixes #1166.
- This now sets a `__qualname__` attribute on the type (as would happen
in Python 3.3+) for Python <3.3, including PyPy. While not particularly
important to have in earlier Python versions, it's useful for us to be
able to extracted the nested name, which is why `__qualname__` was
invented in the first place.
- Added tests for the above.
diff --git a/tests/test_class.py b/tests/test_class.py
index 412d679..d94b61b 100644
--- a/tests/test_class.py
+++ b/tests/test_class.py
@@ -44,6 +44,31 @@
"""
+def test_qualname(doc):
+ """Tests that a properly qualified name is set in __qualname__ (even in pre-3.3, where we
+ backport the attribute) and that generated docstrings properly use it and the module name"""
+ assert m.NestBase.__qualname__ == "NestBase"
+ assert m.NestBase.Nested.__qualname__ == "NestBase.Nested"
+
+ assert doc(m.NestBase.__init__) == """
+ __init__(self: m.class_.NestBase) -> None
+ """
+ assert doc(m.NestBase.g) == """
+ g(self: m.class_.NestBase, arg0: m.class_.NestBase.Nested) -> None
+ """
+ assert doc(m.NestBase.Nested.__init__) == """
+ __init__(self: m.class_.NestBase.Nested) -> None
+ """
+ assert doc(m.NestBase.Nested.fn) == """
+ fn(self: m.class_.NestBase.Nested, arg0: int, arg1: m.class_.NestBase, arg2: m.class_.NestBase.Nested) -> None
+ """ # noqa: E501 line too long
+ assert doc(m.NestBase.Nested.fa) == """
+ fa(self: m.class_.NestBase.Nested, a: int, b: m.class_.NestBase, c: m.class_.NestBase.Nested) -> None
+ """ # noqa: E501 line too long
+ assert m.NestBase.__module__ == "pybind11_tests.class_"
+ assert m.NestBase.Nested.__module__ == "pybind11_tests.class_"
+
+
def test_inheritance(msg):
roger = m.Rabbit('Rabbit')
assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
@@ -229,7 +254,9 @@
# ensure that there is no runaway reentrant implicit conversion (#1035)
with pytest.raises(TypeError) as excinfo:
m.BogusImplicitConversion(0)
- assert msg(excinfo.value) == '''__init__(): incompatible constructor arguments. The following argument types are supported:
- 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
+ assert msg(excinfo.value) == '''
+ __init__(): incompatible constructor arguments. The following argument types are supported:
+ 1. m.class_.BogusImplicitConversion(arg0: m.class_.BogusImplicitConversion)
-Invoked with: 0'''
+ Invoked with: 0
+ '''