pythonc++pybind11

PyBind11 produces pyd file without any class i defined


I am working on wrapping a C++ class using Pybind11 to make it accessible in Python. My project involves a dynamic library built with Qt6, which contains a class named Package. I am writing a wrapper class called PackageExt, and I am using Pybind11 to bind this wrapper to a Python module. Below is the code I am working with:

C++ Wrapper Header (packageext.h)

#ifndef PACKAGEEXT_H
#define PACKAGEEXT_H

#include "package.h" // from the dynamic library

class PackageExt {
public:
    PackageExt(const std::string &id);
    PackageExt(const ContainerCore::Package &pkg);
    PackageExt(const PackageExt &other);
    PackageExt& operator=(const PackageExt &other);
    ~PackageExt();
    void setPackageID(const std::string &id);
    std::string packageID() const;
    ContainerCore::Package* getBasePackage();
private:
    ContainerCore::Package *mPackage; // Defined in the dynamic library
};

#endif // PACKAGEEXT_H

Pybind11 Binding (bindcontainer.cpp)

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "packageext.h"

namespace py = pybind11;

PYBIND11_MODULE(ContainerPy, m) {
    m.doc() = "Pybind11 plugin for Container library";

    py::class_<PackageExt>(m, "Package")
        .def(py::init<const std::string &>(), py::arg("id"),
             "Constructor that initializes a Package with the specified ID.")
        .def("get_package_id", &PackageExt::packageID,
             "Get the package ID as std::string.")
        .def("set_package_id", &PackageExt::setPackageID, py::arg("id"),
             "Set the package ID using std::string.");
}

CMake Configuration (CMakeLists.txt)

find_package(Python REQUIRED COMPONENTS Interpreter Development)
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Core Concurrent Xml Network Sql)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Concurrent Xml Network Sql)
find_package(pybind11 REQUIRED CONFIG HINTS ${PYBIND11_HINTS_PATH})
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BINDING_FILES
    bindcontainer.cpp
    containerext.cpp
    packageext.cpp
    containermapext.cpp
)
pybind11_add_module(${PYTHON_LIB_NAME} MODULE ${BINDING_FILES})
target_link_libraries(${PYTHON_LIB_NAME} PRIVATE Container) # Dynamic library
target_link_libraries(${PYTHON_LIB_NAME} PRIVATE Qt6::Core Qt6::Concurrent Qt6::Network Qt6::Xml Qt6::Sql)
target_link_libraries(${PYTHON_LIB_NAME} PRIVATE Python::Python)

Issue: After building the module, I successfully get a .pyd file. However, when I import the module in Python and inspect it, I see the following:

python

import ContainerPy
print(dir(ContainerPy))
The output is:
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']

It appears that the Package class and its methods are not being exposed as expected. What could be causing this issue, and how can I troubleshoot or fix it?

Additional Details:

What I Have Tried:

Questions:


Solution

  • I encountered an issue where the Pybind11 bindings for my C++ class were not visible in Python, despite the .pyd file being generated correctly. After ensuring all configurations were correct and troubleshooting with the help of the community, the solution was surprisingly simple.

    Problem: The .pyd file, although located in the correct site-packages directory, wasn't being recognized properly by Python. This was due to Python treating directories as potential packages.

    Operating System: Ubuntu Solution: The issue was resolved by adding an __init__.py file to the directory containing the .pyd file. I added the following import statement to clarify the purpose:

    from .ContainerPy import *