Skip to content

[BUG]: __getattr__ and multiple inheritance with smart holders #3801

@petersteneteg

Description

@petersteneteg

Required prerequisites

Problem description

Hi, I've found an other issue related to #3788
this is in regard to the smart holder branch

The example code below fails with infinite recursive getattr calls.

removing either Base2, Derived2 or the binding of __getattr__ removes the problem.

removing the following lines

if (convert && cpptype && try_as_void_ptr_capsule(src)) {
return true;
}

also removes the issue.

Reproducible example code

// Binding code

#include <pybind11/pybind11.h>

namespace py = pybind11;

struct Base1 {int a1{};};
struct Base2 {int a2{};};

struct Base12 : Base1, Base2 {
    virtual ~Base12() = default;
    int foo() const { return 0; }
};

struct Derived1 : Base12 {
    int bar() const { return 1; }
};

struct Derived2 : Base12 {
    int bar() const { return 2; }
};


PYBIND11_MODULE(foo, m) {
    py::class_<Base1>(m, "Base1");
    py::class_<Base2>(m, "Base2");

    py::class_<Base12, Base1, Base2>(m, "Base12")
        .def(py::init<>())
        .def("foo", &Base12::foo)
       .def("__getattr__", [](Base12&, std::string key) {
            return "Base GetAttr: " + key;
        });

    py::class_<Derived1, Base12>(m, "Derived1")
        .def(py::init<>())
        .def("bar", &Derived1::bar);

    py::class_<Derived2, Base12>(m, "Derived2")
        .def(py::init<>())
        .def("bar", &Derived2::bar);
}


// Test code
import foo

d1 = foo.Derived1()
print(f"d1.foo(): {d1.foo()}")
print(f"d1.bar(): {d1.bar()}")
print(f"d1.prop1: {d1.prop1}")

d2 = foo.Derived2()
print(f"d2.foo(): {d2.foo()}")
print(f"d2.bar(): {d2.bar()}")
print(f"d2.prop1: {d2.prop2}")

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageNew bug, unverified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions