Dynamically rethrowing self-defined C++ exceptions as Python exceptions using SWIG Dynamically rethrowing self-defined C++ exceptions as Python exceptions using SWIG python python

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.