Dynamically rethrowing self-defined C++ exceptions as Python exceptions using SWIG
It looks like someone has answered your basic question over on the swig-user list...
%exception { try { $action } catch (MyException &_e) { SWIG_Python_Raise(SWIG_NewPointerObj( (new MyException(static_cast<const MyException& >(_e))), SWIGTYPE_p_MyException,SWIG_POINTER_OWN), "MyException", SWIGTYPE_p_MyException); SWIG_fail; } }
This does assume you have generated wrappers for your exception classes, I believe.
Example for your hierarchy
std::exception -> API::Exception -> API::NetworkException -> API::TimeoutException -> API::UnreachableException -> API::InvalidAddressException
example.i:
%module example%include "stl.i"%include "exception.i"%{#define SWIG_FILE_WITH_INIT#include "example.cpp"%}%{#define CATCH_PE(Namespace,Exception) \ catch(const Namespace::Exception &e) \ { \ SWIG_Python_Raise(SWIG_NewPointerObj(new Namespace::Exception(e), \ SWIGTYPE_p_##Namespace##__##Exception,SWIG_POINTER_OWN), \ #Exception, SWIGTYPE_p_##Namespace##__##Exception); \ SWIG_fail; \ } \/**/// should be in "derived first" order#define FOR_EACH_EXCEPTION(ACTION) \ ACTION(API,UnreachableException) \ ACTION(API,TimeoutException) \ ACTION(API,InvalidAddressException) \ ACTION(API,NetworkException) \ ACTION(API,Exception) \/**/// In order to remove macros, need traits:// http://swig.10945.n7.nabble.com/traits-based-access-to-swig-type-info-td12315.html%}%exception { try { $action } FOR_EACH_EXCEPTION(CATCH_PE) catch (const std::exception & e) { SWIG_exception(SWIG_RuntimeError, (std::string("C++ std::exception: ") + e.what()).c_str()); } catch (...) { SWIG_exception(SWIG_UnknownError, "C++ anonymous exception"); }}%include "example.cpp"
example.cpp:
#include <exception>#include <stdexcept>namespace API{ struct Exception: std::exception { virtual const char* what() const throw() { return "It is API::Exception"; } }; struct NetworkException: Exception { virtual const char* what() const throw() { return "It is API::NetworkException"; } }; struct TimeoutException: NetworkException { virtual const char* what() const throw() { return "It is API::TimeoutException"; } }; struct UnreachableException: NetworkException { virtual const char* what() const throw() { return "It is API::UnreachableException"; } }; struct InvalidAddressException: Exception { virtual const char* what() const throw() { return "It is API::InvalidAddressException"; } }; inline void select(int i) { switch(i) { case 0: throw Exception(); case 1: throw NetworkException(); case 2: throw TimeoutException(); case 3: throw UnreachableException(); case 4: throw InvalidAddressException(); default: throw std::runtime_error("It is std::runtime_error"); } }}
Build:
swig -c++ -python example.i &&g++ -fPIC -shared -lpython2.7 example.cpp example_wrap.cxx -I/usr/include/python2.7 -o _example.so
test.py:
#!/usr/bin/env python2.7from exceptions import BaseExceptionfrom example import *def catch(i): try: select(i) except UnreachableException as e: print "Caught UnreachableException" print e.what() print e except TimeoutException as e: print "Caught TimeoutException" print e.what() print e except InvalidAddressException as e: print "Caught InvalidAddressException" print e.what() print e except NetworkException as e: print "Caught NetworkException" print e.what() print e except Exception as e: print "Caught Exception" print e.what() print e except BaseException as e: print "Caught BaseException" print str(e) print "_"*16for i in xrange(6): catch(i)
Output is:
Caught ExceptionIt is API::Exception<example.Exception; proxy of <Swig Object of type 'API::Exception *' at 0x7f9f54a02120> >________________Caught NetworkExceptionIt is API::NetworkException<example.NetworkException; proxy of <Swig Object of type 'API::NetworkException *' at 0x7f9f54a02120> >________________Caught TimeoutExceptionIt is API::TimeoutException<example.TimeoutException; proxy of <Swig Object of type 'API::TimeoutException *' at 0x7f9f54a02120> >________________Caught UnreachableExceptionIt is API::UnreachableException<example.UnreachableException; proxy of <Swig Object of type 'API::UnreachableException *' at 0x7f9f54a02120> >________________Caught InvalidAddressExceptionIt is API::InvalidAddressException<example.InvalidAddressException; proxy of <Swig Object of type 'API::InvalidAddressException *' at 0x7f9f54a02120> >________________Caught BaseExceptionC++ std::exception: It is std::runtime_error________________
Based on answer in maillist.