pybind / pybind/pybind11

module_local: Sharp edges when using inheritance?

Open
#1,689 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
18k
Forks
2.3k
Avg merge
5d 17h
Merged PRs (30d)
10

Description

It seems like inheritance gets muddled by py::module_local(); I have something like this:

struct Base {
  virtual ~Base() {}
};

struct Child : public Base {};

void def_module_base(py::module m) {
  py::class_<Base>(m, "Base");

  m.def("pass_thru", [](const Base* obj) { return obj; });
}

void def_module_child(py::module m) {
  py::class_<Child, Base>(m, "Child", py::module_local())
    .def(py::init());
}

But the inheritance (namely the typeid matching?) seems to get lost when passing through C++ API (where automatic downcasting should happen):

from module_base import Base, pass_thru
from module_child import Child

c = Child()
print(c)
# <Child at 0x...>
print(pass_thru(c))
# <Base at 0x...> - different address?

Not exactly sure why yet. Will see if I can make a more concrete min-repro, and ensure it's not due to a local fork... which TBH, could be possible.

(My actual case is a bit more complex: it's single inheritance, but two degrees, with templated types. Hoping it doesn't have to do with symbol visibility.)

I don't get this problem if I remove py::module_local(); however, I still get the problem if I define the inheritance use the class handle, e.g.

py::object base_cls = py::module::import("module_base").attr("Base");
py::class_<Child>(m, "Child", base_cls, py::module_local());

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start from the shown def_module_base and def_module_child entry points and reproduce the Python calls to Child and pass_thru. Compare module_local inheritance with the version that omits module_local and the class-handle variant. Done means the inheritance and automatic downcasting behavior are understood and the observed Base result is resolved or clearly characterized.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, python
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.