I have a Python C Extension that wraps the library for a proprietary product. Our company has a large amount of C code that uses the proprietary product. Instead of rewriting this in Python using my C Extension, I figured I could simply return a Capsule to Python land, and allow the user of my library to wrap some C function with ctypes.
Is this a valid approach? Is there a better one?
Here is some code to illustrate my approach.
My Python C Extension:
typedef struct {
PyObject_HEAD
Foo *foo; /* The proprietary data structure we are wrapping */
} PyFoo;
/*
* Expose a pointer to Foo such that ctypes can use it
*/
static PyObject PyFoo_capsule(PyFoo *self, PyObject *args, PyObject *kwargs)
{
return PyCapsule_New(self->foo, "foo", NULL);
}
Here is some pre-existing C code our team has written, and wants to call from Python:
void print_foo(Foo *foo)
{
Foo_print(foo);
}
And in Python, we can wrap the third party C code with ctypes (I learned this here):
import pyfoo
import ctypes
foo = pyfoo.Foo()
capsule = foo.capsule()
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object, ctypes.c_char_p]
pointer = ctypes.pythonapi.PyCapsule_GetPointer(
capsule,
ctypes.create_string_buffer("foo".encode())
)
libfoo = ctypes.CDLL('libfoo.so')
libfoo.print_foo.restype = None
libfoo.print_foo.argtypes = [ctypes.POINTER(None)]
libfoo.print_foo(pointer)