__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/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 90b8ebc..30c6917 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -246,19 +246,16 @@
if (!t)
pybind11_fail("Internal error while parsing type signature (1)");
if (auto tinfo = detail::get_type_info(*t)) {
-#if defined(PYPY_VERSION)
- signature += handle((PyObject *) tinfo->type)
- .attr("__module__")
- .cast<std::string>() + ".";
-#endif
- signature += tinfo->type->tp_name;
+ handle th((PyObject *) tinfo->type);
+ signature +=
+ th.attr("__module__").cast<std::string>() + "." +
+ th.attr("__qualname__").cast<std::string>(); // Python 3.3+, but we backport it to earlier versions
} else if (rec->is_new_style_constructor && arg_index == 0) {
// A new-style `__init__` takes `self` as `value_and_holder`.
// Rewrite it to the proper class type.
-#if defined(PYPY_VERSION)
- signature += rec->scope.attr("__module__").cast<std::string>() + ".";
-#endif
- signature += ((PyTypeObject *) rec->scope.ptr())->tp_name;
+ signature +=
+ rec->scope.attr("__module__").cast<std::string>() + "." +
+ rec->scope.attr("__qualname__").cast<std::string>();
} else {
std::string tname(t->name());
detail::clean_type_id(tname);