From f27bd9a3bb4db8c04f70fb72dea31cb6ae5adf66 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Fri, 7 Apr 2023 18:24:25 -0700 Subject: [PATCH] Alternative approach to #3807 that supports an important PyCLIF use case: `Base` not specified in `classh` statement, but passing Derived as Base works anyway. --- .../detail/smart_holder_type_casters.h | 9 ++--- tests/test_class_sh_void_ptr_capsule.cpp | 40 ++++++++++++++----- tests/test_class_sh_void_ptr_capsule.py | 4 ++ 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/include/pybind11/detail/smart_holder_type_casters.h b/include/pybind11/detail/smart_holder_type_casters.h index 2b96512b1..428c3c3e1 100644 --- a/include/pybind11/detail/smart_holder_type_casters.h +++ b/include/pybind11/detail/smart_holder_type_casters.h @@ -60,7 +60,7 @@ inline void *try_as_void_ptr_capsule_get_pointer(handle src, const char *typeid_ std::string as_void_ptr_function_name("as_"); as_void_ptr_function_name += type_name; - if (hasattr(src, as_void_ptr_function_name.c_str())) { + if (hasattr(src, as_void_ptr_function_name.c_str()) && !hasattr(src, "__getattr__")) { auto as_void_ptr_function = function(src.attr(as_void_ptr_function_name.c_str())); auto void_ptr_capsule = as_void_ptr_function(); if (isinstance(void_ptr_capsule)) { @@ -304,11 +304,8 @@ public: loaded_v_h = value_and_holder(); return true; } - if (convert && cpptype) { - const auto &bases = all_type_info(srctype); - if (bases.empty() && try_as_void_ptr_capsule(src)) { - return true; - } + if (convert && cpptype && try_as_void_ptr_capsule(src)) { + return true; } return false; } diff --git a/tests/test_class_sh_void_ptr_capsule.cpp b/tests/test_class_sh_void_ptr_capsule.cpp index 45b8d2f64..ee8993207 100644 --- a/tests/test_class_sh_void_ptr_capsule.cpp +++ b/tests/test_class_sh_void_ptr_capsule.cpp @@ -58,20 +58,33 @@ struct Derived2 : Base12 { int bar() const { return 2; } }; +struct UnspecBase { + virtual ~UnspecBase() = default; + virtual int Get() const { return 100; } +}; + +inline int PassUnspecBase(const UnspecBase &sb) { return sb.Get() + 30; } + +struct UnspecDerived : UnspecBase { + int Get() const override { return 200; } +}; + } // namespace class_sh_void_ptr_capsule } // namespace pybind11_tests -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Valid) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::TypeWithGetattr) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Base1) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Base2) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Base12) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Derived1) -PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Derived2) +using namespace pybind11_tests::class_sh_void_ptr_capsule; + +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Valid) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(TypeWithGetattr) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Base1) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Base2) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Base12) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Derived1) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(Derived2) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(UnspecBase) +PYBIND11_SMART_HOLDER_TYPE_CASTERS(UnspecDerived) TEST_SUBMODULE(class_sh_void_ptr_capsule, m) { - using namespace pybind11_tests::class_sh_void_ptr_capsule; - py::classh(m, "Valid"); m.def("get_from_valid_capsule", &get_from_valid_capsule); @@ -102,4 +115,13 @@ TEST_SUBMODULE(class_sh_void_ptr_capsule, m) { py::classh(m, "Derived1").def(py::init<>()).def("bar", &Derived1::bar); py::classh(m, "Derived2").def(py::init<>()).def("bar", &Derived2::bar); + + py::classh(m, "UnspecBase"); + m.def("PassUnspecBase", PassUnspecBase); + py::classh(m, "UnspecDerived") // UnspecBase NOT specified as base here. + .def(py::init<>()) + .def("as_pybind11_tests_class_sh_void_ptr_capsule_UnspecBase", [](UnspecDerived *self) { + return py::reinterpret_steal( + PyCapsule_New(static_cast(self), nullptr, nullptr)); + }); } diff --git a/tests/test_class_sh_void_ptr_capsule.py b/tests/test_class_sh_void_ptr_capsule.py index 1ca254d95..7c9824d86 100644 --- a/tests/test_class_sh_void_ptr_capsule.py +++ b/tests/test_class_sh_void_ptr_capsule.py @@ -94,3 +94,7 @@ def test_multiple_inheritance_getattr(): assert d2.foo() == 0 assert d2.bar() == 2 assert d2.prop2 == "Base GetAttr: prop2" + + +def test_pass_unspecified_base(): + assert m.PassUnspecBase(m.UnspecDerived()) == 230