yegle
yegle

Reputation: 5875

SWIG: How to typemap the return value based on the original return value?

Here's a very simple C function:

bool GetSomething(string* result)

After calling this function, the return value should indicate if the result holds the needed information, and user can check the return value to handle accordingly.

To SWIG this function to be used in Python code, I use the default typemaps.i file and then changed the function to

bool GetSomething(string* OUTPUT)

This works but still cumbersome. I'll have to do this to get the result I want:

success, result = GetSomething()
if success:
    # handle result
else:
    # throw exception

Ideally I'd like to have this interface instead:

result = GetSomething()
if result:
    # handle result

Any help would be appreciated.

Upvotes: 2

Views: 1747

Answers (2)

Mark Tolonen
Mark Tolonen

Reputation: 177901

Here's an example .i file of the idea mentioned in comments. Convert a successful return status to None and a failing return status to an exception in Python, and append output parameters to the return value. This requires no changes to the C++ code base:

%module x

%include <exception.i>

// convert non-zero int return values to exceptions
%typemap(out) int %{
    if($1)
        SWIG_exception(SWIG_RuntimeError,"non-zero return value");
    $result = Py_None;
    Py_INCREF(Py_None); // Py_None is a singleton so increment its reference if used.
%}

// Easy way for int*, but customize below for more complicated types
// %apply int* OUTPUT {int*};

// suppress the output parameter as an input.
%typemap(in,numinputs=0) int* (int tmp) %{
    $1 = &tmp;
%}

// append int* output parameters to the return value.
%typemap(argout) int* {
    PyObject* tmp = PyLong_FromLong(*$1);
    $result = SWIG_Python_AppendOutput($result,tmp);
}

// %inline declares and exposes a function
%inline %{
    int func(int val, int* pOut)
    {
        if(val < 1)
            return 1;
        *pOut = 2 * val;
        return 0;
    }
%}

If you SWIG this .i with swig -python -c++ x.i and compile the result into a Python extension:

>>> import x
>>> x.func(2)
4
>>> x.func(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: non-zero return value

Upvotes: 5

yegle
yegle

Reputation: 5875

My current hack, hope this helps someone.

%{
 #define GetSomething 1
%}

%typemap(out) bool %{
#if $symname == 1
if (result) {
return Py_FromString(arg0->data());
} else {
return Py_None;
}
#endif
%}

Upvotes: 0

Related Questions