I have a class Foo() and class Foo() has a function with the following declaration:
bool Foo::copyFile(const std::filesystem::path& src, const std::filesystem::path& dest)
The requirement is that the class Foo should have Python bindings. I am using pybind11 to create the Python bindings.
I have written the following to create the Python bindings:
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "Foo.h"
namespace py = pybind11;
PYBIND11_MODULE(TestModule, m) {
py::class_ <Foo>(m, "Foo")
.def(py::init())
.def("copyFile",&Foo::copyFile);
};
This compiles OK and I am able to create the Python bindings pyd file. When I use the Python bindings for class Foo using:
from TestModule import Foo
f = Foo()
ret = f.copyFile("C:\Users\csaikia\Downloads\testfile_src", "C:\Users\csaikia\Downloads\testfile_dest")
it gives a TypeError. I suspect that it has something to do with pybind11 support for std::filesystem in c++17 since I did not see this happening with other functions of the class that has std::string
or std::vector
.
The error I get is:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: copyFile(): incompatible function arguments. The following argument types are supported:
1. (self: TestModule.Foo, arg0: std::filesystem::path, arg1: std::filesystem::path) -> bool
Invoked with: <TestModule.Foo object at 0x0000000002A33ED8>, 'C:\\Users\\csaikia\\Downloads\\testfile_src', 'C:\\Users\\csaikia\\Downloads\\testfile_dest'
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.
I am new to pybind11. Can someone please help how I can resolve this?
From my conversation with the pybind11 devs:
"Pybind has no idea how to convert a py::str
to std::filesystem::path
. There's no available caster nor has the std::filesystem::path
class been bound.
The easiest way would be to not bind Foo::copyFile
directly. Instead bind a lambda that accepts const Foo&
and const std::string&
as parameters and then you can pass std::string
to copyFile
where std::filesystem::path
is expected, letting C++ implicit conversion take place.
You can maybe also do py::class_<std::filesystem::path>
and make a binding for the std::string
convertor and then use py::implicitly_convertible
to let all that C++ implicit construction happen on python side, but... meh, too much work."
It works like a charm!