| /* This is a rather sophisticated example that illustrates exception handling, | |
| templates, and proxy classes. | |
| (i) The %exception directive is used to attach exception handlers | |
| to specific methods. | |
| (ii) Exception classes are automatically converted to proxy class | |
| objects. | |
| (iii) The %template directive is used to expand the templates | |
| */ | |
| %module example | |
| %{ | |
| #include "example.h" | |
| %} | |
| /* Define some exception handlers for specific methods. In | |
| the header file, the enqueue method throws FullError and | |
| the dequeue method throws EmptyError. Since we don't | |
| want to define an exception handler for everything, we | |
| simply write a handler for each method individually. | |
| Note: the *::enqueue syntax means that we simply define | |
| the handler for any class with this method defined. | |
| */ | |
| %exception *::enqueue { | |
| try { | |
| $action | |
| } catch(FullError& e) { | |
| FullError *ecopy = new FullError(e); | |
| PyObject *err = SWIG_NewPointerObj(ecopy, SWIGTYPE_p_FullError, 1); | |
| PyErr_SetObject(SWIG_Python_ExceptionType(SWIGTYPE_p_FullError), err); | |
| SWIG_fail; | |
| } | |
| } | |
| /* Some notes about the code above: | |
| (0) $action gets replaced with the actual method call. | |
| (1) We are going to return a copy of the exception object (FullError) | |
| to pass back to the Python interpreter. This is why the copy | |
| constructor is being called. | |
| (2) The SWIG_NewPointerObj() call automatically wraps the exception object | |
| into a proxy class. The SWIGTYPE_p_FullError is the type-descriptor | |
| used for type checking. The "1" indicates that Python will have | |
| ownership of the resulting object. | |
| (3) The PyErr_SetObject call sets the Python exception. However, | |
| the SWIGTYPE_p_FullError->clientdata reference may not be | |
| obvious. This is actually the Python proxy class object | |
| for FullError. Recall that in Python, exceptions are defined | |
| as classes. Therefore, this works perfectly as the argument to | |
| PyErr_SetObject()! A neat trick perhaps. | |
| */ | |
| /* | |
| Python classes that are used as exceptions need to be subclasses of the | |
| "Exception" class, and so SWIG needs to know which wrapped classes may be | |
| used in this way. You can explicitly tell SWIG this by using | |
| %exceptionclass. SWIG will implicitly set this feature for classes which | |
| appear in a throw declaration, but it's not a problem to explicitly | |
| mark such classes as well. | |
| This is a Python requirement - if you fail to mark such classes with | |
| %exceptionclass you may see 'interesting' behaviour on the Python side. | |
| */ | |
| %exceptionclass EmptyError; | |
| %exceptionclass FullError; | |
| %exception *::dequeue { | |
| try { | |
| $action | |
| } catch(EmptyError& e) { | |
| EmptyError *ecopy = new EmptyError(e); | |
| PyObject *err = SWIG_NewPointerObj(ecopy, SWIGTYPE_p_EmptyError, 1); | |
| PyErr_SetObject(SWIG_Python_ExceptionType(SWIGTYPE_p_EmptyError), err); | |
| SWIG_fail; | |
| } | |
| } | |
| /* Grab the original header file */ | |
| %include "example.h" | |
| /* Instantiate a few templates */ | |
| %template(intQueue) Queue<int>; | |
| %template(doubleQueue) Queue<double>; | |
| %inline %{ | |
| // The -builtin SWIG option results in SWIGPYTHON_BUILTIN being defined | |
| #ifdef SWIGPYTHON_BUILTIN | |
| bool is_python_builtin() { return true; } | |
| #else | |
| bool is_python_builtin() { return false; } | |
| #endif | |
| %} | |