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

Do type checking with type objects, not strings.

There is no guarantee that tp_name is unique, and it would be bad
if someone fooled the type checking by simply creating a new type
with the same name as an existing type.
parent 1f1f9f47
......@@ -152,7 +152,7 @@ static PyMemberDef PyVTKMethodDescriptor_Members[] = {
PyTypeObject PyVTKMethodDescriptor_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0,
"vtk_method_descriptor", // tp_name
"vtk.method_descriptor", // tp_name
sizeof(PyMethodDescrObject), // tp_basicsize
0, // tp_itemsize
PyVTKMethodDescriptor_Delete, // tp_dealloc
......
......@@ -436,15 +436,14 @@ int vtkPythonOverload::CheckArg(
}
else if (PyVTKObject_Check(arg))
{
PyVTKObject *vobj = (PyVTKObject *)arg;
if (strncmp(vtkPythonUtil::PythonicClassName(
vobj->vtk_ptr->GetClassName()), classname, 127) != 0)
PyVTKClass *info = vtkPythonUtil::FindClass(classname);
PyTypeObject *pytype = (info ? info->py_type : NULL);
if (arg->ob_type != pytype)
{
// Check superclasses
PyTypeObject *basetype = arg->ob_type->tp_base;
penalty = VTK_PYTHON_GOOD_MATCH;
while (basetype &&
strncmp(basetype->tp_name, classname, 127) != 0)
while (basetype && basetype != pytype)
{
penalty++;
basetype = basetype->tp_base;
......@@ -465,14 +464,17 @@ int vtkPythonOverload::CheckArg(
else if (classname[0] == 'v' && classname[1] == 't' &&
classname[2] == 'k')
{
// Look up the required type in the map
PyVTKSpecialType *info = vtkPythonUtil::FindSpecialType(classname);
PyTypeObject *pytype = (info ? info->py_type : NULL);
// Check for an exact match
if (strncmp(arg->ob_type->tp_name, classname, 127) != 0)
if (arg->ob_type != pytype)
{
// Check superclasses
PyTypeObject *basetype = arg->ob_type->tp_base;
penalty = VTK_PYTHON_GOOD_MATCH;
while (basetype &&
strncmp(basetype->tp_name, classname, 127) != 0)
while (basetype && basetype != pytype)
{
penalty++;
basetype = basetype->tp_base;
......@@ -482,12 +484,8 @@ int vtkPythonOverload::CheckArg(
// If it didn't match, then maybe conversion is possible
penalty = VTK_PYTHON_NEEDS_CONVERSION;
// Look up the required type in the map
PyVTKSpecialType *info = NULL;
// The "level != 0" ensures that we don't chain conversions
if (level != 0 ||
(info = vtkPythonUtil::FindSpecialType(classname)) == NULL)
if (level != 0 || info == 0)
{
penalty = VTK_PYTHON_INCOMPATIBLE;
}
......@@ -509,14 +507,17 @@ int vtkPythonOverload::CheckArg(
// Skip over the "&" that indicates a non-const reference
classname++;
// Look up the required type in the map
PyVTKSpecialType *info = vtkPythonUtil::FindSpecialType(classname);
PyTypeObject *pytype = (info ? info->py_type : NULL);
// Check for an exact match
if (strncmp(arg->ob_type->tp_name, classname, 127) != 0)
if (arg->ob_type != pytype)
{
// Check superclasses
PyTypeObject *basetype = arg->ob_type->tp_base;
penalty = VTK_PYTHON_GOOD_MATCH;
while (basetype &&
strncmp(basetype->tp_name, classname, 127) != 0)
while (basetype && basetype != pytype)
{
penalty++;
basetype = basetype->tp_base;
......@@ -585,26 +586,14 @@ int vtkPythonOverload::CheckArg(
}
if (PyInt_Check(arg))
{
if (strcmp(arg->ob_type->tp_name, classname) == 0)
PyTypeObject *pytype = vtkPythonUtil::FindEnum(classname);
if (pytype && PyObject_TypeCheck(arg, pytype))
{
penalty = VTK_PYTHON_EXACT_MATCH;
}
else
{
/* tp_name doesn't include namespace, so we also allow
matches between "name" and "namespace.name" */
size_t l, m;
l = strlen(arg->ob_type->tp_name);
m = strlen(classname);
if (l < m && !isalnum(classname[m-l-1]) &&
strcmp(arg->ob_type->tp_name, &classname[m-l]) == 0)
{
penalty = VTK_PYTHON_GOOD_MATCH;
}
else
{
penalty = VTK_PYTHON_NEEDS_CONVERSION;
}
penalty = VTK_PYTHON_NEEDS_CONVERSION;
}
}
else
......
......@@ -155,6 +155,12 @@ class vtkPythonNamespaceMap
{
};
// Keep track of all the C++ enums that have been wrapped.
class vtkPythonEnumMap
: public std::map<std::string, PyTypeObject*>
{
};
// Keep track of all vtkPythonCommand instances.
class vtkPythonCommandList
: public std::vector<vtkWeakPointer<vtkPythonCommand> >
......@@ -208,6 +214,7 @@ vtkPythonUtil::vtkPythonUtil()
this->ClassMap = new vtkPythonClassMap;
this->SpecialTypeMap = new vtkPythonSpecialTypeMap;
this->NamespaceMap = new vtkPythonNamespaceMap;
this->EnumMap = new vtkPythonEnumMap;
this->PythonCommandList = new vtkPythonCommandList;
}
......@@ -219,6 +226,7 @@ vtkPythonUtil::~vtkPythonUtil()
delete this->ClassMap;
delete this->SpecialTypeMap;
delete this->NamespaceMap;
delete this->EnumMap;
delete this->PythonCommandList;
}
......@@ -754,34 +762,24 @@ PyObject *vtkPythonUtil::GetObjectFromObject(
void *vtkPythonUtil::GetPointerFromSpecialObject(
PyObject *obj, const char *result_type, PyObject **newobj)
{
// The type name
const char *object_type = obj->ob_type->tp_name;
// check to make sure that it is the right type
if (strcmp(object_type, result_type) == 0)
// do a lookup on the desired type
vtkPythonSpecialTypeMap::iterator it =
vtkPythonMap->SpecialTypeMap->find(result_type);
if (it != vtkPythonMap->SpecialTypeMap->end())
{
return ((PyVTKSpecialObject *)obj)->vtk_ptr;
}
PyVTKSpecialType *info = &it->second;
// check superclasses
for (PyTypeObject *basetype = obj->ob_type->tp_base;
basetype != NULL;
basetype = basetype->tp_base)
{
if (strcmp(basetype->tp_name, result_type) == 0)
// first, check if object is the desired type
if (PyObject_TypeCheck(obj, info->py_type))
{
return ((PyVTKSpecialObject *)obj)->vtk_ptr;
}
}
// try to construct the special object from the supplied object
vtkPythonSpecialTypeMap::iterator it =
vtkPythonMap->SpecialTypeMap->find(result_type);
if(it != vtkPythonMap->SpecialTypeMap->end())
{
// try to construct the special object from the supplied object
PyObject *sobj = 0;
PyVTKSpecialType *info = &it->second;
PyMethodDef *meth =
vtkPythonOverload::FindConversionMethod(info->vtk_constructors, obj);
......@@ -866,7 +864,7 @@ void vtkPythonUtil::AddNamespaceToMap(PyObject *module)
}
//--------------------------------------------------------------------
// This method is called
// This method is called from PyVTKNamespace_Delete
void vtkPythonUtil::RemoveNamespaceFromMap(PyObject *obj)
{
if (vtkPythonMap && PyVTKNamespace_Check(obj))
......@@ -900,6 +898,42 @@ PyObject *vtkPythonUtil::FindNamespace(const char *name)
return NULL;
}
//--------------------------------------------------------------------
void vtkPythonUtil::AddEnumToMap(PyTypeObject *enumtype)
{
if (vtkPythonMap == NULL)
{
vtkPythonMap = new vtkPythonUtil();
Py_AtExit(vtkPythonUtilDelete);
}
// Only add to map if it isn't already there
vtkPythonEnumMap::iterator i =
vtkPythonMap->EnumMap->find(enumtype->tp_name);
if (i == vtkPythonMap->EnumMap->end())
{
(*vtkPythonMap->EnumMap)[enumtype->tp_name] = enumtype;
}
}
//--------------------------------------------------------------------
PyTypeObject *vtkPythonUtil::FindEnum(const char *name)
{
PyTypeObject *pytype = NULL;
if (vtkPythonMap)
{
vtkPythonEnumMap::iterator it =
vtkPythonMap->EnumMap->find(name);
if (it != vtkPythonMap->EnumMap->end())
{
pytype = it->second;
}
}
return pytype;
}
//--------------------------------------------------------------------
// mangle a void pointer into a SWIG-style string
char *vtkPythonUtil::ManglePointer(const void *ptr, const char *type)
......
......@@ -31,6 +31,7 @@ class vtkPythonGhostMap;
class vtkPythonObjectMap;
class vtkPythonSpecialTypeMap;
class vtkPythonNamespaceMap;
class vtkPythonEnumMap;
class vtkStdString;
class vtkUnicodeString;
class vtkVariant;
......@@ -144,6 +145,14 @@ public:
// Return an existing namespace, or NULL if it doesn't exist.
static PyObject *FindNamespace(const char *name);
// Description:
// Add a wrapped C++ enum as a python type object.
static void AddEnumToMap(PyTypeObject *o);
// Description:
// Return an enum type object, or NULL if it doesn't exist.
static PyTypeObject *FindEnum(const char *name);
// Description:
// Utility function to build a docstring by concatenating a series
// of strings until a null string is found.
......@@ -180,6 +189,7 @@ private:
vtkPythonClassMap *ClassMap;
vtkPythonSpecialTypeMap *SpecialTypeMap;
vtkPythonNamespaceMap *NamespaceMap;
vtkPythonEnumMap *EnumMap;
vtkPythonCommandList *PythonCommandList;
friend void vtkPythonUtilDelete();
......
......@@ -50,18 +50,20 @@ void vtkWrapPython_AddEnumType(
fprintf(fp,
"%sPyType_Ready(&Py%s%s%s_Type);\n"
"%sPy%s%s%s_Type.tp_new = NULL;\n"
"%svtkPythonUtil::AddEnumToMap(&Py%s%s%s_Type);\n"
"\n",
indent, (scope ? scope : ""), (scope ? "_" : ""), cls->Name,
indent, (scope ? scope : ""), (scope ? "_" : ""), cls->Name,
indent, (scope ? scope : ""), (scope ? "_" : ""), cls->Name);
fprintf(fp,
"%s%s = (PyObject *)&Py%s%s%s_Type;\n"
"%sif (%s && PyDict_SetItemString(%s, \"%s\", %s) != 0)\n"
"%sif (PyDict_SetItemString(%s, \"%s\", %s) != 0)\n"
"%s {\n"
"%s Py_DECREF(%s);\n"
"%s }\n",
indent, objvar,
(scope ? scope : ""), (scope ? "_" : ""), cls->Name,
indent, objvar, dictvar, cls->Name, objvar,
indent, dictvar, cls->Name, objvar,
indent,
indent, objvar,
indent);
......@@ -72,19 +74,19 @@ void vtkWrapPython_AddEnumType(
void vtkWrapPython_GenerateEnumType(
FILE *fp, const char *classname, EnumInfo *data)
{
char enumname[1024];
size_t classnamelen = 0;
char enumname[512];
char tpname[512];
if (classname)
{
classnamelen = strlen(classname);
strcpy(enumname, classname);
enumname[classnamelen] = '_';
strcpy(enumname+classnamelen+1, data->Name);
/* join with "_" for identifier, and with "." for type name */
sprintf(enumname, "%.200s_%.200s", classname, data->Name);
sprintf(tpname, "%.200s.%.200s", classname, data->Name);
}
else
{
strcpy(enumname, data->Name);
sprintf(enumname, "%.200s", data->Name);
sprintf(tpname, "%.200s", data->Name);
}
/* forward declaration of the type object */
......@@ -112,7 +114,7 @@ void vtkWrapPython_GenerateEnumType(
" 0, // tp_setattr\n"
" 0, // tp_compare\n"
" 0, // tp_repr\n",
enumname, data->Name);
enumname, tpname);
fprintf(fp,
" 0, // tp_as_number\n"
......
......@@ -40,7 +40,7 @@ static char *vtkWrapPython_FormatString(
/* create a string for checking arguments against available signatures */
static char *vtkWrapPython_ArgCheckString(
int isStatic, FunctionInfo *currentFunction);
ClassInfo *data, FunctionInfo *currentFunction);
/* -------------------------------------------------------------------- */
......@@ -235,14 +235,14 @@ static char *vtkWrapPython_FormatString(FunctionInfo *currentFunction)
/* -------------------------------------------------------------------- */
/* Create a string to describe the signature of a method.
* If isvtkobject is set the string will start with an "at" symbol.
* The string will start with an "at" symbol unless the method is static.
* Following the optional space will be a ParseTuple format string,
* followed by the names of any VTK classes required. The optional
* "at" symbol indicates that methods like vtkClass.Method(self, arg1,...)
* are possible, so the "at" is a placeholder for "self". */
static char *vtkWrapPython_ArgCheckString(
int isStatic, FunctionInfo *currentFunction)
ClassInfo *data, FunctionInfo *currentFunction)
{
static char result[2048]; /* max literal string length */
char pythonname[1024];
......@@ -260,8 +260,8 @@ static char *vtkWrapPython_ArgCheckString(
result[currPos++] = '-';
}
/* placeholder for type in unbound method calls */
if (!isStatic)
/* placeholder for type object in unbound method calls */
if (!currentFunction->IsStatic)
{
result[currPos++] = '@';
}
......@@ -304,7 +304,16 @@ static char *vtkWrapPython_ArgCheckString(
argtype == VTK_PARSE_QOBJECT_REF ||
argtype == VTK_PARSE_QOBJECT_PTR)
{
vtkWrapPython_PythonicName(arg->Class, pythonname);
/* If argtype is an enum that is a member of the class whose
* method we are wrapping, then qualify the name with the class */
if (vtkWrap_IsEnumMember(data, arg))
{
sprintf(pythonname, "%.200s.%.200s", data->Name, arg->Class);
}
else
{
vtkWrapPython_PythonicName(arg->Class, pythonname);
}
result[currPos++] = ' ';
if ((argtype == VTK_PARSE_OBJECT_REF ||
......@@ -532,11 +541,10 @@ void vtkWrapPython_OverloadMethodDef(
fprintf(fp,
" {NULL, Py%s_%s%s, METH_VARARGS%s,\n"
" \"%s\"},\n",
classname, wrappedFunctions[occ]->Name,
classname, theOccurrence->Name,
occSuffix,
theOccurrence->IsStatic ? " | METH_STATIC" : "",
vtkWrapPython_ArgCheckString(
theOccurrence->IsStatic, wrappedFunctions[occ]));
vtkWrapPython_ArgCheckString(data, theOccurrence));
if (theOccurrence->IsLegacy && !all_legacy)
{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment