2

I'm trying to pass a C struct from C++ into python as a numpy array using boost::python. I know there are simplier ways to pass C structs to python, but the reason I want to use numpy arrays is that solution is part of a reflection model, so the data type needs to be generated dynamically from a string.

I can serialize the struct passing it to python as a string and call numpy.fromstring() in python which successfully converts it into a numpy array. However, this is not very efficient because converting it to a string copies the data instead of passing it to python by reference.

For example:

#include <boost/python.hpp>

using namespace boost::python;

struct MyRecord
{
    uint32_t myInt;
    char myString[4];
    double myDouble;
};

class MyBaseClass
    :   public wrapper<MyBaseClass>
{
public:
    void myCallback(const MyRecord& data)
    {
        object func = get_override("myCallback");
        if (func) {
            std::string dataStr(reinterpret_cast<const char*>(data), sizeof(data));
            func(dataStr, "[('myInt','<u4'),('myString','|S4'),('myDouble','<f8')]");
        }
    }
};

BOOST_PYTHON_MODULE(example1)
{
    class_<MyBaseClass>("MyBaseClass")
        .def("myCallback", &MyBaseClass::myCallback);
}

#!/usr/bin/env python

import numpy
from example1 import MyBaseClass

class MyClass(MyBaseClass):
    def myCallback(self, dataStr, dtypeStr):
        dt = numpy.dtype(eval(dtypeStr))
        data = numpy.fromstring(dataStr, dt)
        print data # This is now a numpy array

What I'd really like to be able to do is to convert the struct to a numpy array in C++ and pass it by reference directly to python.

I've experimented with the boost::python::numeric::array class, but I'm having problems getting it to convert the C++ type into an numpy array. The constructor is throwing: "TypeError: No to_python (by-value) converter found for C++ type: MyRecord"

There some example code:

#include <boost/python.hpp>
#include <boost/python/exec.hpp>
#include <boost/python/numeric.hpp>

using namespace boost::python;

struct MyRecord
{
    uint32_t myInt;
    char myString[4];
    double myDouble;
};

class MyBaseClass
    :   public wrapper<MyBaseClass>
{
public:
    void myCallback(const MyRecord& data)
    {
        object func = get_override("myCallback");
        if (func) {
            object dtype = exec("eval(\"[('myInt','<u4'),('myString','|S4'),('myDouble','<f8')]\")");
            func(numeric::array(data, dtype));  // numeric::array throws
        }
    }
};

BOOST_PYTHON_MODULE(example2)
{
    class_<MyBaseClass>("MyBaseClass")
        .def("myCallback", &MyBaseClass::myCallback);
}

#!/usr/bin/env python

import numpy
from example2 import MyBaseClass

class MyClass(MyBaseClass):
    def myCallback(self, data):
        print data # This is a numpy array passed from C++

Thanks,

Paul

2

1 Answer 1

3

Ok, I've managed to answer my own question. It wasn't straight-forward, but it works now...

#include <numpy/arrayobject.h>

void MyBaseClass::myCallback(const MyRecord& data)
{
    object func = get_override("myCallback");
    if (func) {
        PyArray_Descr* dtype;
        PyObject* op = Py_BuildValue("[(s,s),(s,s),(s,s)]", "myInt", "<u4", "myString", "|S4", "myDouble", "<f8");
        PyArray_DescrConverter(op, &dtype);
        Py_DECREF(op);
        PyObject* pya = PyArray_FromString(const_cast<char*>(reinterpret_cast<const char*>(&data)), sizeof(data), dtype, 1, NULL);
        // PyObject_Print(pya, stdout, 0);
        numeric::array bpa(static_cast<numeric::array>(handle<>(pya)));
        func(bpa);
    }
}

BOOST_PYTHON_MODULE(example3)
{
    import_array()
    class_<MyBaseClass>("MyBaseClass")
        .def("myCallback", &MyBaseClass::myCallback);
}

Thanks again,

Paul

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.