Swig typemap for python: input and output arrays

I have a C function that I want to use in Python:

extern int convertAtoB( stateStruct *myStruct, const double PointA[3], double PointB[3]); 

Using SWIG, I think I need to define a map-map to convert two points (PointA input, PointB output) so that Python can use it. It seems that there is no typemap in typemaps.i that works with this, so I have to define it. I cannot find examples of this for arrays in the SWIG documentation.

I would like to use this library like this:

 s = externalStruct() point_a = [1, 2, 3] result, point_b = convertAtoB(s, point_a) print point_b "expect [4, 5, 6]" 

How can I do it? Thanks

+4
source share
3 answers

One solution was found here, but it may not be the best:

 %typemap(in) double[ANY] (double temp[$1_dim0]) { int i; if (!PySequence_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a sequence"); return NULL; } if (PySequence_Length($input) != $1_dim0) { PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements"); return NULL; } for (i = 0; i < $1_dim0; i++) { PyObject *o = PySequence_GetItem($input,i); if (PyNumber_Check(o)) { temp[i] = (double) PyFloat_AsDouble(o); } else { PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers"); return NULL; } } $1 = temp; } 

This is an example in the docs I finally got into that convert Python lists to arrays. The next part was more difficult, having collected some examples, I was able to convert the returned array to a python list:

 %typemap(argout) double PointB[3]{ PyObject *o = PyList_New(3); int i; for(i=0; i<3; i++) { PyList_SetItem(o, i, PyFloat_FromDouble($1[i])); } $result = o; } 

However, I must create one for each return value in the API. Also I have to call it with a dummy value as a parameter:

 point_b = convertAtoB(s, point_a, dummy) 

Is there a better way?

+1
source

You are almost there. To get rid of the dummy argument in the python signature, you need to change %typemap(in) on PointB[3] to %typemap(in,numinputs=0) to instruct SWIG to ignore this input value (you copy it anyway). This will remove the dummy argument from the python method signature.

I'm not sure, however, if you need to copy all %typemap(in) for this specialization. There is probably a way to reuse the actual map, but I do not know how to do this. Otherwise, you will receive an additional

 %typemap(in,numinputs=0) double PointB[3] (double temp[$1_dim0]) { int i; if (!PySequence_Check($input)) { PyErr_SetString(PyExc_ValueError,"Expected a sequence"); return NULL; } if (PySequence_Length($input) != $1_dim0) { PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements"); return NULL; } for (i = 0; i < $1_dim0; i++) { PyObject *o = PySequence_GetItem($input,i); if (PyNumber_Check(o)) { temp[i] = (double) PyFloat_AsDouble(o); } else { PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers"); return NULL; } } $1 = temp; } 
+3
source

This is an old thread, but I am responding to it because not many messages were received in response to SWIG.

To specifically tune the situation above

 %typemap(in, numinputs=0) double PointB[3] { double tmp[3]; $1 = tmp; } %typemap(argout) double PointB[3] { PyObject *o = PyList_New(3); int i; for(i=0; i<3; i++) { PyList_SetItem(o, i, PyFloat_FromDouble($1[i])); } $result = o; } 
+1
source

All Articles