Wrapping a c++ singleton with cython - cython

Using Cython to wrap some parts from a C++ API to python, I'm having misunderstandings that I couldn't fix by search similar questions. I like to access a Factory class that has the constructors private and a public method GetInstance.
namespace cpplibrary
{
class CppFactory
{
public:
static CppFactory& GetInstance();
private:
CppFactory(void);
CppFactory( const CppFactory& );
};
}
I'm trying a cython code like:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
CppFactory& GetInstance()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = GetInstance()
I've check with as many variants as I thought. With and without the declaration of the constructor in the extern. With different ways to define the _thisptr from different posted examples. And so on. But I couldn't find a singleton example like this.
Where is the mistake I can't see?

I think you've got two issues:
1) How to wrap static methods: the recommended way is to declare the function outside the class, and use a string to tell Cython what name it should use in C++
2) The assignment to thisptr, where you just need to use & to get a pointer from the reference.
Code:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
# declare outside the class and use a string to specify name
# unfortunately this doesn't seem to play well with namespace
# so we need to specify it again
cdef CppFactory& CppFactory_GetInstance "cpplibrary::CppFactory::GetInstance"()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = &CppFactory_GetInstance()

One of the problem is indeed to wrap a static method (here Getinstance()).
You can do that by using the cython #staticmethod decorator (see Cython's doc here):
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
#staticmember
CppFactory& GetInstance()
Then, the .pyx can be:
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = new CppFactory()

Related

Should the reference count of PyObject* created by a cdef public function be manually decreased

I want to export a python class to be used in C++:
class Object:
def method(self):
pass
cdef public object create_object() with gil:
return Object()
cdef public void py_method(object obj) with gil:
obj.method() # obj is expected to have method()
Then the generated header file will have the following functions:
__PYX_EXTERN_C PyObject *create_object(void);
__PYX_EXTERN_C void py_method(PyObject *);
My question is: should I also have a function like
from cpython cimport Py_XDECREF, PyObject
cdef public void destroy_object(PyObject* obj) with gil:
Py_XDECREF(obj)
to avoid memory leak?
Then these functions may be used in C++ code like:
auto obj = create_object()
py_method(obj)
// Finally
destroy_object(obj)
Yes you should decrement it when calling it from C++. You could do it the way you propose or you could skip the definition of destroy_object and just use Py_XDECREF in C++.
Other things you should consider:
create_object can return NULL if it's raised a Python exception so check for that
RAII wrappers are always a good idea (to handle the reference counting)

How to cast a python function to a C function pointer? [duplicate]

