2

I am trying to get cython to store a Python class as a C++ class for later manipulation by C++ code, and to be able to get a C++ class as a Python class for later manipulation by Python code.

I keep getting "cannot convert Class1 to Python object".

What am I doing wrong?

Here is all the code:

class1.h

#ifndef CLASS1 // header guards
#define CLASS1

using namespace std;

namespace cls {
    class Class1 {
        public:
            Class1();
            ~Class1();
    };
}

#endif

class1.cpp

#include "class1.h"

using namespace cls;

Class1::Class1()
{
}

Class1::~Class1()
{
}

class2.h

#ifndef CLASS2 // header guards
#define CLASS2

using namespace std;

#include "class1.h"

namespace cls {
    class Class2 {
        private:
            Class1 cpp_class;

        public:
            Class2();
            ~Class2();
            Class1& get_class();
            void set_class(const Class1 &c);
    };
}

#endif

class2.cpp

#include "class2.h"
#include "class1.h"

using namespace cls;

Class2::Class2()
{
    cpp_class = new Class1();
}

Class2::~Class2()
{
    delete cpp_class;
}

const Class1& Class2::get_class()
{
    return cpp_class;
}

void Class2::set_class(const Class1 &c)
{
    cpp_class = c;
}

pyclasses.pxd

import cython

cdef extern from "class1.h" namespace "cls":

    cpdef cppclass Class1:
        Class1()

cdef extern from "class2.h" namespace "cls":

    cpdef cppclass Class2:
        Class2()
        Class1 get_class()
        void set_class(Class1)

pyclasses.pyx

cimport pyclasses
from pyclasses cimport Class1, Class2

cdef class PyClass1:

    cdef Class1 *thisptr

    def __init__(self):
        self.thisptr = new Class1()

    def __dealloc__(self):
        del self.thisptr

cdef class PyClass2:

    cdef Class2 *thisptr

    def __init__(self):
        self.thisptr = new Class2()

    def __dealloc__(self):
        del self.thisptr

    def getClass(self):
        return self.thisptr.get_class()

    def setClass(self, Class1 c):
        self.thisptr.set_class(c)

setup.py

from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension

sourcefiles = ['class1.cpp', 'class2.cpp', 'pyclasses.pyx']
compile_opts = ['-std=c++11', '-I../include']
ext=[Extension('pyclass',
               sourcefiles,
               extra_compile_args=compile_opts,
               language='c++')
    ]

setup(
  ext_modules=cythonize(ext)
)

Compile command

python setup.py build_ext --inplace
  • It looks like `PyClass2.getClass` and `PyClass2.setClass` should be marked `cdef` instead of `def` since you can't return a cpp class from a python level function. – chrisb Nov 10 '17 at 17:17
  • Tried that. Still got the same error. Is there something I have to do to the .pxd file? – deepthinker Nov 10 '17 at 18:00
  • For cdef you need to specify the return type of getclass. I think what you're really trying to do though is get or pass a PyClass2. This is slightly trickier since you have to think about ownership (i.e. who calls the destructor, do you want to make a copy or hold a pointer, etc) – DavidW Nov 10 '17 at 20:22
  • 1
    I doubt your class2.cpp compiles. It may seem unrelated, but the answer depends on whether your cpp_class is a pointer or not. – ead Nov 10 '17 at 21:17
  • Possible duplicate of [Calling Cython from c++ with not built-in types](https://stackoverflow.com/questions/47074071/calling-cython-from-c-with-not-built-in-types) – danny Nov 20 '17 at 13:23
  • See [duplicate question](https://stackoverflow.com/questions/47074071/calling-cython-from-c-with-not-built-in-types/47077191#47077191). In short, write factory function to convert from existing C++ pointer to Python cdef class. The other way around, exposing cdef class to C++ can be done with Cython's `public` directive, see [docs](http://cython.readthedocs.io/en/latest/src/reference/extension_types.html#public). – danny Nov 20 '17 at 13:26

0 Answers0