Reputation: 43
in my C++/Pybind11 project I have a C++ class Foo
that can be subclassed in Python. As usual, I went through the usual process of having a trampoline class PyFoo
and the customary bindings.
However, now it turned out that it would be useful to have the start
method of Foo
to take key words arguments (pybind11::kwargs
).
In my project, I also have a class Caller
that holds a collection of Foo
s. Caller
exposes a method start
that calls the start
method of the required foo, forwarding the
kwargs
to the Foo
's start
method.
However, calling Caller
's start method from Python always generates the following error:
TypeError: start() takes 1 positional argument but 2 were given
Here's the complete code to reproduce the issue. Is this something possible and if so, what should I do to make it work?
File foo.h/cpp
#pragma once
#include <pybind11/pybind11.h>
#include <iostream>
// c++ class
class Foo {
public:
Foo() = default;
virtual ~Foo() = default;
virtual void start(pybind11::kwargs args) {}
virtual void update(double) {}
};
// trampoline class
class PyFoo : public Foo {
public:
using Foo::Foo; // Inherit constructors
void PyFoo::start(pybind11::kwargs args) override {
std::cout << "mane\n";
PYBIND11_OVERRIDE(
void, // Return type
Foo, // Parent class
start, // Name of function in C++
args
);
void PyFoo::update(double dt) {
PYBIND11_OVERRIDE(
void, // Return type
Foo, // Parent class
update, // Name of function in C++
dt
);
};
class Caller {
public:
void start(int id, pybind11::kwargs args) {
_controllers[id]->start(std::move(args));
}
void add(pybind11::object foo) {
_objs.push_back(foo);
_controllers.push_back(foo.cast<std::shared_ptr<Foo>>());
}
private:
std::vector<pybind11::object> _objs;
std::vector<std::shared_ptr<Foo>> _controllers;
};
Here's the bindings:
namespace py = pybind11;
PYBIND11_MODULE(untitled3, m) {
py::class_<Foo, PyFoo, std::shared_ptr<Foo>>(m, "Foo")
.def(py::init<>());
py::class_<Caller, std::shared_ptr<Caller>>(m, "Caller")
.def(py::init<>())
.def("add", &Caller::add)
.def("start", &Caller::start);
}
Here's the Py code
import untitled3
class Bar(untitled3.Foo):
def __init__(self):
super().__init__()
def start(self, **kwargs):
print('ici')
def update(self, dt):
print('here')
c = untitled3.Caller()
c.add(Bar())
c.add(Bar())
c.start(1)
Upvotes: 0
Views: 37