2

I'm trying to expose C++ class and method to Python. Therefore I opted to use Cython to wrap the two. C++ code is a part of a catkin package, so I researched ways how to integrate Cython compilation inside catkin_make.

In my dummy example, there's a C++ class A, and a factory method get_a() which returns a shared_ptr<A>. On Cython side I created one pair of files example_a.pxd and example_a.pyx which wrap C++ class A into PyA, and c_example_a_factory.pxd and example_a_factory.pyx which wrap a C++ method get_a() into a Cython method of the same name. I both import and cimport class PyA from example_a module to example_a_factory, and it compiles nicely. However, when I try to import example_a_factory from python, I get an error:

ImportError: No module named example_a

I found several repos that try to accomplish something similar to what I need, in regard to build process, and I followed those examples: ros_cython_example, cython_catkin_example, cython_cmake_example

You can find my example code in this repo, together with instructions on how to run it. For easier reference, I'm posting Cython files here as well:

example_a.pxd

from libcpp.memory cimport shared_ptr


cdef extern from "catkin_cython_example/example_a.hpp" namespace "example_a":

    cdef cppclass A:
        int get() const

cdef class PyA:
    cdef shared_ptr[A] c_a  # Hold a C++ instance which we're wrapping

    @staticmethod
    cdef inline create(shared_ptr[A] c_a):
        cdef PyA py_a = PyA()
        py_a.c_a = c_a

        return py_a

example_a.pyx

from cython.operator cimport dereference as d


cdef class PyA:

    def get(self):
        cdef int v = d(self.c_a).get()
        return v

c_example_a_factory.pxd

from libcpp.memory cimport shared_ptr

from example_a cimport A

cdef extern from "catkin_cython_example/example_a_factory.hpp" namespace "example_a_factory":

    shared_ptr[A] get_a(int val) except +

example_a_factory.pyx

from libcpp.memory cimport shared_ptr

cimport c_example_a_factory
from example_a cimport A, PyA
from example_a import PyA


def get_a(val):
    cdef shared_ptr[A] c_a = c_example_a_factory.get_a(val)
    return PyA.create(c_a)

I tested putting everything inside one module, and the code works fine, but I'd rather have separate modules for easier maintainability and logic decoupling. All the help is appreciated!

makons
  • 522
  • 1
  • 11
  • 27
  • and do you see a so-file (example_a.xxx.so) somewhere around? Was it compiled with the same python version? – ead Jun 03 '19 at 09:32
  • In the first version of cmake files no, example_a.so wasn't generated. However, I just pushed some changes made in the meantime, which do generate the binary, and I still get the `ImportError`. – makons Jun 03 '19 at 10:36

0 Answers0