-
-
Save zed/84de2115f164d1ad031e to your computer and use it in GitHub Desktop.
convert c array to numpy array in python callback provided by ctypes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/build/ | |
/pointer2ndarray.cpp | |
/pointer2ndarray.h | |
/pointer2ndarray.so | |
/pointer2ndarray_api.h | |
/test_pointer2ndarray | |
/call_callback.o | |
/call_callback.so |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "call_callback.h" | |
void call_callback(bool (*callback)(double*, long long)) { | |
double data[] = {3,2,1}; | |
if (!callback(data, sizeof(data)/sizeof(data[0]))) | |
std::cerr << "callback failed" << std::endl; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef HAVE_call_callback | |
#define HAVE_call_callback | |
#ifdef __cplusplus | |
#define EXTERN_C extern "C" | |
#else | |
#define EXTERN_C extern | |
#endif | |
EXTERN_C void call_callback(bool (*)(double *, long long)); | |
#endif /* !HAVE_call_callback */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
NAME = pointer2ndarray | |
all: test test_frompython test_call_callback | |
test: test_pointer2ndarray $(NAME).so | |
env PYTHONPATH=. ./$< | |
test_frompython: test_pointer2ndarray.py $(NAME).so | |
python $< | |
test_pointer2ndarray: test_pointer2ndarray.cpp pointer2ndarray_api.h $(NAME).so | |
$(CXX) -g -Wall -I/usr/include/python2.6 -lpython2.6 $< -o $@ | |
test_call_callback: test_call_callback.py $(NAME).so call_callback.so | |
LD_LIBRARY_PATH=. python $< | |
call_callback.so: call_callback.o | |
$(CXX) -shared -Wl,-O1 -Wl,-Bsymbolic-functions $< -o $@ | |
call_callback.o: call_callback.cpp call_callback.h | |
$(CXX) -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -fPIC -c $< -o $@ | |
pointer2ndarray_api.h $(NAME).so: setup.py $(NAME).pyx | |
python setup.py build_ext -i | |
clean: | |
git clean -x -d -f |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from libcpp cimport bool | |
cimport libc.string # memcpy | |
import numpy as _np | |
cimport numpy as np | |
np.import_array() # initialize C API to call PyArray_SimpleNewFromData | |
cdef public api bool ptsetDataSource(double* data, long long size) with gil: | |
if not data: return False | |
print "ptsetDataSource", | |
tonumpyarray(data, size) | |
return True | |
cdef public api bool ptsetDataSourceCopy(double* data, long long size) with gil: | |
if not data: return False | |
cdef np.ndarray[np.float_t,ndim=1] a = _np.empty(size, dtype=_np.float) | |
assert a.shape[0] == size and a.itemsize == sizeof(data[0]) | |
assert a.flags['C_CONTIGUOUS'] | |
libc.string.memcpy(a.data, <char*>data, a.nbytes) | |
print "ptsetDataSourceCopy", repr(a) | |
return True | |
cpdef call_ptsetDataSource(np.ndarray[np.float_t,ndim=1] data): | |
assert data is not None | |
if not data.flags['C_CONTIGUOUS']: | |
data = _np.ascontiguousarray(data) | |
print "call_ptsetDataSource", | |
if not ptsetDataSource(<double*>data.data, data.shape[0]): | |
raise RuntimeError("call_ptsetDataSource(%s)" % (data,)) | |
cdef public api tonumpyarray(double* data, long long size) with gil: | |
assert data and size >= 0 | |
cdef np.npy_intp dims = size | |
#NOTE: it doesn't take ownership of `data`. You must free `data` yourself | |
cdef np.ndarray[np.float_t,ndim=1] a = np.PyArray_SimpleNewFromData( | |
1, &dims, np.NPY_DOUBLE, <void*>data) | |
print "tonumpyarray", repr(a) | |
return a |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from distutils.core import setup | |
from distutils.extension import Extension | |
from Cython.Distutils import build_ext | |
setup(ext_modules=[Extension( | |
"pointer2ndarray", # name of extension | |
["pointer2ndarray.pyx"], # our Cython source | |
language="c++", # bool type | |
)], | |
cmdclass={'build_ext': build_ext}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from ctypes import (PYFUNCTYPE, py_object, POINTER, c_double, c_longlong, | |
pydll, CFUNCTYPE, c_bool, cdll) | |
import pointer2ndarray | |
tonumpyarray = PYFUNCTYPE(py_object, POINTER(c_double), c_longlong)( | |
("tonumpyarray", pydll.LoadLibrary(pointer2ndarray.__file__))) | |
@CFUNCTYPE(c_bool, POINTER(c_double), c_longlong) | |
def callback(data, size): | |
a = tonumpyarray(data, size) | |
# call scipy functions on the `a` array here | |
return True | |
cpplib = cdll.LoadLibrary("call_callback.so") # your C++ lib goes here | |
cpplib.call_callback(callback) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Embed Python interpreter and call C API function from | |
// pointer2ndarray Python module | |
#include <iomanip> | |
#include <iostream> | |
#include "Python.h" // Py_Initialize Py_Finalize | |
#include "pointer2ndarray_api.h" // import_pointer2ndarray ptsetDataSource | |
int main() { | |
using namespace std; | |
cout << "initialize python interpreter" << endl; | |
Py_Initialize(); | |
cout << "import pointer2ndarray module and initialize C API" << endl; | |
if (import_pointer2ndarray() < 0) { | |
cerr << "import pointer2ndarray failed\n"; | |
return 1; | |
} | |
cout << "call ptsetDataSource" << endl; | |
double data[] = {1,2,3}; | |
cout << boolalpha << ptsetDataSource(data, sizeof(data)/sizeof(data[0])) | |
<< endl; | |
cout << "shutdown the interpreter" << endl; | |
Py_Finalize(); | |
cout << "The End" << endl; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# call C API function defined in pointer2ndarray.so | |
from ctypes import cdll, CFUNCTYPE, POINTER, c_longlong, c_bool, c_double | |
import pointer2ndarray # required | |
c_double_p = POINTER(c_double) | |
prototype = CFUNCTYPE(c_bool, c_double_p, c_longlong) | |
lib = cdll.LoadLibrary(pointer2ndarray.__file__) | |
for i, name in enumerate(pointer2ndarray.__pyx_capi__): | |
if "ptsetDataSource" not in name: continue | |
f = prototype((name, lib)) | |
def errcheck(result, func, arguments): | |
if not result: raise RuntimeError("%s %s" % (name, arguments)) | |
f.errcheck = errcheck | |
ary = (c_double*2)(i, .25) | |
f(ary, len(ary)) | |
# call C API function with a numpy array | |
import numpy as np | |
npary = np.array([[11, 12, 13],[21,22,23]], dtype=np.float) | |
a = np.ascontiguousarray(npary[:,1]) | |
f(a.ctypes.data_as(c_double_p), a.shape[0]) | |
# call python function defined in the extension module | |
from pointer2ndarray import call_ptsetDataSource | |
call_ptsetDataSource(npary[:,1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment