[Insight-users] [PATCH] Getting itk::exceptions through to Python

Charl P. Botha c . p . botha at ewi . tudelft . nl
Sun, 20 Jul 2003 23:42:47 +0200


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

Dear lists,

As I've mentioned previously, ITK error handling is done by throwing
exceptions and this is causing trouble in the CableSwig wrappings.  At the
moment, the CableSwig wrapping code does not catch these exceptions, meaning
that when the wrapped ITK code throws an exception, the whole calling
process is terminated.  For example:

cpbotha at dutidad:/tmp$ python cannyEdgeDetectionImageFilter.py 
Aborted

We have no clue what went wrong or where it went wrong.  In a larger Python
application, this is quite debilitating.  Due to this, I've made some
changes to the CableSwig.cxx wrapping code so that itk exceptions are
handled and the exceptions are propagated through to Python.  Note the
difference:

cpbotha at crabtree:/tmp$ python cannyEdgeDetectionImageFilter.py 
Traceback (most recent call last):
  File "cannyEdgeDetectionImageFilter.py", line 16, in ?
      writer.Update()
        File "/data1/home/cpbotha/build/Insight/bin/itkImageFileWriter.py",
line 166, in Update
    def Update(*args): return
apply(_itkImageFileWriter.itkImageFileWriterUS2_Pointer_Update,args)
RuntimeError: ITK Exception at
/data1/home/cpbotha/build/Insight/Code/IO/itkImageFileReader.txx:101:  Could
not create IO object for file
c:/Hoffman/InsightNew/Testing/Data/Input/cthead1.png

Now we finally see that it was actually just a "file not found" error.  Of
course, these exceptions can easily be caught and handled in Python.

I would be very glad if someone could check and hopefully apply my patch.
As I don't know Cable and CableSwig that well, a sanity check would be much
appreciated.  The patch is attached.

Thanks,
Charl

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

--Kj7319i9nmIyA2yE
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="CableSwig-PythonExceptions-v1.diff"

Index: Executables/CableSwig.cxx
===================================================================
RCS file: /cvsroot/CableSwig/CableSwig/Executables/CableSwig.cxx,v
retrieving revision 1.6
diff -u -r1.6 CableSwig.cxx
--- Executables/CableSwig.cxx	28 May 2003 21:55:34 -0000	1.6
+++ Executables/CableSwig.cxx	20 Jul 2003 19:51:22 -0000
@@ -314,6 +314,42 @@
     {
     Setattr(m, "access", access);
     }
+
+  // The following clause will instruct SWIG to let ITK C++ exceptions
+  // propagate through as Python exceptions.  Suggestions and improvements
+  // are welcome. -- Charl P. Botha <cpbotha [AT] ieee.org>
+  if (m_WrapLanguage == "python")
+  {
+     if (strncmp(mth->GetQualifiedName().c_str(), "itk::", 5) == 0)
+     {
+        // attaching this node as "throws" attribute to the method object
+        // will cause the swig emit code to add an exception handler
+        // the node only has to have a type-attribute with the type of the
+        // object that will be thrown
+        Node *catchNode = NewHash();
+        Setattr(catchNode, "type", "itk::ExceptionObject");
+        Setattr(m, "throws", catchNode);
+
+        // this has to be added to the swig typemap... when hitting a
+        // method with a "throws" attribute, it will look up the "type"
+        // attribute of that "throws" attribute, once again look up the
+        // "throws" of that result, and use the "code" attribute of the
+        // final result as
+        // handler (catch) code - we should only have to do this registration
+        // once, but for now it's much clearer here and it does no real harm
+        // being called multiple times
+        char *code = 
+           "char emsg[512];\n" 
+           "snprintf(emsg, 511, \"ITK Exception at %s:%d: %s\", "
+           "_e.GetFile(), _e.GetLine(), _e.GetDescription());\n"
+           "PyErr_SetString(PyExc_RuntimeError, emsg); SWIG_fail;\n";
+        Swig_typemap_register("throws", catchNode, code,
+                              NULL, NULL);
+
+        // take care of the memory
+        Delete(catchNode);
+     }
+  }
   
   ParmList* parms = 0;
   Parm* pp = 0;

--Kj7319i9nmIyA2yE--