Fix detail::obj_class_name() to work correctly for meta classes. (#4436)

* Fix `detail::obj_class_name()` to work correctly for meta classes.

* Adjust expected name for PyPy
This commit is contained in:
Ralf W. Grosse-Kunstleve 2023-01-02 03:46:17 -08:00 committed by GitHub
parent 60f02f5f66
commit f12e098f1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 21 additions and 2 deletions

View File

@ -463,7 +463,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
// Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class). // Equivalent to obj.__class__.__name__ (or obj.__name__ if obj is a class).
inline const char *obj_class_name(PyObject *obj) { inline const char *obj_class_name(PyObject *obj) {
if (Py_TYPE(obj) == &PyType_Type) { if (PyType_Check(obj)) {
return reinterpret_cast<PyTypeObject *>(obj)->tp_name; return reinterpret_cast<PyTypeObject *>(obj)->tp_name;
} }
return Py_TYPE(obj)->tp_name; return Py_TYPE(obj)->tp_name;

View File

@ -55,6 +55,8 @@ void bind_empty0(py::module_ &m) {
} // namespace test_class } // namespace test_class
TEST_SUBMODULE(class_, m) { TEST_SUBMODULE(class_, m) {
m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });
// test_instance // test_instance
struct NoConstructor { struct NoConstructor {
NoConstructor() = default; NoConstructor() = default;

View File

@ -1,10 +1,19 @@
import pytest import pytest
import env # noqa: F401 import env
from pybind11_tests import ConstructorStats, UserType from pybind11_tests import ConstructorStats, UserType
from pybind11_tests import class_ as m from pybind11_tests import class_ as m
def test_obj_class_name():
if env.PYPY:
expected_name = "UserType"
else:
expected_name = "pybind11_tests.UserType"
assert m.obj_class_name(UserType(1)) == expected_name
assert m.obj_class_name(UserType) == expected_name
def test_repr(): def test_repr():
assert "pybind11_type" in repr(type(UserType)) assert "pybind11_type" in repr(type(UserType))
assert "UserType" in repr(UserType) assert "UserType" in repr(UserType)

View File

@ -99,6 +99,8 @@ void m_defs(py::module_ &m) {
} // namespace handle_from_move_only_type_with_operator_PyObject } // namespace handle_from_move_only_type_with_operator_PyObject
TEST_SUBMODULE(pytypes, m) { TEST_SUBMODULE(pytypes, m) {
m.def("obj_class_name", [](py::handle obj) { return py::detail::obj_class_name(obj.ptr()); });
handle_from_move_only_type_with_operator_PyObject::m_defs(m); handle_from_move_only_type_with_operator_PyObject::m_defs(m);
// test_bool // test_bool

View File

@ -9,6 +9,12 @@ from pybind11_tests import detailed_error_messages_enabled
from pybind11_tests import pytypes as m from pybind11_tests import pytypes as m
def test_obj_class_name():
assert m.obj_class_name(None) == "NoneType"
assert m.obj_class_name(list) == "list"
assert m.obj_class_name([]) == "list"
def test_handle_from_move_only_type_with_operator_PyObject(): # noqa: N802 def test_handle_from_move_only_type_with_operator_PyObject(): # noqa: N802
assert m.handle_from_move_only_type_with_operator_PyObject_ncnst() assert m.handle_from_move_only_type_with_operator_PyObject_ncnst()
assert m.handle_from_move_only_type_with_operator_PyObject_const() assert m.handle_from_move_only_type_with_operator_PyObject_const()