[Insight-developers] RFC: PATCH for exception handling in vtkWrapPython.c

Charl P. Botha c.p.botha at ewi.tudelft.nl
Mon, 1 Mar 2004 15:02:23 +0100


--tKW2IUtsqtDRztdT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Dear developers,

Something which has become acutely obvious especially with ITK/VTK
integration in Python is the fact that the Python VTK wrappings do not
handle exceptions.  For example, if I make the following pipeline in Python:

VTK reader -> ConnectVTKITK -> ITK processing -> ConnectITKVTK -> VTK
visualisation (see Insight/Examples/Visualization/Canny*.py for a more
concrete example)

and I call Update() on the last VTK object in the pipeline, and any of the
ITK objects flag an error (ITK does this by throwing an exception), my whole
application is unceremoniously dumped to the command-line with no error
message whatsoever.  That's just rude. :)

This happens because there is no exception handling in the VTK Python
wrappings.

In the light of this, I have modified vtkWrapPython() with try...catch
blocks around ALL wrapped code method invocations.  Any exception of class
std::exception is caught and passed through to Python as a RuntimeError.
Anything else is rethrown.  This means that if *any* C++ code throws an
exception-derived exception and this code was executed as a result of a
wrapped VTK Python call, Python will see the exception and the program won't
be unceremoniously dumped.

Please check and comment on the attached patch.  My only remaning problem is
the "#include <exception>" I had to add to all Python wrapped code.  If
anyone could give any advice about the portability of the <exception>
include on all platforms that VTK builds on, I would be grateful.

I would like to apply this patch at some stage.  It could obviously also be
made conditional.

Thanks,
Charl

-- 
charl p. botha http://cpbotha.net/ http://visualisation.tudelft.nl/

--tKW2IUtsqtDRztdT
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="vtkWrapPython-exceptions.diff"

Index: vtkWrapPython.c
===================================================================
RCS file: /vtk/cvsroot/VTK/Wrapping/vtkWrapPython.c,v
retrieving revision 1.69
diff -u -r1.69 vtkWrapPython.c
--- vtkWrapPython.c	17 Feb 2004 15:31:24 -0000	1.69
+++ vtkWrapPython.c	1 Mar 2004 13:07:14 -0000
 at  at  -735,17 +735,20  at  at 
               fprintf(fp,"    else {\n");
               sprintf(methodname,"op->%s",currentFunction->Name);
               }
-                
+
+            /* start of try around method invocation */
+            fprintf(fp, "     try {\n");
+            
             switch (currentFunction->ReturnType%1000)
               {
               case 2:
-                fprintf(fp,"      %s(",methodname);
+                fprintf(fp,"        %s(",methodname);
                 break;
               case 109:
-                fprintf(fp,"      temp%i = &%s(",MAX_ARGS,methodname);
+                fprintf(fp,"        temp%i = &%s(",MAX_ARGS,methodname);
                 break;
               default:
-                fprintf(fp,"      temp%i = %s(",MAX_ARGS,methodname);
+                fprintf(fp,"        temp%i = %s(",MAX_ARGS,methodname);
               }
 
             for (i = 0; i < currentFunction->NumberOfArguments; i++)
 at  at  -769,6 +772,16  at  at 
                 }
               }
             fprintf(fp,");\n");
+
+            /* catch clause for any possible exceptions */
+            fprintf(fp, "     }\n");
+            fprintf(fp, "     catch (std::exception &_e) {\n");
+            fprintf(fp, "       PyErr_SetString(PyExc_RuntimeError, _e.what());\n");
+            fprintf(fp, "       return NULL;\n");
+            fprintf(fp, "     }\n");
+            fprintf(fp, "     catch (...) {\n");
+            fprintf(fp, "       throw;\n");
+            fprintf(fp, "     }\n");
           
             if (currentFunction->NumberOfArguments == 1 
                 && currentFunction->ArgTypes[0] == 5000)
 at  at  -1037,6 +1050,7  at  at 
   #if defined(__APPLE__)
   fprintf(fp,"#include \"vtkPythonUtil.h\"\n");
   #endif
+  fprintf(fp,"#include <exception>\n");
 
   fprintf(fp,"#if defined(WIN32)\n");
   fprintf(fp,"extern \"C\" { __declspec( dllexport ) PyObject *PyVTKClass_%sNew(char *); }\n",

--tKW2IUtsqtDRztdT--