Thore Goll
Thore Goll

Reputation: 11

How to inherit from `LeafSystem<T>` in other pybind11 module

first of all, thanks for this great project!

I have the following situation: I'm developing a C++ library which uses drake as a dependency. Specifically I have a custom System, inheriting from LeafSystem<T>:

// my_system.h
#include <drake/systems/framework/leaf_system.h>

template <typename T>
class MySystem : public drake::systems::LeafSystem<T> {
 public:
  MySystem() {}
};

I want to expose this system also via a Python API, also using pybind11 like drake is doing, i.e.:

// my_module.cpp
#include "my_system.h"
#include <drake/systems/framework/leaf_system.h>
#include <pybind11/pybind11.h>

namespace py = pybind11;

PYBIND11_MODULE(my_module, m) {
  py::module::import("pydrake.systems.framework");
  py::class_<MySystem<double>, drake::systems::LeafSystem<double>>(m, "MySystem").def(py::init<>());
}

This compiles with CMake, life is good. But when I try to import MySystem in python, the base class cannot be resolved:

>>> import my_module
Traceback (most recent call last):
  Cell In [2], line 1
    import my_module
ImportError: generic_type: type "MySystem" referenced unknown base type "drake::systems::LeafSystem<double>"

I suspect it has something to do with the way drake generates the actual name of the binding, but this is all way beyond my head: https://github.com/RobotLocomotion/drake/blob/72794d7818ef51629ed97faf6cd325004f49eb9a/bindings/pydrake/common/cpp_template_pybind.h#L90-L93

How can I create python bindings for my class which inherits from drake::system::framework::LeafSystem (or any other system, really)?

Thanks for your help!

The only relevant information I could find on pybind11 is from the officle docs about inheritance, which don't apply in my case, since the bindings of the base have already been written.

I tried to simulate the situation by compiling a libfoo.so which exports one base class Foo and its bindings. If MySystem inherits from Foo I can get the python binding to work just fine:

// Simulated foo library and its bindings
class Foo {};

#include "foo.h"
#include <pybind11/pybind11.h>

namespace py = pybind11;

PYBIND11_MODULE(foo, m) {
  m.doc() = "hello, foo";
  py::class_<Foo>(m, "Foo").def(py::init<>());
}

In another lib, this now works:

class MySystem : Foo {};

PYBIND11_MODULE(my_module, m) {
  py::class_<MySystem, Foo>(m, "MySystem").def(py::init<>());
}

Upvotes: 1

Views: 181

Answers (1)

jwnimmer-tri
jwnimmer-tri

Reputation: 2464

Does it fix it if you add py::module::import("pydrake.systems.framework"); to your PYBIND11_MODULE before trying to define your class?

For any C++ classes used by a pybind11 binding that are from other modules, you need to py::import that module before you can inherit from it (or use it as an argument, or etc).

Upvotes: 1

Related Questions