2011-11-10 12 views
3

私はクライアントがサーバーのAPIを呼び出してユーザー入力用のPythonインターフェイスを提供するサーバークライアントアプリケーションを開発しています。つまり、クライアントインターフェイスとサーバーインターフェイスはPythonで書かれていますが、ソケットコードはC++で書かれています。サーバー側ではC++でPython例外をキャッチ

: -

私はC++で、クラス、Testを持っていると、このクラスはPythonで継承されているがSWIGのディレクター機能を使用してTestPythonを命名しました。 また、私はC++で例外クラスMyExceptionを持っています。

TestPythonクラスの関数は、PythonコードからMyException()をスローします。

SWIGを使用しているC++コードでPythonからスローされた例外を処理したいと考えています。 - TestException()関数が呼び出された場合今

class TestPython(Test): 
    def __init__(self): 
    Test.__init__(self) 

    def TestException(self,val): 
    if val > 20: 
     throw MyException("MyException : Value Exceeded !!!") 
    else:  
     print "Value passed = ",val 

、それは MyExceptionをスローする必要があり

C++コード -

class MyException 
{ 
    public: 
    string errMsg; 
    MyException(); 
    MyException(string); 
    ~MyException(); 
}; 

class Test 
{ 
    int value; 
    public: 
     void TestException(int val); 
     Test(int); 
}; 

Pythonのコード:

は、以下のコードです。私はこのMyException()の例外を私のC++コードで処理したい。

誰も私のやり方を示唆することができます。私は、これを処理するために私の* .i(インタフェース)ファイルに何を書き込むべきですか?

上記のTestException()はPythonで記述されているため、クライアントから例外がスローされた場合はクライアントに通知する必要があります。

+0

このトピックに関するSWIGのドキュメントをご覧になりましたか? (http://www.swig.org/Doc2.0/SWIGDocumentation.html#Customization_exception) – gecco

+0

SWIGのディレクター機能を使用していることをもう少し明白にしたいと思うかもしれません。あなたが表示したコードでは何もヒントがありません。 – Flexo

+0

@gecco - ディレクターからのSWIG Pythonコード(例外的に 'director:except')によってスローされた例外については、まったく詳しくは書かれていません。 – Flexo

答えて

3

これを行うには、基本的にPythonの例外を処理してC++のものとして再スローすることができる%feature("director:except")を書く必要があります。ここでは、小さいながらも完全な例です:

#include <iostream> 
#include <exception> 

class MyException : public std::exception { 
}; 

class AnotherException : public std::exception { 
}; 

class Callback { 
public: 
     virtual ~Callback() { std::cout << "~Callback()" << std:: endl; } 
     virtual void run() { std::cout << "Callback::run()" << std::endl; } 
}; 

inline void call(Callback *callback) { if (callback) callback->run(); } 

そして、それを使用して、このPythonコード:

は、我々はラップしたい、次のヘッダファイルがあるとし

import example 

class PyCallback(example.Callback): 
    def __init__(self): 
     example.Callback.__init__(self) 
    def run(self): 
     print("PyCallback.run()") 
     raise example.MyException() 

callback = PyCallback() 
example.call(callback) 

私たちは、次のように定義することができますSWIGインタフェースファイル:

%module(directors="1") example 
%{ 
#include "example.h" 
%} 

%include "std_string.i" 
%include "std_except.i" 
%include "pyabc.i" 

// Python requires that anything we raise inherits from this 
%pythonabc(MyException, Exception); 

%feature("director:except") { 
    PyObject *etype = $error; 
    if (etype != NULL) { 
     PyObject *obj, *trace; 
     PyErr_Fetch(&etype, &obj, &trace); 
     Py_DecRef(etype); 
     Py_DecRef(trace); 
     // Not too sure if I need to call Py_DecRef for obj 

     void *ptr; 
     int res = SWIG_ConvertPtr(obj, &ptr, SWIGTYPE_p_MyException, 0); 
     if (SWIG_IsOK(res) && ptr) { 
     MyException *e = reinterpret_cast< MyException * >(ptr); 
     // Throw by pointer (Yucky!) 
     throw e; 
     } 

     res = SWIG_ConvertPtr(obj, &ptr, SWIGTYPE_p_AnotherException, 0); 
     if (SWIG_IsOK(res) && ptr) { 
     AnotherException *e = reinterpret_cast< AnotherException * >(ptr); 
     throw e; 
     } 

     throw Swig::DirectorMethodException(); 
    } 
} 

%feature("director") Callback; 
%include "example.h" 

ディレクタコールのエラーを処理するものは、次のとおりですoそれが私たちのMyExceptionインスタンスの1つだったかどうかを確認し、ポインタがあればそれを再スローします。複数のタイプの例外がスローされている場合は、最初にどのタイプを処理するかは、おそらくPyErr_ExceptionMatchesを使用する必要があります。

我々は使用して値または参照でも投げることができます:代わりに

// Throw by value (after a copy!) 
    MyException temp = *e; 
    if (SWIG_IsNewObj(res)) 
    delete e; 
    throw temp; 

ていますが、PythonでMyExceptionサブクラスを投げた場合、これはobject slicing problemのファウルを下落するだろうことに注意してください。

コードが100%正しいかどうかは確かではありません。特に、参照カウントが正しいと思いますが、間違っている可能性があります。

注:この例を動作させるには(%pythonabcは別の方法では動作しません)、-py3でSWIGを呼び出す必要がありました。これは、SWIG 2.0にアップグレードしなければならないことを意味しました。なぜなら、Python 3.2のインストールされたコピーは、SWIG 1.3.40が呼び出すC-APIから廃止予定の機能を削除したからです。

+0

私はあなたがクラスをもう一つ例外クラスを持っている場合、どのように私は例外を処理することができます表示するPLZをすることができますAnotherException:public std :: exception {};どのような例外がPythonコードからスローされるのか、どのタイプのコードが両方のタイプの例外を処理するために追加されるのかをどのように区別するのですか? Thxxxxを事前に入力する – Gunjan49

+0

@ Gunjan49 - 複数のタイプの例外を処理する方法を示すサンプルを更新しました。私はこれが最も簡単な方法だと思っています。それはSWIGタイプのシステムを使って、それがどんなタイプなのか理解しています。多相型の階層構造を持っているなら、ここでそれを利用できます。呼び出し元は、例外がどこから来たのかを区別することはできません。 (あなたがどこから来たのか分かりたければ、間違っていることを示唆していますが、本当にしたいと思ったら原点を示す 'director:except'コードから例外のフラグを立てることができますそれを行う) – Flexo