diff options
Diffstat (limited to 'Examples/python/exceptproxy')
-rw-r--r-- | Examples/python/exceptproxy/Makefile | 22 | ||||
-rw-r--r-- | Examples/python/exceptproxy/example.h | 54 | ||||
-rw-r--r-- | Examples/python/exceptproxy/example.i | 114 | ||||
-rw-r--r-- | Examples/python/exceptproxy/runme.py | 45 |
4 files changed, 235 insertions, 0 deletions
diff --git a/Examples/python/exceptproxy/Makefile b/Examples/python/exceptproxy/Makefile new file mode 100644 index 0000000..ba5c798 --- /dev/null +++ b/Examples/python/exceptproxy/Makefile @@ -0,0 +1,22 @@ +TOP = ../.. +SWIG = $(TOP)/../preinst-swig +CXXSRCS = +TARGET = example +INTERFACE = example.i +LIBS = -lm +SWIGOPT = + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' python_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + SWIGOPT='$(SWIGOPT)' TARGET='mypython' INTERFACE='$(INTERFACE)' python_cpp_static + +clean:: + $(MAKE) -f $(TOP)/Makefile python_clean + rm -f $(TARGET).py + +check: all + $(MAKE) -f $(TOP)/Makefile python_run diff --git a/Examples/python/exceptproxy/example.h b/Examples/python/exceptproxy/example.h new file mode 100644 index 0000000..ec7107a --- /dev/null +++ b/Examples/python/exceptproxy/example.h @@ -0,0 +1,54 @@ +/* File : example.h */ + +// A simple exception +class EmptyError { }; +class FullError { + public: + int maxsize; + FullError(int m) : maxsize(m) { } +}; + +#if defined(_MSC_VER) + #pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) +#endif + +template<typename T> class Queue { + int maxsize; + T *items; + int nitems; + int last; + public: + Queue(int size) { + maxsize = size; + items = new T[size]; + nitems = 0; + last = 0; + } + ~Queue() { + delete [] items; + } + void enqueue(T x) throw(FullError) { + if (nitems == maxsize) { + throw FullError(maxsize); + } + items[last] = x; + last = (last + 1) % maxsize; + nitems++; + } + T dequeue() { + T x; + if (nitems == 0) throw EmptyError(); + x = items[(last + maxsize - nitems) % maxsize]; + nitems--; + return x; + } + int length() { + return nitems; + } +}; + + +#if defined(_MSC_VER) + #pragma warning(default: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) +#endif + diff --git a/Examples/python/exceptproxy/example.i b/Examples/python/exceptproxy/example.i new file mode 100644 index 0000000..4a1e0ba --- /dev/null +++ b/Examples/python/exceptproxy/example.i @@ -0,0 +1,114 @@ +/* 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 each method individually. + + Note: the *::enqueue syntax means that we simply define + the handler for any class with this method defined. +*/ + +/* + First we need to 'disable' the default swig throw mechanism for the + FullError class. We do this by rethrowing the exception. + + Note that this is necessary since the class appears in a throw + declaration: + + + void enqueue(T x) throw(FullError); + + hence, swig recognizes it as an exception class and it will generate + the necessary code to catch it and rethrow it to the python side. + +*/ +%typemap(throws) FullError "(void)$1; throw;"; + + +%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. +*/ + +/* + Now, the EmpytError doesn't appear in a throw declaration, and hence + we need to 'mark' it as an exception class. In python, classes that + are used as exception are 'special', and need to be wrapped as + 'classic' ones. + + This is a python issue, and if you don't mark the class, you will + see 'interesting' behaviours at 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>; + + + + + diff --git a/Examples/python/exceptproxy/runme.py b/Examples/python/exceptproxy/runme.py new file mode 100644 index 0000000..a2ae555 --- /dev/null +++ b/Examples/python/exceptproxy/runme.py @@ -0,0 +1,45 @@ +# file: runme.py +import example + +q = example.intQueue(10) + +print "Inserting items into intQueue" + +try: + for i in range(0,100): + q.enqueue(i) +except example.FullError,e: + print "Maxsize is", e.maxsize + +print "Removing items" + +try: + while 1: + q.dequeue() +except example.EmptyError,e: + pass + + +q = example.doubleQueue(1000) + +print "Inserting items into doubleQueue" + +try: + for i in range(0,10000): + q.enqueue(i*1.5) +except example.FullError,e: + print "Maxsize is", e.maxsize + +print "Removing items" + +try: + while 1: + q.dequeue() +except example.EmptyError,e: + pass + + + + + + |