Commit 04633829 authored by David Gobbi's avatar David Gobbi Committed by Marcus D. Hanwell
Browse files

ENH: Add wrapping of non-vtk objects to the python wrappers

parent 399a6fed
......@@ -68,6 +68,38 @@
//#define VTKPYTHONDEBUG
//--------------------------------------------------------------------
// special struct for the SpecialType hash
static PyObject *vtkBuildDocString(char *docstring[]);
class PyVTKSpecialTypeInfo
{
public:
PyVTKSpecialTypeInfo() :
classname(0), docstring(0), methods(0),
copy_func(0), delete_func(0), print_func(0) {};
PyVTKSpecialTypeInfo(
char *cname, char *cdocstring[], PyMethodDef *cmethods,
PyVTKSpecialCopyFunc copyfunc, PyVTKSpecialDeleteFunc deletefunc,
PyVTKSpecialPrintFunc printfunc) {
this->classname = PyString_FromString(cname);
this->docstring = vtkBuildDocString(cdocstring);
this->methods = cmethods;
this->copy_func = copyfunc;
this->delete_func = deletefunc;
this->print_func = printfunc; };
PyObject *classname;
PyObject *docstring;
PyMethodDef *methods;
PyVTKSpecialCopyFunc copy_func;
PyVTKSpecialDeleteFunc delete_func;
PyVTKSpecialPrintFunc print_func;
};
//--------------------------------------------------------------------
// There are two hash tables associated with the Python wrappers
......@@ -79,6 +111,7 @@ public:
vtkstd::map<vtkSmartPointerBase, PyObject*> *ObjectHash;
vtkstd::map<vtkstd::string, PyObject*> *ClassHash;
vtkstd::map<vtkstd::string, PyVTKSpecialTypeInfo> *SpecialTypeHash;
};
//--------------------------------------------------------------------
......@@ -89,6 +122,8 @@ vtkPythonUtil::vtkPythonUtil()
{
this->ObjectHash = new vtkstd::map<vtkSmartPointerBase, PyObject*>;
this->ClassHash = new vtkstd::map<vtkstd::string, PyObject*>;;
this->SpecialTypeHash =
new vtkstd::map<vtkstd::string, PyVTKSpecialTypeInfo>;
}
//--------------------------------------------------------------------
......@@ -96,6 +131,7 @@ vtkPythonUtil::~vtkPythonUtil()
{
delete this->ObjectHash;
delete this->ClassHash;
delete this->SpecialTypeHash;
}
//--------------------------------------------------------------------
......@@ -1168,8 +1204,10 @@ static PyObject *PyVTKClass_NewSubclass(PyObject *, PyObject *args,
//--------------------------------------------------------------------
static PyObject *PyVTKSpecialObject_PyString(PyVTKSpecialObject *self)
{
Py_INCREF(self->vtk_name);
return self->vtk_name;
vtksys_ios::ostringstream os;
self->vtk_info->print_func(os, self->vtk_ptr);
const vtksys_stl::string &s = os.str();
return PyString_FromStringAndSize(s.data(), s.size());
}
//--------------------------------------------------------------------
......@@ -1177,7 +1215,7 @@ static PyObject *PyVTKSpecialObject_PyRepr(PyVTKSpecialObject *self)
{
char buf[255];
sprintf(buf,"<%s %s at %p>", self->ob_type->tp_name,
PyString_AsString(self->vtk_name), self);
PyString_AsString(self->vtk_info->classname), self);
return PyString_FromString(buf);
}
......@@ -1192,17 +1230,17 @@ static PyObject *PyVTKSpecialObject_PyGetAttr(PyVTKSpecialObject *self,
{
if (strcmp(name,"__name__") == 0)
{
Py_INCREF(self->vtk_name);
return self->vtk_name;
Py_INCREF(self->vtk_info->classname);
return self->vtk_info->classname;
}
if (strcmp(name,"__doc__") == 0)
{
Py_INCREF(self->vtk_doc);
return self->vtk_doc;
Py_INCREF(self->vtk_info->docstring);
return self->vtk_info->docstring;
}
if (strcmp(name,"__methods__") == 0)
{
meth = self->vtk_methods;
meth = self->vtk_info->methods;
PyObject *lst;
int i, n;
......@@ -1213,7 +1251,7 @@ static PyObject *PyVTKSpecialObject_PyGetAttr(PyVTKSpecialObject *self,
if ((lst = PyList_New(n)) != NULL)
{
meth = self->vtk_methods;
meth = self->vtk_info->methods;
for (i = 0; i < n; i++)
{
PyList_SetItem(lst, i, PyString_FromString(meth[i].ml_name));
......@@ -1237,7 +1275,7 @@ static PyObject *PyVTKSpecialObject_PyGetAttr(PyVTKSpecialObject *self,
}
}
for (meth = self->vtk_methods; meth && meth->ml_name; meth++)
for (meth = self->vtk_info->methods; meth && meth->ml_name; meth++)
{
if (name[0] == meth->ml_name[0] && strcmp(name+1, meth->ml_name+1) == 0)
{
......@@ -1252,9 +1290,11 @@ static PyObject *PyVTKSpecialObject_PyGetAttr(PyVTKSpecialObject *self,
//--------------------------------------------------------------------
static void PyVTKSpecialObject_PyDelete(PyVTKSpecialObject *self)
{
if (self->vtk_ptr)
{
self->vtk_info->delete_func(self->vtk_ptr);
}
self->vtk_ptr = NULL;
Py_XDECREF(self->vtk_name);
Py_XDECREF(self->vtk_doc);
#if (PY_MAJOR_VERSION >= 2)
PyObject_Del(self);
#else
......@@ -1298,8 +1338,7 @@ int PyVTKSpecialObject_Check(PyObject *obj)
return (obj->ob_type == &PyVTKSpecialObjectType);
}
PyObject *PyVTKSpecialObject_New(void *ptr, PyMethodDef *methods,
char *classname, char *docstring[])
PyObject *PyVTKSpecialObject_New(char *classname, void *ptr, int copy)
{
#if (PY_MAJOR_VERSION >= 2)
PyVTKSpecialObject *self = PyObject_New(PyVTKSpecialObject,
......@@ -1308,11 +1347,35 @@ PyObject *PyVTKSpecialObject_New(void *ptr, PyMethodDef *methods,
PyVTKSpecialObject *self = PyObject_NEW(PyVTKSpecialObject,
&PyVTKSpecialObjectType);
#endif
PyVTKSpecialTypeInfo *info = 0;
if (vtkPythonHash)
{
vtkstd::map<vtkstd::string, PyVTKSpecialTypeInfo>::iterator it =
vtkPythonHash->SpecialTypeHash->find(classname);
if(it != vtkPythonHash->SpecialTypeHash->end())
{
info = &it->second;
}
}
if (info == 0)
{
char buf[256];
sprintf(buf,"cannot create object of unknown type \"%s\"",classname);
PyErr_SetString(PyExc_ValueError,buf);
return NULL;
}
if (copy)
{
ptr = info->copy_func(ptr);
}
self->vtk_ptr = ptr;
self->vtk_methods = methods;
self->vtk_name = PyString_FromString(classname);
self->vtk_doc = vtkBuildDocString(docstring);
self->vtk_info = info;
return (PyObject *)self;
}
......@@ -1360,6 +1423,42 @@ vtkObjectBase *PyArg_VTKParseTuple(PyObject *pself, PyObject *args,
return obj;
}
//--------------------------------------------------------------------
void vtkPythonAddSpecialTypeToHash(
char *classname, PyMethodDef *methods, char *docstring[],
PyVTKSpecialCopyFunc copy_func, PyVTKSpecialDeleteFunc delete_func,
PyVTKSpecialPrintFunc print_func)
{
if (vtkPythonHash == NULL)
{
vtkPythonHash = new vtkPythonUtil();
Py_AtExit(vtkPythonHashDelete);
}
#ifdef VTKPYTHONDEBUG
// vtkGenericWarningMacro("Adding an type " << type << " to hash ptr");
#endif
// lets make sure it isn't already there
vtkstd::map<vtkstd::string, PyVTKSpecialTypeInfo>::iterator i =
vtkPythonHash->SpecialTypeHash->find(classname);
if(i != vtkPythonHash->SpecialTypeHash->end())
{
#ifdef VTKPYTHONDEBUG
vtkGenericWarningMacro("Attempt to add type to the hash when already there!!!");
#endif
return;
}
(*vtkPythonHash->SpecialTypeHash)[classname] =
PyVTKSpecialTypeInfo(classname, docstring, methods,
copy_func, delete_func, print_func);
#ifdef VTKPYTHONDEBUG
// vtkGenericWarningMacro("Added type to hash type = " << typeObject);
#endif
}
//--------------------------------------------------------------------
void vtkPythonAddClassToHash(PyObject *vtkclass, const char *classname)
{
......@@ -1638,6 +1737,64 @@ PyObject *vtkPythonGetObjectFromObject(PyObject *arg, const char *type)
return NULL;
}
//--------------------------------------------------------------------
PyObject *vtkPythonGetSpecialObjectFromPointer(void *ptr,
const char *classname)
{
PyObject *obj = NULL;
#ifdef VTKPYTHONDEBUG
vtkGenericWarningMacro("Checking into pointer " << ptr);
#endif
if (ptr)
{
obj = PyVTKSpecialObject_New((char *)(classname), ptr, 1);
}
else
{
Py_INCREF(Py_None);
obj = Py_None;
}
return obj;
}
//--------------------------------------------------------------------
void *vtkPythonGetPointerFromSpecialObject(PyObject *obj,
const char *result_type)
{
// convert Py_None to NULL every time
if (obj == Py_None)
{
return NULL;
}
// check to ensure it is a vtk special object
if (obj->ob_type != &PyVTKSpecialObjectType)
{
return NULL;
}
// check to make sure that it is the right type
const char *object_type =
PyString_AsString(((PyVTKSpecialObject *)obj)->vtk_info->classname);
if (strcmp(object_type, result_type) != 0)
{
char error_string[256];
#ifdef VTKPYTHONDEBUG
vtkGenericWarningMacro("vtk bad argument, type conversion failed.");
#endif
sprintf(error_string,"method requires a %s, a %s was provided.",
result_type, object_type);
PyErr_SetString(PyExc_ValueError,error_string);
return NULL;
}
return ((PyVTKSpecialObject *)obj)->vtk_ptr;
}
//--------------------------------------------------------------------
// mangle a void pointer into a SWIG-style string
char *vtkPythonManglePointer(void *ptr, const char *type)
......
......@@ -63,12 +63,16 @@ typedef struct {
} PyVTKObject;
// This for objects not derived from vtkObjectBase
typedef void *(*PyVTKSpecialCopyFunc)(void *);
typedef void (*PyVTKSpecialDeleteFunc)(void *);
typedef void (*PyVTKSpecialPrintFunc)(ostream& os, void *);
class PyVTKSpecialTypeInfo;
typedef struct {
PyObject_HEAD
void *vtk_ptr;
PyMethodDef *vtk_methods;
PyObject *vtk_name;
PyObject *vtk_doc;
PyVTKSpecialTypeInfo *vtk_info;
} PyVTKSpecialObject;
// Standard methods for all vtk/python objects
......@@ -84,8 +88,7 @@ PyObject *PyVTKClass_New(vtknewfunc constructor, PyMethodDef *methods,
char *classname, char *modulename, char *docstring[],
PyObject *base);
VTK_PYTHON_EXPORT
PyObject *PyVTKSpecialObject_New(void *ptr, PyMethodDef *methods,
char *classname, char *docstring[]);
PyObject *PyVTKSpecialObject_New(char *classname, void *ptr, int copy);
// this is a special version of ParseTuple that handles both bound
// and unbound method calls for VTK objects
......@@ -118,6 +121,24 @@ PyObject *vtkPythonGetObjectFromPointer(vtkObjectBase *ptr);
extern VTK_PYTHON_EXPORT
PyObject *vtkPythonGetObjectFromObject(PyObject *arg, const char *type);
// Add a non-VTK type to the type lookup table, this allows us to later
// create object given only the class name.
extern VTK_PYTHON_EXPORT
void vtkPythonAddSpecialTypeToHash(
char *classname, PyMethodDef *methods, char *docstring[],
PyVTKSpecialCopyFunc copyfunc, PyVTKSpecialDeleteFunc deletefunc,
PyVTKSpecialPrintFunc printfunc);
// Return the pointer to a non-VTK object
extern VTK_PYTHON_EXPORT
void *vtkPythonGetPointerFromSpecialObject(PyObject *obj,
const char *result_type);
// Convert a non-VTK object to a PyVTKSpecialObject
extern VTK_PYTHON_EXPORT
PyObject *vtkPythonGetSpecialObjectFromPointer(void *ptr,
const char *type);
// Add and delete PyVTKObject/vtkObjectBase pairs from the wrapper hash table,
// these methods do not change the reference counts of either the vtkObjectBase
// or the PyVTKObject.
......
......@@ -35,7 +35,7 @@ static void vtkWrapPython_ClassDoc(
/* print out all methods and the method table */
static void vtkWrapPython_GenerateMethods(
FILE *fp, FileInfo *data, int *class_has_new);
FILE *fp, FileInfo *data, int class_has_new, int do_constructors);
/* make a temporary variable for an arg value or a return value */
static void vtkWrapPython_MakeTempVariable(
......@@ -55,7 +55,7 @@ static void vtkWrapPython_ReturnHintedValue(
/* check whether a method is wrappable */
static int vtkWrapPython_MethodCheck(
FileInfo *data, FunctionInfo *currentFunction);
FileInfo *data, FunctionInfo *currentFunction, int contructor);
/* create a format string for PyArg_ParseTuple */
static char *vtkWrapPython_FormatString(
......@@ -260,6 +260,13 @@ static void vtkWrapPython_MakeTempVariable(
break;
}
/* handle non-vtkObjectBase object arguments as pointers */
if ((aType & VTK_PARSE_UNQUALIFIED_TYPE) == VTK_PARSE_VTK_OBJECT &&
i != MAX_ARGS)
{
fprintf(fp, " *");
}
/* the variable name */
fprintf(fp,"temp%i",i);
......@@ -285,9 +292,9 @@ static void vtkWrapPython_MakeTempVariable(
i);
}
/* for VTK_OBJECT_PTR arguments, a PyObject temp is also needed */
/* for VTK_OBJECT arguments, a PyObject temp is also needed */
if ((i != MAX_ARGS) &&
((aType & VTK_PARSE_UNQUALIFIED_TYPE) == VTK_PARSE_VTK_OBJECT_PTR))
((aType & VTK_PARSE_BASE_TYPE) == VTK_PARSE_VTK_OBJECT))
{
fprintf(fp,
" PyObject *tempH%d;\n",
......@@ -343,10 +350,21 @@ static void vtkWrapPython_ReturnValue(
break;
}
/* only pointers to VTK objects are handled */
/* convert special objects to Python objects */
case VTK_PARSE_VTK_OBJECT_REF:
{
fprintf(fp,
" return vtkPythonGetSpecialObjectFromPointer(temp%i, \"%s\");\n",
MAX_ARGS, currentFunction->ReturnClass);
break;
}
/* convert special objects to Python objects */
case VTK_PARSE_VTK_OBJECT:
{
fprintf(fp,
" return vtkPythonGetSpecialObjectFromPointer(&temp%i, \"%s\");\n",
MAX_ARGS, currentFunction->ReturnClass);
break;
}
......@@ -694,7 +712,7 @@ static char *vtkWrapPython_FormatString(FunctionInfo *currentFunction)
break;
#endif
case VTK_PARSE_SIGNED_CHAR:
result[currPos++] = 'i';
result[currPos++] = 'b';
break;
case VTK_PARSE_CHAR:
result[currPos++] = 'c';
......@@ -703,6 +721,7 @@ static char *vtkWrapPython_FormatString(FunctionInfo *currentFunction)
result[currPos++] = 'b';
break;
case VTK_PARSE_BOOL:
/* assume that sizeof(bool) == 1 */
result[currPos++] = 'b';
break;
}
......@@ -1039,11 +1058,10 @@ static const char *vtkWrapPython_QuoteString(const char *comment, int maxlen)
* words, this poorly named function is "the big one". */
static void vtkWrapPython_GenerateMethods(
FILE *fp, FileInfo *data, int *class_has_new_ptr)
FILE *fp, FileInfo *data, int class_has_new, int do_constructors)
{
int i, j, k, is_static, is_vtkobject, fnum, occ, goto_used;
int all_legacy;
int class_has_new = 0;
int numberOfWrappedFunctions = 0;
FunctionInfo *wrappedFunctions[1000];
FunctionInfo *currentFunction;
......@@ -1053,26 +1071,14 @@ static void vtkWrapPython_GenerateMethods(
int voteCurrent = 0;
int voteMaster = 0;
/* initialize to say "we don't know if the class has a New method" */
*class_has_new_ptr = class_has_new;
/* go through all functions and see which are wrappable,
* note that "currentFunction" is a global variable */
for (i = 0; i < data->NumberOfFunctions; i++)
{
currentFunction = &data->Functions[i];
/* check for New() function */
if (currentFunction->Name &&
strcmp("New",currentFunction->Name) == 0 &&
currentFunction->NumberOfArguments == 0)
{
class_has_new = 1;
*class_has_new_ptr = class_has_new;
}
/* check for wrappability */
if (vtkWrapPython_MethodCheck(data, currentFunction))
if (vtkWrapPython_MethodCheck(data, currentFunction, do_constructors))
{
wrappedFunctions[numberOfWrappedFunctions++] = currentFunction;
}
......@@ -1186,11 +1192,23 @@ static void vtkWrapPython_GenerateMethods(
fprintf(fp,
"#if !defined(VTK_LEGACY_REMOVE)\n");
}
fprintf(fp,
"static PyObject *Py%s_%s(PyObject *%s, PyObject *args)\n"
"{\n",
data->ClassName,currentFunction->Name,
(is_static ? "" : "self"));
/* declare the method */
if (do_constructors)
{
fprintf(fp,
"PyObject *PyVTKObject_%sNew(PyObject *, PyObject *args)\n"
"{\n",
data->ClassName);
}
else
{
fprintf(fp,
"static PyObject *Py%s_%s(PyObject *%s, PyObject *args)\n"
"{\n",
data->ClassName,currentFunction->Name,
(is_static ? "" : "self"));
}
/* find all occurances of this method */
for (occ = fnum; occ < numberOfWrappedFunctions; occ++)
......@@ -1244,7 +1262,7 @@ static void vtkWrapPython_GenerateMethods(
"\n",
data->ClassName);
}
else
else if (!do_constructors)
{
fprintf(fp,
" %s *op = (%s *)((PyVTKSpecialObject *)self)->vtk_ptr;\n"
......@@ -1286,7 +1304,7 @@ static void vtkWrapPython_GenerateMethods(
argType = (currentFunction->ArgTypes[i] &
VTK_PARSE_UNQUALIFIED_TYPE);
if (argType == VTK_PARSE_VTK_OBJECT_PTR)
if ((argType & VTK_PARSE_BASE_TYPE) == VTK_PARSE_VTK_OBJECT)
{
fprintf(fp,", &tempH%d",i);
}
......@@ -1338,6 +1356,18 @@ static void vtkWrapPython_GenerateMethods(
i,i,occ);
goto_used = 1;
}
else if (argType == VTK_PARSE_VTK_OBJECT_REF ||
argType == VTK_PARSE_VTK_OBJECT)
{
fprintf(fp,
" temp%d = (%s *)vtkPythonGetPointerFromSpecialObject(tempH%d,(char*)\"%s\");\n",
i, currentFunction->ArgClasses[i], i,
currentFunction->ArgClasses[i]);
fprintf(fp,
" if (!temp%d && tempH%d != Py_None) { goto break%d; }\n",
i,i,occ);
goto_used = 1;
}
}
/* make sure passed method is callable for VAR functions */
......@@ -1397,6 +1427,10 @@ static void vtkWrapPython_GenerateMethods(
sprintf(methodname,"%s::%s",
data->ClassName,currentFunction->Name);
}
else if (do_constructors)
{
sprintf(methodname, "%s",currentFunction->Name);
}
else if (!is_vtkobject)
{
fprintf(fp,
......@@ -1439,9 +1473,18 @@ static void vtkWrapPython_GenerateMethods(
switch (returnType)
{
case VTK_PARSE_VOID:
fprintf(fp,
" %s(",
methodname);
if (do_constructors)
{
fprintf(fp,
" %s *op = new %s(",
data->ClassName, methodname);
}
else
{
fprintf(fp,
" %s(",
methodname);
}
break;
case VTK_PARSE_VTK_OBJECT_REF:
fprintf(fp,
......@@ -1463,7 +1506,8 @@ static void vtkWrapPython_GenerateMethods(
{
fprintf(fp,",");
}
if (argType == VTK_PARSE_VTK_OBJECT_REF)
if (argType == VTK_PARSE_VTK_OBJECT_REF ||
argType == VTK_PARSE_VTK_OBJECT)
{
fprintf(fp,"*(temp%i)",i);
}
......@@ -1486,8 +1530,12 @@ static void vtkWrapPython_GenerateMethods(
" %sArgDelete(vtkPythonVoidFuncArgDelete);\n",
methodname);
}
fprintf(fp,
" }\n");
if (!do_constructors)
{
fprintf(fp,
" }\n");
}
}
for (i = 0; i < currentFunction->NumberOfArguments; i++)
......@@ -1512,7 +1560,16 @@ static void vtkWrapPython_GenerateMethods(
}
/* generate the code that does "return" for this occurrence */
vtkWrapPython_ReturnValue(fp, currentFunction);
if (do_constructors && !is_vtkobject)
{
fprintf(fp,
" return PyVTKSpecialObject_New((char*)\"%s\", op, 0);\n",
data->ClassName);
}
else
{
vtkWrapPython_ReturnValue(fp, currentFunction);
}
fprintf(fp,
" }\n"
......@@ -1562,7 +1619,13 @@ static void vtkWrapPython_GenerateMethods(
}
} /* is this method non NULL */
} /* loop over all methods */
/* the method table for constructors is produced elsewhere */
if (do_constructors)
{
return;
}
/* output the method table, with pointers to each function defined above */
fprintf(fp,
"static PyMethodDef Py%sMethods[] = {\n",
......@@ -1623,7 +1686,7 @@ static void vtkWrapPython_GenerateMethods(
/* Check a method to see if it is wrappable in python */
static int vtkWrapPython_MethodCheck(
FileInfo *data, FunctionInfo *currentFunction)
FileInfo *data, FunctionInfo *currentFunction, int constructor)
{
int i;
int args_ok = 1;
......@@ -1647,7 +1710,6 @@ static int vtkWrapPython_MethodCheck(