Pengikatan python menggunakan pybind11 dengan std::filesystem sebagai argumen fungsi yang memberikan TypeError

Saya memiliki kelas Foo() dan kelas Foo() memiliki fungsi dengan deklarasi berikut:

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

Persyaratannya adalah kelas Foo harus memiliki binding Python. Saya menggunakan pybind11 untuk membuat binding Python.

Saya telah menulis yang berikut ini untuk membuat binding 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);
};

Ini mengkompilasi OK dan saya dapat membuat file pyd binding Python. Ketika saya menggunakan binding Python untuk kelas Foo menggunakan:

from TestModule import Foo

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

itu memberikan TypeError. Saya menduga ini ada hubungannya dengan dukungan pybind11 untuk std::filesystem di c++17 karena saya tidak melihat ini terjadi dengan fungsi lain dari kelas yang memiliki std::string atau std::vector.

Kesalahan yang saya dapatkan adalah:

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.

Saya baru mengenal pybind11. Dapatkah seseorang tolong bantu bagaimana saya bisa mengatasi ini?


person user304255    schedule 06.05.2019    source sumber


Jawaban (2)


Dari percakapan saya dengan pengembang pybind11:

"Pybind tidak tahu cara mengonversi py::str menjadi std::filesystem::path. Tidak ada kastor yang tersedia dan kelas std::filesystem::path juga belum terikat.

Cara termudah adalah dengan tidak mengikat Foo::copyFile secara langsung. Alih-alih ikat lambda yang menerima const Foo& dan const std::string& sebagai parameter dan kemudian Anda dapat meneruskan std::string ke copyFile di mana std::filesystem::path diharapkan, sehingga konversi implisit C++ terjadi.

Anda mungkin juga dapat melakukan py::class_<std::filesystem::path> dan membuat pengikatan untuk konverter std::string dan kemudian menggunakan py::implicitly_convertible untuk membiarkan semua konstruksi implisit C++ terjadi di sisi python, tapi... yah, terlalu banyak pekerjaan."

Ini bekerja dengan sangat baik!

person user304255    schedule 06.05.2019

Cukup tambahkan baris berikut ke binding Anda (dengan asumsi py::module& m).

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

Hal ini didasarkan pada pendekatan terakhir yang dijelaskan oleh @ user304255.

person Alexandro Sánchez    schedule 21.04.2020