Commit bee2a598 authored by David Gobbi's avatar David Gobbi
Browse files

Update PyVTKSpecialObject to match changes with PyVTKObject.

This includes the use of PyVTKMethodDescriptor, which fixes the issue
where overloads of static and non-static methods did not work.
parent 163f308b
......@@ -64,7 +64,12 @@ PyVTKClass::PyVTKClass(
}
//--------------------------------------------------------------------
PyObject *PyVTKClass_New(
// C API
//--------------------------------------------------------------------
// Add a class, add methods and members to its type object. A return
// value of NULL signifies that the class was already added.
PyVTKClass *PyVTKClass_Add(
PyTypeObject *pytype, PyMethodDef *methods,
const char *classname, const char *manglename,
const char *docstring[], vtknewfunc constructor)
......@@ -76,8 +81,8 @@ PyObject *PyVTKClass_New(
if (info == 0)
{
// Return the class if it was already in the map
return (PyObject *)pytype;
// The class was already in the map, so do nothing
return info;
}
// Cache the type object for vtkObjectBase for quick access
......@@ -110,15 +115,7 @@ PyObject *PyVTKClass_New(
Py_DECREF(func);
}
// Return NULL so caller knows that type object is not ready yet
return 0;
}
//--------------------------------------------------------------------
int PyVTKClass_Check(PyObject *op)
{
return (PyType_Check(op) &&
PyObject_IsSubclass(op, (PyObject *)PyVTKObject_Type));
return info;
}
//--------------------------------------------------------------------
......@@ -127,6 +124,9 @@ int PyVTKObject_Check(PyObject *op)
return PyObject_TypeCheck(op, PyVTKObject_Type);
}
//--------------------------------------------------------------------
// Object protocol
//--------------------------------------------------------------------
PyObject *PyVTKObject_String(PyObject *op)
{
......
......@@ -71,13 +71,10 @@ extern VTKWRAPPINGPYTHONCORE_EXPORT PyBufferProcs PyVTKObject_AsBuffer;
extern "C"
{
VTKWRAPPINGPYTHONCORE_EXPORT
PyObject *PyVTKClass_New(
PyVTKClass *PyVTKClass_Add(
PyTypeObject *pytype, PyMethodDef *methods, const char *classname,
const char *manglename, const char *docstring[], vtknewfunc constructor);
VTKWRAPPINGPYTHONCORE_EXPORT
int PyVTKClass_Check(PyObject *obj);
VTKWRAPPINGPYTHONCORE_EXPORT
int PyVTKObject_Check(PyObject *obj);
......
......@@ -30,6 +30,7 @@
-----------------------------------------------------------------------*/
#include "PyVTKSpecialObject.h"
#include "PyVTKMethodDescriptor.h"
#include "vtkPythonUtil.h"
#include <vtksys/ios/sstream>
......@@ -45,15 +46,17 @@
//--------------------------------------------------------------------
PyVTKSpecialType::PyVTKSpecialType(
PyTypeObject *typeobj, PyMethodDef *cmethods, PyMethodDef *ccons,
const char *cdocs[], PyVTKSpecialCopyFunc copyfunc)
vtkcopyfunc copyfunc)
{
this->py_type = typeobj;
this->methods = cmethods;
this->constructors = ccons;
this->docstring = vtkPythonUtil::BuildDocString(cdocs);
this->copy_func = copyfunc;
this->vtk_methods = cmethods;
this->vtk_constructors = ccons;
this->vtk_copy = copyfunc;
}
//--------------------------------------------------------------------
// Object protocol
//--------------------------------------------------------------------
PyObject *PyVTKSpecialObject_Repr(PyObject *self)
{
......@@ -166,6 +169,10 @@ PyObject *PyVTKSpecialObject_SequenceString(PyObject *self)
}
//--------------------------------------------------------------------
// C API
//--------------------------------------------------------------------
// Create a new python object from the pointer to a C++ object
PyObject *PyVTKSpecialObject_New(const char *classname, void *ptr)
{
// would be nice if "info" could be passed instead if "classname",
......@@ -182,6 +189,7 @@ PyObject *PyVTKSpecialObject_New(const char *classname, void *ptr)
}
//--------------------------------------------------------------------
// Create a new python object via the copy constructor of the C++ object
PyObject *PyVTKSpecialObject_CopyNew(const char *classname, const void *ptr)
{
PyVTKSpecialType *info = vtkPythonUtil::FindSpecialType(classname);
......@@ -197,30 +205,48 @@ PyObject *PyVTKSpecialObject_CopyNew(const char *classname, const void *ptr)
PyVTKSpecialObject *self = PyObject_New(PyVTKSpecialObject, info->py_type);
self->vtk_info = info;
self->vtk_ptr = info->copy_func(ptr);
self->vtk_ptr = info->vtk_copy(ptr);
self->vtk_hash = -1;
return (PyObject *)self;
}
//--------------------------------------------------------------------
PyObject *PyVTKSpecialType_New(PyTypeObject *pytype,
PyMethodDef *methods, PyMethodDef *constructors, PyMethodDef *newmethod,
const char *docstring[], PyVTKSpecialCopyFunc copyfunc)
// Add a special type, add methods and members to its type object.
// A return value of NULL signifies that it was already added.
PyVTKSpecialType *PyVTKSpecialType_Add(PyTypeObject *pytype,
PyMethodDef *methods, PyMethodDef *constructors,
const char *docstring[], vtkcopyfunc copyfunc)
{
// Add this type to the special type map
PyVTKSpecialType *info =
vtkPythonUtil::AddSpecialTypeToMap(
pytype, methods, constructors, docstring, copyfunc);
pytype, methods, constructors, copyfunc);
if (info == 0)
{
// The type was already in the map, so do nothing
return info;
}
// Create the dict
if (pytype->tp_dict == 0)
{
pytype->tp_dict = PyDict_New();
}
// Add the docstring to the type
PyObject *doc = vtkPythonUtil::BuildDocString(docstring);
PyDict_SetItemString(pytype->tp_dict, "__doc__", doc);
Py_DECREF(doc);
if (info)
// Add all of the methods
for (PyMethodDef *meth = methods; meth && meth->ml_name; meth++)
{
// Add the built docstring to the type
pytype->tp_doc = PyString_AsString(info->docstring);
newmethod->ml_doc = PyString_AsString(info->docstring);
PyObject *func = PyVTKMethodDescriptor_New(pytype, meth);
PyDict_SetItemString(pytype->tp_dict, meth->ml_name, func);
Py_DECREF(func);
}
// Return the type object
PyType_Ready(pytype);
return (PyObject *)pytype;
return info;
}
......@@ -29,7 +29,7 @@
// Prototypes for per-type copy, delete, and print funcs
// copy the object and return the copy
typedef void *(*PyVTKSpecialCopyFunc)(const void *);
typedef void *(*vtkcopyfunc)(const void *);
// Because the PyTypeObject can't hold all the typing information that we
// need, we use this PyVTKSpecialType class to hold a bit of extra info.
......@@ -37,19 +37,18 @@ class VTKWRAPPINGPYTHONCORE_EXPORT PyVTKSpecialType
{
public:
PyVTKSpecialType() :
py_type(0), methods(0), constructors(0), docstring(0), copy_func(0) {}
py_type(0), vtk_methods(0), vtk_constructors(0), vtk_copy(0) {}
PyVTKSpecialType(
PyTypeObject *typeobj, PyMethodDef *cmethods, PyMethodDef *ccons,
const char *cdocs[], PyVTKSpecialCopyFunc copyfunc);
vtkcopyfunc copyfunc);
// general information
PyTypeObject *py_type;
PyMethodDef *methods;
PyMethodDef *constructors;
PyObject *docstring;
PyMethodDef *vtk_methods;
PyMethodDef *vtk_constructors;
// copy an object
PyVTKSpecialCopyFunc copy_func;
vtkcopyfunc vtk_copy;
};
// The PyVTKSpecialObject is very lightweight. All special VTK types
......@@ -65,9 +64,9 @@ struct PyVTKSpecialObject {
extern "C"
{
VTKWRAPPINGPYTHONCORE_EXPORT
PyObject *PyVTKSpecialType_New(PyTypeObject *pytype,
PyMethodDef *methods, PyMethodDef *constructors, PyMethodDef *newmethod,
const char *docstring[], PyVTKSpecialCopyFunc copyfunc);
PyVTKSpecialType *PyVTKSpecialType_Add(PyTypeObject *pytype,
PyMethodDef *methods, PyMethodDef *constructors,
const char *docstring[], vtkcopyfunc copyfunc);
VTKWRAPPINGPYTHONCORE_EXPORT
PyObject *PyVTKSpecialObject_New(const char *classname, void *ptr);
......
......@@ -793,7 +793,7 @@ VTK_PYTHON_BUILD_TUPLE(unsigned __int64)
//--------------------------------------------------------------------
// If "self" is a class, get real "self" from arg list
vtkObjectBase *vtkPythonArgs::GetSelfFromFirstArg(
PyObject *vtkPythonArgs::GetSelfFromFirstArg(
PyObject *self, PyObject *args)
{
if (PyType_Check(self))
......@@ -804,7 +804,7 @@ vtkObjectBase *vtkPythonArgs::GetSelfFromFirstArg(
self = PyTuple_GET_ITEM(args, 0);
if (PyObject_TypeCheck(self, pytype))
{
return ((PyVTKObject *)self)->vtk_ptr;
return self;
}
}
......
......@@ -65,13 +65,19 @@ public:
// Description:
// Get a pointer to the self object, converted to its C++ type.
// Returns NULL and sets a TypeError if the type is wrong.
// If "self" is a PyVTKClass, pull the object from the first arg.
// If "self" is a class type, pull the object from the first arg.
static vtkObjectBase *GetSelfPointer(PyObject *self, PyObject *args);
// Description:
// Get a pointer to the self object, converted to its C++ type.
// Returns NULL and sets a TypeError if the type is wrong.
// If "self" is a type, pull the object from the first arg.
static void *GetSelfSpecialPointer(PyObject *self, PyObject *args);
// Description:
// Get a pointer to the self object, converted to its C++ type.
// Always succeeds.
static void *GetSelfPointer(PyObject *self);
static void *GetSelfSpecialPointer(PyObject *self);
// Description:
// Verify the arg count for a method with optional arguments.
......@@ -499,7 +505,7 @@ protected:
// Description:
// Get the "self" object from the first argument.
static vtkObjectBase *GetSelfFromFirstArg(PyObject *self, PyObject *args);
static PyObject *GetSelfFromFirstArg(PyObject *self, PyObject *args);
// Description:
// Get the next argument as an object of the given type.
......@@ -568,14 +574,25 @@ vtkObjectBase *vtkPythonArgs::GetSelfPointer(PyObject *self, PyObject *args)
{
if (PyType_Check(self))
{
return vtkPythonArgs::GetSelfFromFirstArg(self, args);
self = vtkPythonArgs::GetSelfFromFirstArg(self, args);
}
return ((PyVTKObject *)self)->vtk_ptr;
return (self ? ((PyVTKObject *)self)->vtk_ptr : NULL);
}
// Get "self" from a PyVTKSpecialObject.
inline
void *vtkPythonArgs::GetSelfPointer(PyObject *self)
void *vtkPythonArgs::GetSelfSpecialPointer(PyObject *self, PyObject *args)
{
if (PyType_Check(self))
{
self = vtkPythonArgs::GetSelfFromFirstArg(self, args);
}
return (self ? ((PyVTKSpecialObject *)self)->vtk_ptr : NULL);
}
// Get "self" from a PyVTKSpecialObject (for methods with no args).
inline
void *vtkPythonArgs::GetSelfSpecialPointer(PyObject *self)
{
return ((PyVTKSpecialObject *)self)->vtk_ptr;
}
......
......@@ -495,7 +495,7 @@ int vtkPythonOverload::CheckArg(
{
// Try out all the constructor methods
if (!vtkPythonOverload::FindConversionMethod(
info->constructors, arg))
info->vtk_constructors, arg))
{
penalty = VTK_PYTHON_INCOMPATIBLE;
}
......@@ -692,9 +692,9 @@ PyObject *vtkPythonOverload::CallMethod(
bool selfIsClass = 0;
int sig;
// Is self a PyVTKClass object, rather than a PyVTKObject? If so,
// then first arg is an object, and other args should follow format.
if (self && PyVTKClass_Check(self))
// Is self a type object, rather than an instance? If so, then the
// first arg is an object, and other args should follow format.
if (self && PyType_Check(self))
{
selfIsClass = true;
}
......
......@@ -291,7 +291,7 @@ PyObject *vtkPythonUtil::BuildDocString(const char *docstring[])
//--------------------------------------------------------------------
PyVTKSpecialType *vtkPythonUtil::AddSpecialTypeToMap(
PyTypeObject *pytype, PyMethodDef *methods, PyMethodDef *constructors,
const char *docstring[], PyVTKSpecialCopyFunc copyfunc)
vtkcopyfunc copyfunc)
{
const char *classname = pytype->tp_name;
vtkPythonUtilCreateIfNeeded();
......@@ -303,19 +303,15 @@ PyVTKSpecialType *vtkPythonUtil::AddSpecialTypeToMap(
// lets make sure it isn't already there
vtkPythonSpecialTypeMap::iterator i =
vtkPythonMap->SpecialTypeMap->find(classname);
if(i != vtkPythonMap->SpecialTypeMap->end())
if (i != vtkPythonMap->SpecialTypeMap->end())
{
#ifdef VTKPYTHONDEBUG
vtkGenericWarningMacro("Attempt to add type to the map when already there!!!");
#endif
return 0;
}
i = vtkPythonMap->SpecialTypeMap->insert(i,
vtkPythonSpecialTypeMap::value_type(
classname,
PyVTKSpecialType(pytype, methods, constructors,
docstring, copyfunc)));
PyVTKSpecialType(pytype, methods, constructors, copyfunc)));
#ifdef VTKPYTHONDEBUG
// vtkGenericWarningMacro("Added type to map type = " << typeObject);
......@@ -787,7 +783,7 @@ void *vtkPythonUtil::GetPointerFromSpecialObject(
PyVTKSpecialType *info = &it->second;
PyMethodDef *meth =
vtkPythonOverload::FindConversionMethod(info->constructors, obj);
vtkPythonOverload::FindConversionMethod(info->vtk_constructors, obj);
// If a constructor signature exists for "obj", call it
if (meth && meth->ml_meth)
......
......@@ -113,7 +113,7 @@ public:
// later create object given only the class name.
static PyVTKSpecialType *AddSpecialTypeToMap(
PyTypeObject *pytype, PyMethodDef *methods, PyMethodDef *constructors,
const char *docstring[], PyVTKSpecialCopyFunc copyfunc);
vtkcopyfunc copyfunc);
// Description:
// Get information about a special VTK type, given the type name.
......
......@@ -68,9 +68,9 @@ const char *vtkWrapPython_GetSuperClass(
supername = cp;
}
// Add QVTKInteractor as the sole exception: It is derived
// from vtkObject but does not start with "vtk". Given its
// name, it would be expected to be derived from QObject.
/* Add QVTKInteractor as the sole exception: It is derived
* from vtkObject but does not start with "vtk". Given its
* name, it would be expected to be derived from QObject. */
if (vtkWrap_IsVTKObjectBaseType(hinfo, data->Name) ||
strcmp(data->Name, "QVTKInteractor") == 0)
{
......@@ -354,7 +354,7 @@ static void vtkWrapPython_GenerateObjectNew(
fprintf(fp,
"PyObject *Py%s_ClassNew(const char *)\n"
"{\n"
" PyObject *cls = PyVTKClass_New(\n"
" PyVTKClass_Add(\n"
" &Py%s_Type, Py%s_Methods,\n",
classname, classname, classname);
......@@ -386,12 +386,13 @@ static void vtkWrapPython_GenerateObjectNew(
" NULL);\n\n");
}
/* return if the class is already ready */
/* if type is already ready, then return */
fprintf(fp,
" if (cls)\n"
" if ((Py%s_Type.tp_flags & Py_TPFLAGS_READY) != 0)\n"
" {\n"
" return cls;\n"
" }\n\n");
" return (PyObject *)&Py%s_Type;\n"
" }\n\n",
classname, classname);
/* find the first superclass that is a VTK class, create it first */
name = vtkWrapPython_GetSuperClass(data, hinfo);
......
......@@ -1061,8 +1061,8 @@ void vtkWrapPython_GenerateOneMethod(
else if (!theOccurrence->IsStatic && !do_constructors)
{
fprintf(fp,
" vtkPythonArgs ap(args, \"%s\");\n"
" void *vp = ap.GetSelfPointer(self);\n"
" vtkPythonArgs ap(self, args, \"%s\");\n"
" void *vp = ap.GetSelfSpecialPointer(self, args);\n"
" %s *op = static_cast<%s *>(vp);\n"
"\n",
theOccurrence->Name, data->Name, data->Name);
......@@ -1085,13 +1085,18 @@ void vtkWrapPython_GenerateOneMethod(
fprintf(fp,
" if (");
/* special things for vtkObject methods */
if (is_vtkobject && !theOccurrence->IsStatic)
if (!theOccurrence->IsStatic && !do_constructors)
{
/* if not static, make sure the object is not null */
fprintf(fp, "op && ");
if (theOccurrence->IsPureVirtual)
if (is_vtkobject)
{
fprintf(fp, "!ap.IsPureVirtual() && ");
/* special things for vtkObject methods */
if (theOccurrence->IsPureVirtual)
{
fprintf(fp, "!ap.IsPureVirtual() && ");
}
}
}
......@@ -1170,7 +1175,7 @@ void vtkWrapPython_GenerateOneMethod(
vtkWrapPython_OverloadMethodDef(
fp, classname, data, overloadMap,
wrappedFunctions, numberOfWrappedFunctions,
fnum, numberOfOccurrences, is_vtkobject, all_legacy);
fnum, numberOfOccurrences, all_legacy);
}
if (numberOfOccurrences > 1)
......
......@@ -40,7 +40,7 @@ static char *vtkWrapPython_FormatString(
/* create a string for checking arguments against available signatures */
static char *vtkWrapPython_ArgCheckString(
int isvtkobjmethod, FunctionInfo *currentFunction);
int isStatic, FunctionInfo *currentFunction);
/* -------------------------------------------------------------------- */
......@@ -242,7 +242,7 @@ static char *vtkWrapPython_FormatString(FunctionInfo *currentFunction)
* are possible, so the "at" is a placeholder for "self". */
static char *vtkWrapPython_ArgCheckString(
int isvtkobjmethod, FunctionInfo *currentFunction)
int isStatic, FunctionInfo *currentFunction)
{
static char result[2048]; /* max literal string length */
char pythonname[1024];
......@@ -256,10 +256,12 @@ static char *vtkWrapPython_ArgCheckString(
if (currentFunction->IsExplicit)
{
/* only used for explicit contsructors */
result[currPos++] = '-';
}
if (isvtkobjmethod)
/* placeholder for type in unbound method calls */
if (!isStatic)
{
result[currPos++] = '@';
}
......@@ -452,7 +454,7 @@ int *vtkWrapPython_ArgCountToOverloadMap(
void vtkWrapPython_OverloadMethodDef(
FILE *fp, const char *classname, ClassInfo *data, int *overloadMap,
FunctionInfo **wrappedFunctions, int numberOfWrappedFunctions,
int fnum, int numberOfOccurrences, int is_vtkobject, int all_legacy)
int fnum, int numberOfOccurrences, int all_legacy)
{
char occSuffix[8];
int occ, occCounter;
......@@ -534,8 +536,7 @@ void vtkWrapPython_OverloadMethodDef(
occSuffix,
theOccurrence->IsStatic ? " | METH_STATIC" : "",
vtkWrapPython_ArgCheckString(
(is_vtkobject && !theOccurrence->IsStatic),
wrappedFunctions[occ]));
theOccurrence->IsStatic, wrappedFunctions[occ]));
if (theOccurrence->IsLegacy && !all_legacy)
{
......
......@@ -24,7 +24,7 @@
void vtkWrapPython_OverloadMethodDef(
FILE *fp, const char *classname, ClassInfo *data, int *overloadMap,
FunctionInfo **wrappedFunctions, int numberOfWrappedFunctions, int fnum,
int numberOfOccurrences, int is_vtkobject, int all_legacy);
int numberOfOccurrences, int all_legacy);
/* a master method to choose which overload to call */
void vtkWrapPython_OverloadMasterMethod(
......
......@@ -366,7 +366,7 @@ static void vtkWrapPython_SequenceProtocol(
fprintf(fp,
"Py_ssize_t Py%s_SequenceSize(PyObject *self)\n"
"{\n"
" void *vp = vtkPythonArgs::GetSelfPointer(self);\n"
" void *vp = vtkPythonArgs::GetSelfSpecialPointer(self);\n"
" %s *op = static_cast<%s *>(vp);\n"
"\n"
" return static_cast<Py_ssize_t>(op->%s);\n"
......@@ -376,7 +376,7 @@ static void vtkWrapPython_SequenceProtocol(
fprintf(fp,
"PyObject *Py%s_SequenceItem(PyObject *self, Py_ssize_t i)\n"
"{\n"
" void *vp = vtkPythonArgs::GetSelfPointer(self);\n"
" void *vp = vtkPythonArgs::GetSelfSpecialPointer(self);\n"
" %s *op = static_cast<%s *>(vp);\n"
"\n",
classname, data->Name, data->Name);
......@@ -417,7 +417,7 @@ static void vtkWrapPython_SequenceProtocol(
"int Py%s_SequenceSetItem(\n"
" PyObject *self, Py_ssize_t i, PyObject *arg1)\n"
"{\n"
" void *vp = vtkPythonArgs::GetSelfPointer(self);\n"
" void *vp = vtkPythonArgs::GetSelfSpecialPointer(self);\n"
" %s *op = static_cast<%s *>(vp);\n"
"\n",
classname, data->Name, data->Name);
......@@ -666,15 +666,6 @@ void vtkWrapPython_GenerateSpecialType(
/* generate all constructor methods */
vtkWrapPython_GenerateMethods(fp, classname, data, finfo, hinfo, 0, 1);
/* generate the method table for the New method */
fprintf(fp,
"static PyMethodDef Py%s_NewMethod = \\\n"
"{ \"%s\", Py%s_%*.*s, 1,\n"
" \"\" };\n"
"\n",
classname, classname, classname,
(int)n, (int)n, constructor);
/* generate all functions and protocols needed for the type */
vtkWrapPython_SpecialTypeProtocols(
fp, classname, data, finfo, hinfo, &info);
......@@ -757,14 +748,10 @@ void vtkWrapPython_GenerateSpecialType(
fprintf(fp,
" 0, // tp_weaklistoffset\n"
" 0, // tp_iter\n"
" 0, // tp_iternext\n");
/* class methods introduced in python 2.2 */
fprintf(fp,
" Py%s_Methods, // tp_methods\n"
" 0, // tp_iternext\n"
" 0, // tp_methods\n"
" 0, // tp_members\n"
" 0, // tp_getset\n",
classname);
" 0, // tp_getset\n");
if (has_superclass)
{
......@@ -817,22 +804,53 @@ void vtkWrapPython_GenerateSpecialType(
"\n",
classname, data->Name, data->Name);
/* export New method for use by subclasses */
fprintf(fp,
"extern \"C\" { %s PyObject *Py%s_TypeNew(const char *); }\n\n",
"VTK_PYTHON_EXPORT", classname);
/* import New method of the superclass */
if (has_superclass)
{
fprintf(fp,
"#ifndef DECLARED_Py%s_TypeNew\n"
"extern \"C\" { PyObject *Py%s_TypeNew(const char *); }\n"
"#define DECLARED_Py%s_TypeNew\n"
"#endif\n",
supername, supername, supername);
}
/* the method for adding the VTK extras to the type,
* the unused "const char *" arg is the module name */
fprintf(fp,
"static PyObject *Py%s_TypeNew(const char *)\n"
"PyObject *Py%s_TypeNew(const char *)\n"
"{\n"
" PyObject *cls = PyVTKSpecialType_New(\n"
" PyVTKSpecialType_Add(\n"
" &Py%s_Type,\n"
" Py%s_Methods,\n"
" Py%s_%*.*s_Methods,\n"
" &Py%s_NewMethod,\n"
" Py%s_Doc(), &Py%s_CCopy);\n"
"\n",
classname, classname, classname,
classname, (int)n, (int)n