2011-11-10 2 views
3

Je développe une application client-serveur dans laquelle le client appelle l'API d'un serveur qui fournit une interface Python pour l'entrée de l'utilisateur. Cela signifie que l'interface client et l'interface du serveur sont écrites en Python alors que le code du socket est en C++.Attraper une exception Python en C++

Du côté du serveur: -

J'ai une classe, Test, en C++ et cette classe est héritée en Python nommé TestPython en utilisant la fonction de directeur SWIG. J'ai aussi une exception MyException en C++.

Maintenant, une fonction de la classe TestPython lance MyException() à partir du code Python.

Je veux gérer l'exception levée à partir de Python dans le code C++ en utilisant SWIG.

extrait de code ci-dessous:

C++ Code-

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

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

Python Code -

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 

Maintenant, si la fonction TestException() est appelée, elle devrait jeter MyException. Je veux gérer cette exception MyException() dans mon code C++.

Donc, quelqu'un peut-il suggérer ma façon de faire cela, je veux dire que dois-je écrire dans mon fichier * .i (interface) pour gérer cela.

Le TestException() écrit en Python ci-dessus est appelé par le client, donc je dois informer le client si une exception est levée par le serveur.

+0

Avez-vous déjà regardé la documentation SWIG sur ce sujet? (http://www.swig.org/Doc2.0/SWIGDocumentation.html#Customization_exception) – gecco

+0

Vous pourriez vouloir rendre un peu plus évident que vous utilisez la fonction de directeur de SWIG - je l'ai manqué la première fois que j'ai lu ceci question, et il n'y a rien à suggérer du tout dans le code que vous avez montré. – Flexo

+0

@gecco - cette documentation ne s'applique pas aux exceptions lancées par le code SWIG Python des directeurs (c'est-à-dire 'director: except') de façon très détaillée. – Flexo

Répondre

3

Pour ce faire, vous devez écrire un %feature("director:except") capable de gérer une exception Python et de le relancer en C++. Voici un petit exemple complet:

Supposons que nous ayons le fichier d'en-tête suivant, nous souhaitons conclure:

#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(); } 

Et ce code Python qui l'utilise:

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) 

Nous pouvons définir les éléments suivants Fichier d'interface 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" 

Qui gère une erreur d'un appel de o voir si c'était l'une de nos MyException instances et puis relance le pointeur si c'était le cas. Si vous avez plusieurs types d'exceptions lancées, vous devrez probablement utiliser PyErr_ExceptionMatches pour déterminer quel type il est en premier.

On pourrait aussi jeter en valeur ou en référence à l'aide:

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

à la place, mais notez que si vous jetiez une sous-classe de MyException en Python ce échoueraient la object slicing problem.Je ne suis pas tout à fait sûr si le code est 100% correct - en particulier je pense que le comptage de référence est correct, mais je pourrais me tromper.

Note: Afin de faire fonctionner cet exemple (%pythonabc ne fonctionnerait pas autrement) J'ai dû appeler SWIG avec -py3. Cela signifiait que je devais passer à SWIG 2.0, parce que ma copie installée de Python 3.2 avait supprimé certaines fonctions obsolètes de l'API C que SWIG 1.3.40 appelait.

+0

pouvez-vous montrer comment je peux gérer l'exception si j'ai une autre classe d'exception nommée class AnotherException: public std :: exception {}; Comment distinguer quelle exception est levée du code python et quelle partie du code sera ajoutée pour gérer les deux types d'exception. Thanxx à l'avance – Gunjan49

+0

@ Gunjan49 - J'ai mis à jour l'exemple pour montrer comment vous pourriez gérer plusieurs types d'exceptions. Je pense que c'est le moyen le plus simple, il utilise le système de type SWIG pour comprendre de quel type il s'agissait. Si vous avez une hiérarchie de type polymorphique, vous pouvez l'exploiter ici. L'appelant ne peut pas savoir d'où vient l'exception - c'est une bonne chose à ce sujet. (Si vous voulez savoir d'où cela vient, cela suggère que vous faites quelque chose de mal, mais vous * pouvez * mettre un drapeau sur l'exception du code 'director: except' pour indiquer l'origine si vous voulez vraiment fais le) – Flexo

Questions connexes