Привязки Python с использованием pybind11 с std :: filesystem в качестве аргумента функции, дающего TypeError

У меня есть класс Foo (), а у класса Foo () есть функция со следующим объявлением:

bool Foo::copyFile(const std::filesystem::path& src, const std::filesystem::path& dest)

Требование состоит в том, чтобы у класса Foo были привязки Python. Я использую pybind11 для создания привязок Python.

Для создания привязок Python я написал следующее:

#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);
};

Это нормально компилируется, и я могу создать файл pyd привязок Python. Когда я использую привязки Python для класса Foo, используя:

from TestModule import Foo

f = Foo()
ret = f.copyFile("C:\Users\csaikia\Downloads\testfile_src", "C:\Users\csaikia\Downloads\testfile_dest")

это дает TypeError. Я подозреваю, что это как-то связано с поддержкой pybind11 для std :: filesystem в C ++ 17, поскольку я не видел, чтобы это происходило с другими функциями класса, имеющего std::string или std::vector.

Я получаю следующую ошибку:

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.

Я новичок в pybind11. Может кто-нибудь помочь, как я могу это решить?


person user304255    schedule 06.05.2019    source источник


Ответы (2)


Из моего разговора с разработчиками pybind11:

"Pybind не знает, как преобразовать py::str в std::filesystem::path. Нет доступного кастера и не привязан класс std::filesystem::path.

Самый простой способ - не связывать Foo::copyFile напрямую. Вместо этого привяжите лямбду, которая принимает const Foo& и const std::string& в качестве параметров, а затем вы можете передать std::string в copyFile, где ожидается std::filesystem::path, позволяя неявное преобразование C ++.

Возможно, вы также можете сделать py::class_<std::filesystem::path> и сделать привязку для std::string преобразователя, а затем использовать py::implicitly_convertible, чтобы позволить всей этой неявной конструкции C ++ происходить на стороне Python, но ... эээ, слишком много работы. "

Работает как часы!

person user304255    schedule 06.05.2019

Просто добавьте следующие строки в свои привязки (при условии py::module& m).

py::class_<std::filesystem::path>(m, "Path")
    .def(py::init<std::string>());
py::implicitly_convertible<std::string, std::filesystem::path>();

Это основано на последнем подходе, описанном @ user304255.

person Alexandro Sánchez    schedule 21.04.2020