[vtk-developers] Modification to vtkPythonUtil to support passing of void *callData

Charl P. Botha c.p.botha at its.tudelft.nl
Fri Mar 14 12:29:48 EST 2003


Dear developers and especially David and Prabhu,

As you know, the Python wrapping does not pass the void *callData of the
vtkPythonCommand->Execute() through to Python for very obvious reasons: it's
very difficult to determine the type of this parameter at run-time.

This means that no Python observer can query the callData parameter, so, for
example, a Python program can not determine the error message when catching
an ErrorEvent.  

I've made changes to vtkPythonUtil.{cxx,h} that attempt to remedy this
situation, but are entirely backwards compatible.  I'll illustrate with an
example:

### this is the traditional way and still works...
def handlerOne(theObject, eventname):
   # durn, we don't know what the error was!
   print eventname
   
someVtkObject.AddObserver('ErrorEvent', handlerOne)

### this is the new way:
def handlerOne(theObject, eventname, errorMessage):
   # if my code can't convert callData to a string, errorMessage will
   # be None
   print errorMessage
   
# we KNOW that an ErrorEvent passes a null-terminated string
handlerOne.callDataType = "string0"

someVtkObject.AddObserver('ErrorEvent', handlerOne)

### END EXAMPLE

At the moment, I've only implemented the "string0" type, but others can be
easily added within my framework.  I would very much like to commit this
patch, as I desperately need the functionality, but will obviously only do
this with the approval of the VTK Python Pantheon.  I've attached the patch
for your review.

Thanks,
Charl

-- 
charl p. botha http://cpbotha.net/ http://visualisation.tudelft.nl/
-------------- next part --------------
Index: vtkPythonUtil.cxx
===================================================================
RCS file: /vtk/cvsroot/VTK/Common/vtkPythonUtil.cxx,v
retrieving revision 1.56
diff -u -r1.56 vtkPythonUtil.cxx
--- vtkPythonUtil.cxx	12 Mar 2003 14:35:29 -0000	1.56
+++ vtkPythonUtil.cxx	14 Mar 2003 16:19:55 -0000
@@ -1735,8 +1735,8 @@
   this->obj = o; 
 }
 
-void vtkPythonCommand::Execute(vtkObject *ptr, unsigned long eventtype, 
-                               void *)
+void vtkPythonCommand::Execute(vtkObject *ptr, unsigned long eventtype,
+                               void *callData)
 {
   PyObject *arglist, *result, *obj2;
   const char *eventname;
@@ -1753,7 +1753,66 @@
 
   eventname = this->GetStringFromEventId(eventtype);
   
-  arglist = Py_BuildValue("(Ns)",obj2,eventname);
+  // extension by Charl P. Botha so that callData is available from Python:
+  // * callData used to be ignored completely: this is not entirely desirable,
+  //   e.g. with catching ErrorEvent
+  // * I have extended this code so that callData can be caught whilst not
+  //   affecting any existing VTK Python code
+  // * make sure your observer python function has a callDataType string
+  //   attribute that describes how callData should be passed through, e.g.:
+  //   def handler(theObject, eventType, message):
+  //      print "Error: %s" % (message)
+  //   # we know that ErrorEvent passes a null-terminated string
+  //   handler.callDataType = "string0" 
+  //   someObject.AddObserver('ErrorEvent', handler)
+  //                                    
+  PyObject *callDataTypeObj = PyObject_GetAttrString(this->obj, "callDataType");
+  char *callDataTypeString = NULL;
+  if (callDataTypeObj)
+    {
+    callDataTypeString = PyString_AsString(callDataTypeObj);
+    if (callDataTypeString)
+        {
+        if (strcmp(callDataTypeString, "string0") == 0)
+            {
+            // this means the user wants the callData cast as a string
+            PyObject* callDataAsString = PyString_FromString((char*)callData);
+            if (callDataAsString)
+                {
+                arglist = Py_BuildValue("(NsN)", obj2, eventname, callDataAsString);
+                }
+            else
+                {
+                PyErr_Clear();
+                // we couldn't create a string, so we pass in None
+                Py_INCREF(Py_None);
+                arglist = Py_BuildValue("(NsN)", obj2, eventname, Py_None);
+                }
+            }
+        else
+            {
+            // we don't handle this, so we pass in a None as the third parameter
+            Py_INCREF(Py_None);
+            arglist = Py_BuildValue("(NsN)", obj2, eventname, Py_None);
+            }
+        }
+    else
+        {
+        // the handler object has a callDataType attribute, but it's not a
+        // string -- then we do traditional arguments
+        arglist = Py_BuildValue("(Ns)",obj2,eventname);
+        }
+        
+    // we have to do this
+    Py_DECREF(callDataTypeObj);
+    }
+  else
+    {
+    // this means there was no callDataType attribute, so we do the
+    // traditional obj(object, eventname) call
+    PyErr_Clear();
+    arglist = Py_BuildValue("(Ns)",obj2,eventname);
+    }
   
   result = PyEval_CallObject(this->obj, arglist);
   Py_DECREF(arglist);
Index: vtkPythonUtil.h
===================================================================
RCS file: /vtk/cvsroot/VTK/Common/vtkPythonUtil.h,v
retrieving revision 1.28
diff -u -r1.28 vtkPythonUtil.h
--- vtkPythonUtil.h	16 Jul 2002 21:17:33 -0000	1.28
+++ vtkPythonUtil.h	14 Mar 2003 16:19:56 -0000
@@ -164,7 +164,7 @@
   static vtkPythonCommand *New() { return new vtkPythonCommand; };
 
   void SetObject(PyObject *o);
-  void Execute(vtkObject *ptr, unsigned long eventtype, void *);
+  void Execute(vtkObject *ptr, unsigned long eventtype, void *callData);
  
   PyObject *obj;
 protected:


More information about the vtk-developers mailing list