77namespace pybind11_tests {
88namespace class_sh_void_ptr_capsule {
99
10- // Without the helper we will run into a type_caster::load recursion.
11- // This is because whenever the type_caster::load is called, it checks
12- // whether the object defines an `as_` method that returns the void pointer
13- // capsule. If yes, it calls the method. But in the following testcases, those
14- // `as_` methods are defined with pybind11, which implicitly takes the object
15- // itself as the first parameter. Therefore calling those methods causes loading
16- // the object again, which causes infinite recursion.
17- // This test is unusual in the sense that the void pointer capsules are meant to
18- // be provided by objects wrapped with systems other than pybind11
19- // (i.e. having to avoid the recursion is an artificial problem, not the norm).
20- // Conveniently, the helper also serves to keep track of `capsule_generated`.
10+ // Conveniently, the helper serves to keep track of `capsule_generated`.
2111struct HelperBase {
2212 HelperBase () = default ;
2313 HelperBase (const HelperBase &) = delete ;
@@ -65,6 +55,12 @@ struct AsAnotherObject : public HelperBase {
6555 }
6656};
6757
58+ // https://github.com/pybind/pybind11/issues/3788
59+ struct TypeWithGetattr {
60+ TypeWithGetattr () = default ;
61+ int get_42 () const { return 42 ; }
62+ };
63+
6864int get_from_valid_capsule (const Valid *c) { return c->get (); }
6965
7066int get_from_shared_ptr_valid_capsule (const std::shared_ptr<Valid> &c) { return c->get (); }
@@ -83,6 +79,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::Va
8379PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::NoConversion)
8480PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::NoCapsuleReturned)
8581PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::AsAnotherObject)
82+ PYBIND11_SMART_HOLDER_TYPE_CASTERS(pybind11_tests::class_sh_void_ptr_capsule::TypeWithGetattr)
8683
8784TEST_SUBMODULE(class_sh_void_ptr_capsule, m) {
8885 using namespace pybind11_tests ::class_sh_void_ptr_capsule;
@@ -94,10 +91,8 @@ TEST_SUBMODULE(class_sh_void_ptr_capsule, m) {
9491
9592 py::classh<Valid, HelperBase>(m, " Valid" )
9693 .def (py::init<>())
97- .def (" as_pybind11_tests_class_sh_void_ptr_capsule_Valid" , [](HelperBase *self) {
98- auto *obj = dynamic_cast <Valid *>(self);
99- assert (obj != nullptr );
100- PyObject *capsule = obj->as_pybind11_tests_class_sh_void_ptr_capsule_Valid ();
94+ .def (" as_pybind11_tests_class_sh_void_ptr_capsule_Valid" , [](Valid &self) {
95+ PyObject *capsule = self.as_pybind11_tests_class_sh_void_ptr_capsule_Valid ();
10196 return pybind11::reinterpret_steal<py::capsule>(capsule);
10297 });
10398
@@ -106,20 +101,16 @@ TEST_SUBMODULE(class_sh_void_ptr_capsule, m) {
106101 py::classh<NoCapsuleReturned, HelperBase>(m, " NoCapsuleReturned" )
107102 .def (py::init<>())
108103 .def (" as_pybind11_tests_class_sh_void_ptr_capsule_NoCapsuleReturned" ,
109- [](HelperBase *self) {
110- auto *obj = dynamic_cast <NoCapsuleReturned *>(self);
111- assert (obj != nullptr );
104+ [](NoCapsuleReturned &self) {
112105 PyObject *capsule
113- = obj-> as_pybind11_tests_class_sh_void_ptr_capsule_NoCapsuleReturned ();
106+ = self. as_pybind11_tests_class_sh_void_ptr_capsule_NoCapsuleReturned ();
114107 return pybind11::reinterpret_steal<py::capsule>(capsule);
115108 });
116109
117110 py::classh<AsAnotherObject, HelperBase>(m, " AsAnotherObject" )
118111 .def (py::init<>())
119- .def (" as_pybind11_tests_class_sh_void_ptr_capsule_Valid" , [](HelperBase *self) {
120- auto *obj = dynamic_cast <AsAnotherObject *>(self);
121- assert (obj != nullptr );
122- PyObject *capsule = obj->as_pybind11_tests_class_sh_void_ptr_capsule_Valid ();
112+ .def (" as_pybind11_tests_class_sh_void_ptr_capsule_Valid" , [](AsAnotherObject &self) {
113+ PyObject *capsule = self.as_pybind11_tests_class_sh_void_ptr_capsule_Valid ();
123114 return pybind11::reinterpret_steal<py::capsule>(capsule);
124115 });
125116
@@ -128,4 +119,10 @@ TEST_SUBMODULE(class_sh_void_ptr_capsule, m) {
128119 m.def (" get_from_unique_ptr_valid_capsule" , &get_from_unique_ptr_valid_capsule);
129120 m.def (" get_from_no_conversion_capsule" , &get_from_no_conversion_capsule);
130121 m.def (" get_from_no_capsule_returned" , &get_from_no_capsule_returned);
122+
123+ py::classh<TypeWithGetattr>(m, " TypeWithGetattr" )
124+ .def (py::init<>())
125+ .def (" get_42" , &TypeWithGetattr::get_42)
126+ .def (" __getattr__" ,
127+ [](TypeWithGetattr &, const std::string &key) { return " GetAttr: " + key; });
131128}
0 commit comments