Hello i've been trying to call a python user-defined callback from c++ using cython for a while. But it looks like it's impossible without changes on the c++ side or a static function buffer.
So, is there only one option for binding a propper callback (ctypes with CFUNCTYPE)?
Cython 0.29.23
A.hpp:
typedef void (*Callback) ();
class A{
Callback callback;
public:
A(){
this->callback = nullptr;
}
void set_callback(Callback callback){
this->callback = callback;
}
void call_callback(){
this->callback();
}
};
A.pxd:
cdef extern from "A.hpp":
ctypedef void (*Callback) ()
cdef cppclass A:
A() except +
void set_callback(Callback callback)
void call_callback()
B.pyx
from A cimport A, Callback
cdef class B:
cdef A *c_self
cdef object callback
def __cinit__(self):
self.c_self = new A()
def __dealloc__(self):
del self.c_self
cdef void callback_func(self) with gil:
print("I'm here")
self.callback()
def set_callback(self, callback):
self.callback = callback
self.c_self.set_callback(<Callback>self.callback_func)
def call_callback(self):
self.c_self.call_callback()
def print_():
print("hello")
b = B()
b.set_callback(print)
b.call_callback()
Output:
I'm here
[segmentation fault]
Looks like ctypes: get the actual address of a c function is a good one work-around, but it uses ctypes.
It scares me, but works:
B.pyx
from A cimport A, Callback
import ctypes
from libc.stdint cimport uintptr_t
cdef class B:
cdef A *c_self
cdef object callback
def __cinit__(self):
self.c_self = new A()
def __dealloc__(self):
del self.c_self
def set_callback(self, callback):
f = ctypes.CFUNCTYPE(None)(callback)
self.callback = f
cdef Callback c_callback = (<Callback*><uintptr_t>ctypes.addressof(f))[0]
self.c_self.set_callback(c_callback)
def call_callback(self):
self.c_self.call_callback()
def hello():
print("hello")
b = B()
b.set_callback(hello)
b.call_callback()
A function pointer does not have any space to store extra information. Therefore it is not possible to convert a Python callable to a function pointer in pure C. Similarly a cdef function of a cdef class must store the address of the instance to be usable and that is impossible too.
You have three options:
Use ctypes as in https://stackoverflow.com/a/34900829/4657412 (the bottom half of the answer shows how to do it). ctypes accomplishes this with runtime code generation (and thus only works on processors that it explicitly supports).
Use a std::function in C++ instead of a function pointer. These can store arbitrary information. You need to write an object wrapper (or re-use one from elsewhere) so it isn't completely pure Cython. See Pass a closure from Cython to C++. What you're trying to do is probably better covered by How to use a Cython cdef class member method in a native callback.
Use the class C scheme where the callback is of type
void (CallbackT)(/* any args */, void* user_data)
and is registered with:
void register_callback(CallbackT func, void* user_data)
In this case user_data would be the address of your B instances (and you'd need to make sure it was Py_INCREFed before setting the address and Py_DECREFed before unsetting the address). Cython callback with class method provides an example.

Strange behaviour when creating python attributes in cython cdef class

We have given Cython code:
cdef extern from "C_File_A.h":
cdef struct C_Obj_A:
pass
cdef extern from "C_File_B.h":
cdef struct C_Obj_B:
pass
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
cdef class pC_Obj_B:
cdef const C_Obj_B * _c_self
cdef class pC_Obj_C:
cdef const C_Obj_A * _c_a
cdef const C_Obj_B * _c_b
cdef class Obj_A_Wrap(pC_Obj_A):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_a
cdef class Obj_B_Wrap(pC_Obj_B):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_b
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a._c_self = obj_c._c_a
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b._c_self = obj_c._c_b
# Not working
self.obj_a._c_self = obj_c._c_a
self.obj_b._c_self = obj_c._c_b
I need a python object Stack with attrubutes accessible from Python, so I have added to Stack class cdef public pC_Obj_A obj_a and cdef public pC_Obj_B obj_b.These objects are wrappers to the C struct pointers.
When I initialize these objects with intermediary wrappers i.e. Obj_A_Wrap everything is fine.
When I initialize one of these objects directly i.e. self.obj_a._c_self = obj_c._c_a also everything is fine.
When both obj_a and obj_b are initialized directly (# Not Working part of code) I have got strange behaviour of my C library that inlcude C_File_A and C_File_B and respectively the C structs definitions. The behaviour is similar to memory corruption, or overwriting some parts of the memory that should not be.
I have no idea why the direct initialization causes this strange behaviour. Maybe you know?
I have found the solution of my problem. When I was trying to solve this problem I have printed only _c_self attribute of the given object to check that the pointer was properly assigned and it was but when I printed entire object it turned out that python object is None instead of proper object declared as attribute.
print(self.obj_a, self.obj_b) # 66f000c0 66f000c0
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # None None
The solution is to add Create function to cdef class:
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
#staticmethod
cdef Create(C_Obj_A * ptr):
cdef pC_Obj_A result = pC_Obj_A()
result._c_self = ptr
return result
And use it like this:
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
self.obj_a = pC_Obj_A.Create(obj_c._c_a)
self.obj_b = pC_Obj_B.Create(obj_c._c_b)
Then printout is:
print(self.obj_a, self.obj_b) # <pC_Obj_A object at 0x029FF610> <pC_Obj_B object at 0x029FF620>
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # 2134b9c 2134c08
And everything works great!

How to call a cpdef method from C

I have a public class with a method defined with cpdef. According to cython documentation, this can be called from C. However the generated header does not have any C/C++ functions/method generated for this.
cdef public class Model[type ModelType, object Model]:
cdef ModelContext *modelContext
cpdef calculate(self):
print 'calculate called on Modell'

c++ class in fused type

I wish to implement python wrapper for a bunch of c++ classes. Somewhere in pxd I have:
cdef cppclass FooImpl1:
FooImpl1()
int foo()
cdef cppclass FooImpl2
FooImpl2()
int foo()
I wonder if I can write something like this in pyx python wrapper:
ctypedef fused FooImpl:
FooImpl1*
FooImpl2*
cdef class Foo:
cdef FooImpl impl
def __cinit__(self, int selector):
if selector == 1:
self.impl = new FooImpl1()
else:
self.impl = new FooImpl2()
def func(self):
# depending on the object stored in impl FooImpl2::foo or FooImpl1::foo
# will be called
return self.impl.foo()
Is there a way to accomplish expected behavior? FooImpl1 and FooImpl2 don't share abstract interface, they are template specializations of a class.
As of this version (0.20), Cython doesn't support fused types in classes, only in function parameters and variables. Here are the docs.