2016-06-29 11 views
0

はここに私のC APIの関数の例は以下のとおりです。SWIGを使用して、C関数の戻り値の型に基づいて特定の例外を返すにはどうすればよいですか?

int do_something(struct object *with_this) 
struct object *get_something(struct object *from_this) 

do_somethingが成功したか-1ため0を返し、失敗のerrnoを設定します。 get_somethingは成功した場合には有効なポインタを返し、失敗の場合にはerrnoを設定します。

私はSWIG 2.0を使用してPythonバインディングを生成しています。 do_somethingバインディングについては、失敗した場合はerrnoに基づいて例外を返したいと思います。成功した場合は、Python Noneオブジェクトを返します。 get_somethingバインディングについては、それが失敗した場合はerrnoに基づく例外を返し、成功した場合は不透明オブジェクトを返したいと思います。

質問はどのように私はこの魔法のすべてを私にするのですか?

現在、私はSWIG 2.0を使用しています。

私は%exceptionを使用することができ、シンボルごとに異なる例外を定義できますが、戻り値の型に基づいています。私は多くのAPI関数を持っているので、それらをリストアップしたくありません。だから私は、各シンボルのためにこれを行うことができます。

%exception do_something { 
    $action 
    if (result < 0) { 
     return PyErr_SetFromErrno(PyExc_RuntimeError); 
    } 
} 

%exception get_something { 
    $action 
    if (result == NULL) { 
     return PyErr_SetFromErrno(PyExc_RuntimeError); 
    } 
} 

(あなたが%typemapで行うことができますように)私はこのような何かを行うことができれば、それは多くの方のようになります。

%exception int { 
    $action 
    if (result < 0) { 
     return PyErr_SetFromErrno(PyExc_RuntimeError); 
    } 
} 

%exception struct object * { 
    $action 
    if (result == NULL) { 
     return PyErr_SetFromErrno(PyExc_RuntimeError); 
    } 
} 

は、私のような何かを行うことができますこの?このようなものがあれば、それは例外を処理するでしょう。そして、私はget_somethingバインディングが完璧だと信じています。

マイdo_somethingまだ私は%typemapを使用する場合には、Pythonなしオブジェクトを返すために取得するには、このようなものが必要でしょうバインディング:

%typemap(out) int { 
    $result = Py_BuildValue(""); 
} 

は、私が存在を探していますか私はこのすべてについてつもり魔法をい違う?これを行うより良い方法はありますか?

struct object { int bar; }; 

static int do_something(struct object *with_this) { 
    errno = EACCES; 
    return -1; 
} 

static struct object *get_something(struct object *from_this) { 
    errno = EAGAIN; 
    return NULL; 
} 

私は%typemap(out)がする場所であることをかなり確信している:私はあなたの機能を取り、実際に問題を説明するのに十分な実際のコードが含まれ、次のTEST.Hファイルを作成し、この質問に答えるために

+0

あなたのユースケースのための '%exception'は赤い鳴き声であり、あなたは'%typemap(out) 'または'%pythoncode'のいずれかの中ですべてそれをしたいと思っています。誰も私にそれを打つことができなければ、私は試してみて、あなたのために適切な答えを書くことを忘れないでください。 – Flexo

+0

フレキソありがとうございます。 'typemap(out)'を試してみましたが、問題は型の処理を再実装する必要があることです。これは 'get_something'の場合にはやりたくないものです。 'get_something'の場合、例外を処理したいが、そのまま型を処理したいだけです。 –

+0

私はあなたが心配していることを見て、私はそれについて考えて、いくつかの解決策を示します。 – Flexo

答えて

0

%exceptionではなく、このコードを記述します。これは、呼び出す関数の名前ではなく、戻り値の型によって必要な動作が決まるためです。リターンの価値を気にしているという事実は、これをさらに裏付けています。 $typemapを使用して、あなたの中の他のタイプマップを参照することは、ある程度繰り返しを避けることができます。私は明示的にdo_somethingという名前のためのtypemapに一致する場合にのみけれども働い

Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import test 
>>> test.do_something(None) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: (13, 'Permission denied') 
>>> test.get_something(None) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
RuntimeError: (11, 'Resource temporarily unavailable') 
>>> 

、そう:

試験したときに働いていた
%module test 

%{ 
#include <errno.h> 
#include "test.h" 
%} 

%typemap(out) int do_something %{ 
    if ($1 < 0) { 
    PyErr_SetFromErrno(PyExc_RuntimeError); 
    SWIG_fail;  
    } 
    $result = Py_None; // Return only controls exception 
    Py_INCREF($result); 
%} 

%typemap(out) struct object *get_something %{ 
    if (!$1) { 
    PyErr_SetFromErrno(PyExc_RuntimeError); 
    SWIG_fail; 
    } 

    // Return passed through unless NULL 
    $typemap(out,$1_ltype); 
%} 

%include "test.h" 

だから私は、これを説明するために少しSWIGインタフェースを書きました名前付き関数なしのフォールバックは問題ありません。その制限を削除しようとすると、再帰的な型マップに関するエラーが発生します。 %applyを使用して回避することができます。

%typemap(out) struct object * MY_NULL_OR_ERRNO %{ 
    if (!$1) { 
    PyErr_SetFromErrno(PyExc_RuntimeError); 
    SWIG_fail; 
    } 

    $typemap(out,$1_ltype); 
%} 

%apply struct object * MY_NULL_OR_ERRNO { struct object *get_something, struct object *some_other_function }; 

それはあまりにも痛いなら、あなたはもちろん、単に手でタイプマップ書くことができます:あなたは本当にどこにでもstruct object*が返されることをしたい場合、最も簡単なオプションを思わ

%typemap(out) struct object * %{ 
    if (!$1) { 
    PyErr_SetFromErrno(PyExc_RuntimeError); 
    SWIG_fail; 
    } 

    $result = SWIG_NewPointerObj(SWIG_as_voidptr($1), $1_descriptor, $owner); 
%} 

を。

%pythoncodeまたは%pythonappendを使用する可能性のある他の解決策もありますが、どちらも実際には私の見解では上の改善点ではありません。

+0

ありがとう!これはまさに私が必要としていたものです。あなたの最後の「手書きのタイプマップ」は私が一番好きなものです。自動変数を使ってすべての情報を取得する方法があることをうれしく思っています。代替案も提供してくれてありがとう。彼らは間違いなく便利になるでしょう。驚くべき答え! –

関連する問題