/*========================================================================= Program: Visualization Toolkit Module: vtkPythonUtil.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkPythonUtil.h" #include "vtkPythonOverload.h" #include "vtkSystemIncludes.h" #include "vtkObject.h" #include "vtkPythonCommand.h" #include "vtkSmartPointerBase.h" #include "vtkStdString.h" #include "vtkToolkits.h" #include "vtkUnicodeString.h" #include "vtkVariant.h" #include "vtkWeakPointer.h" #include "vtkWindows.h" #include #include #include #include #include #include #ifdef VTK_WRAP_PYTHON_SIP #include "sip.h" #endif // for uintptr_t #ifdef _MSC_VER #include #else #include #endif //-------------------------------------------------------------------- // A ghost object, can be used to recreate a deleted PyVTKObject class PyVTKObjectGhost { public: PyVTKObjectGhost() : vtk_ptr(), vtk_class(nullptr), vtk_dict(nullptr) {}; vtkWeakPointerBase vtk_ptr; PyTypeObject *vtk_class; PyObject *vtk_dict; }; //-------------------------------------------------------------------- // There are six maps associated with the Python wrappers // Map VTK objects to python objects (this is also the cornerstone // of the vtk/python garbage collection system, because it contains // exactly one pointer reference for each VTK object known to python) class vtkPythonObjectMap : public std::map > { public: ~vtkPythonObjectMap(); void add(vtkObjectBase* key, PyObject* value); void remove(vtkObjectBase* key); }; // Call Delete instead of relying on vtkSmartPointer, so that crashes // caused by deletion are easier to follow in the debug stack trace vtkPythonObjectMap::~vtkPythonObjectMap() { iterator i; for (i = this->begin(); i != this->end(); ++i) { for (int j = 0; j < i->second.second; ++j) { i->first->Delete(); } } } void vtkPythonObjectMap::add(vtkObjectBase* key, PyObject* value) { key->Register(nullptr); iterator i = this->find(key); if (i == this->end()) { (*this)[key] = std::make_pair(value, 1); } else { i->second.first = value; ++i->second.second; } } void vtkPythonObjectMap::remove(vtkObjectBase* key) { iterator i = this->find(key); if (i != this->end()) { // Save the object. The iterator will become invalid if the iterator is // erased. vtkObjectBase* obj = i->first; // Remove it from the map if necessary. if (!--i->second.second) { this->erase(i); } // Remove a reference to the object. This must be done *after* removing it // from the map (if needed) because if there's a callback which reacts when // the reference is dropped, it might call RemoveObjectFromMap as well. If // it still exists in the map at that point, this becomes an infinite loop. obj->Delete(); } } // Keep weak pointers to VTK objects that python no longer has // references to. Python keeps the python 'dict' for VTK objects // even when they pass leave the python realm, so that if those // VTK objects come back, their 'dict' can be restored to them. // Periodically the weak pointers are checked and the dicts of // VTK objects that have been deleted are tossed away. class vtkPythonGhostMap : public std::map { }; // Keep track of all the VTK classes that python knows about. class vtkPythonClassMap : public std::map { }; // Like the ClassMap, for types not derived from vtkObjectBase. class vtkPythonSpecialTypeMap : public std::map { }; // Keep track of all the C++ namespaces that have been wrapped. class vtkPythonNamespaceMap : public std::map { }; // Keep track of all the C++ enums that have been wrapped. class vtkPythonEnumMap : public std::map { }; // Keep track of all vtkPythonCommand instances. class vtkPythonCommandList : public std::vector > { public: ~vtkPythonCommandList() { iterator iter; for (iter = this->begin(); iter != this->end(); ++iter) { if (iter->GetPointer()) { iter->GetPointer()->obj = nullptr; iter->GetPointer()->ThreadState = nullptr; } } } void findAndErase(vtkPythonCommand* ptr) { this->erase(std::remove(this->begin(), this->end(), ptr), this->end()); } }; //-------------------------------------------------------------------- // The singleton for vtkPythonUtil static vtkPythonUtil *vtkPythonMap = nullptr; // destructs the singleton when python exits void vtkPythonUtilDelete() { delete vtkPythonMap; vtkPythonMap = nullptr; } // constructs the singleton void vtkPythonUtilCreateIfNeeded() { if (vtkPythonMap == nullptr) { vtkPythonMap = new vtkPythonUtil(); Py_AtExit(vtkPythonUtilDelete); } } //-------------------------------------------------------------------- vtkPythonUtil::vtkPythonUtil() { this->ObjectMap = new vtkPythonObjectMap; this->GhostMap = new vtkPythonGhostMap; this->ClassMap = new vtkPythonClassMap; this->SpecialTypeMap = new vtkPythonSpecialTypeMap; this->NamespaceMap = new vtkPythonNamespaceMap; this->EnumMap = new vtkPythonEnumMap; this->PythonCommandList = new vtkPythonCommandList; } //-------------------------------------------------------------------- vtkPythonUtil::~vtkPythonUtil() { delete this->ObjectMap; delete this->GhostMap; delete this->ClassMap; delete this->SpecialTypeMap; delete this->NamespaceMap; delete this->EnumMap; delete this->PythonCommandList; } //-------------------------------------------------------------------- void vtkPythonUtil::RegisterPythonCommand(vtkPythonCommand* cmd) { if (cmd) { vtkPythonUtilCreateIfNeeded(); vtkPythonMap->PythonCommandList->push_back(cmd); } } //-------------------------------------------------------------------- void vtkPythonUtil::UnRegisterPythonCommand(vtkPythonCommand* cmd) { if (cmd && vtkPythonMap) { vtkPythonMap->PythonCommandList->findAndErase(cmd); } } //-------------------------------------------------------------------- PyVTKSpecialType *vtkPythonUtil::AddSpecialTypeToMap( PyTypeObject *pytype, PyMethodDef *methods, PyMethodDef *constructors, vtkcopyfunc copyfunc) { const char *classname = vtkPythonUtil::StripModule(pytype->tp_name); vtkPythonUtilCreateIfNeeded(); #ifdef VTKPYTHONDEBUG // vtkGenericWarningMacro("Adding an type " << type << " to map ptr"); #endif // lets make sure it isn't already there vtkPythonSpecialTypeMap::iterator i = vtkPythonMap->SpecialTypeMap->find(classname); if (i != vtkPythonMap->SpecialTypeMap->end()) { return nullptr; } i = vtkPythonMap->SpecialTypeMap->insert(i, vtkPythonSpecialTypeMap::value_type( classname, PyVTKSpecialType(pytype, methods, constructors, copyfunc))); #ifdef VTKPYTHONDEBUG // vtkGenericWarningMacro("Added type to map type = " << typeObject); #endif return &i->second; } //-------------------------------------------------------------------- PyVTKSpecialType *vtkPythonUtil::FindSpecialType(const char *classname) { if (vtkPythonMap) { vtkPythonSpecialTypeMap::iterator it = vtkPythonMap->SpecialTypeMap->find(classname); if (it != vtkPythonMap->SpecialTypeMap->end()) { return &it->second; } } return nullptr; } //-------------------------------------------------------------------- void vtkPythonUtil::AddObjectToMap(PyObject *obj, vtkObjectBase *ptr) { vtkPythonUtilCreateIfNeeded(); #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Adding an object to map ptr = " << ptr); #endif ((PyVTKObject *)obj)->vtk_ptr = ptr; vtkPythonMap->ObjectMap->add(ptr, obj); #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Added object to map obj= " << obj << " " << ptr); #endif } //-------------------------------------------------------------------- void vtkPythonUtil::RemoveObjectFromMap(PyObject *obj) { PyVTKObject *pobj = (PyVTKObject *)obj; #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Deleting an object from map obj = " << pobj << " " << pobj->vtk_ptr); #endif if (vtkPythonMap && vtkPythonMap->ObjectMap->count(pobj->vtk_ptr)) { vtkWeakPointerBase wptr; // check for customized class or dict if (pobj->vtk_class->py_type != Py_TYPE(pobj) || PyDict_Size(pobj->vtk_dict)) { wptr = pobj->vtk_ptr; } vtkPythonMap->ObjectMap->remove(pobj->vtk_ptr); // if the VTK object still exists, then make a ghost if (wptr.GetPointer()) { // List of attrs to be deleted std::vector delList; // Erase ghosts of VTK objects that have been deleted vtkPythonGhostMap::iterator i = vtkPythonMap->GhostMap->begin(); while (i != vtkPythonMap->GhostMap->end()) { if (!i->second.vtk_ptr.GetPointer()) { delList.push_back((PyObject *)i->second.vtk_class); delList.push_back(i->second.vtk_dict); vtkPythonMap->GhostMap->erase(i++); } else { ++i; } } // Add this new ghost to the map PyVTKObjectGhost &g = (*vtkPythonMap->GhostMap)[pobj->vtk_ptr]; g.vtk_ptr = wptr; g.vtk_class = Py_TYPE(pobj); g.vtk_dict = pobj->vtk_dict; Py_INCREF(g.vtk_class); Py_INCREF(g.vtk_dict); // Delete attrs of erased objects. Must be done at the end. for (size_t j = 0; j < delList.size(); j++) { Py_DECREF(delList[j]); } } } } //-------------------------------------------------------------------- PyObject *vtkPythonUtil::FindObject(vtkObjectBase *ptr) { PyObject *obj = nullptr; if (ptr && vtkPythonMap) { vtkPythonObjectMap::iterator i = vtkPythonMap->ObjectMap->find(ptr); if (i != vtkPythonMap->ObjectMap->end()) { obj = i->second.first; } if (obj) { Py_INCREF(obj); return obj; } } else { Py_INCREF(Py_None); return Py_None; } // search weak list for object, resurrect if it is there vtkPythonGhostMap::iterator j = vtkPythonMap->GhostMap->find(ptr); if (j != vtkPythonMap->GhostMap->end()) { if (j->second.vtk_ptr.GetPointer()) { obj = PyVTKObject_FromPointer( j->second.vtk_class, j->second.vtk_dict, ptr); } Py_DECREF(j->second.vtk_class); Py_DECREF(j->second.vtk_dict); vtkPythonMap->GhostMap->erase(j); } return obj; } //-------------------------------------------------------------------- PyObject *vtkPythonUtil::GetObjectFromPointer(vtkObjectBase *ptr) { PyObject *obj = vtkPythonUtil::FindObject(ptr); if (obj == nullptr) { // create a new object PyVTKClass *vtkclass = nullptr; vtkPythonClassMap::iterator k = vtkPythonMap->ClassMap->find(ptr->GetClassName()); if (k != vtkPythonMap->ClassMap->end()) { vtkclass = &k->second; } // if the class was not in the map, then find the nearest base class // that is, and associate ptr->GetClassName() with that base class if (vtkclass == nullptr) { const char *classname = ptr->GetClassName(); vtkclass = vtkPythonUtil::FindNearestBaseClass(ptr); vtkPythonClassMap::iterator i = vtkPythonMap->ClassMap->find(classname); if (i == vtkPythonMap->ClassMap->end()) { vtkPythonMap->ClassMap->insert( i, vtkPythonClassMap::value_type(classname, *vtkclass)); } } obj = PyVTKObject_FromPointer(vtkclass->py_type, nullptr, ptr); } return obj; } //-------------------------------------------------------------------- const char *vtkPythonUtil::PythonicClassName(const char *classname) { const char *cp = classname; /* check for non-alphanumeric chars */ if (isalpha(*cp) || *cp == '_') { do { cp++; } while (isalnum(*cp) || *cp == '_'); } if (*cp != '\0') { /* look up class and get its pythonic name */ PyVTKClass *o = vtkPythonUtil::FindClass(classname); if (o) { classname = vtkPythonUtil::StripModule(o->py_type->tp_name); } } return classname; } //-------------------------------------------------------------------- const char *vtkPythonUtil::StripModule(const char *tpname) { const char *cp = tpname; while (*cp != '.' && *cp != '\0') { cp++; } if (*cp == '.') { return ++cp; } return tpname; } //-------------------------------------------------------------------- PyVTKClass *vtkPythonUtil::AddClassToMap( PyTypeObject *pytype, PyMethodDef *methods, const char *classname, vtknewfunc constructor) { vtkPythonUtilCreateIfNeeded(); // lets make sure it isn't already there vtkPythonClassMap::iterator i = vtkPythonMap->ClassMap->find(classname); if (i != vtkPythonMap->ClassMap->end()) { return nullptr; } i = vtkPythonMap->ClassMap->insert(i, vtkPythonClassMap::value_type( classname, PyVTKClass(pytype, methods, classname, constructor))); return &i->second; } //-------------------------------------------------------------------- PyVTKClass *vtkPythonUtil::FindClass(const char *classname) { if (vtkPythonMap) { vtkPythonClassMap::iterator it = vtkPythonMap->ClassMap->find(classname); if (it != vtkPythonMap->ClassMap->end()) { return &it->second; } } return nullptr; } //-------------------------------------------------------------------- // this is a helper function to find the nearest base class for an // object whose class is not in the ClassDict PyVTKClass *vtkPythonUtil::FindNearestBaseClass(vtkObjectBase *ptr) { PyVTKClass *nearestbase = nullptr; int maxdepth = 0; int depth; for (vtkPythonClassMap::iterator classes = vtkPythonMap->ClassMap->begin(); classes != vtkPythonMap->ClassMap->end(); ++classes) { PyVTKClass *pyclass = &classes->second; if (ptr->IsA(pyclass->vtk_name)) { PyTypeObject *base = pyclass->py_type->tp_base; // count the hierarchy depth for this class for (depth = 0; base != nullptr; depth++) { base = base->tp_base; } // we want the class that is furthest from vtkObjectBase if (depth > maxdepth) { maxdepth = depth; nearestbase = pyclass; } } } return nearestbase; } //-------------------------------------------------------------------- vtkObjectBase *vtkPythonUtil::GetPointerFromObject( PyObject *obj, const char *result_type) { vtkObjectBase *ptr; // convert Py_None to nullptr every time if (obj == Py_None) { return nullptr; } // check to ensure it is a vtk object if (!PyVTKObject_Check(obj)) { obj = PyObject_GetAttrString(obj, "__vtk__"); if (obj) { PyObject *arglist = Py_BuildValue("()"); PyObject *result = PyEval_CallObject(obj, arglist); Py_DECREF(arglist); Py_DECREF(obj); if (result == nullptr) { return nullptr; } if (!PyVTKObject_Check(result)) { PyErr_SetString(PyExc_TypeError, "__vtk__() doesn't return a VTK object"); Py_DECREF(result); return nullptr; } else { ptr = ((PyVTKObject *)result)->vtk_ptr; Py_DECREF(result); } } else { #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Object " << obj << " is not a VTK object!!"); #endif PyErr_SetString(PyExc_TypeError, "method requires a VTK object"); return nullptr; } } else { ptr = ((PyVTKObject *)obj)->vtk_ptr; } #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Checking into obj " << obj << " ptr = " << ptr); #endif if (ptr->IsA(result_type)) { #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("Got obj= " << obj << " ptr= " << ptr << " " << result_type); #endif return ptr; } else { char error_string[2048]; #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("vtk bad argument, type conversion failed."); #endif snprintf(error_string, sizeof(error_string), "method requires a %.500s, a %.500s was provided.", vtkPythonUtil::PythonicClassName(result_type), vtkPythonUtil::PythonicClassName( ((vtkObjectBase *)ptr)->GetClassName())); PyErr_SetString(PyExc_TypeError, error_string); return nullptr; } } //---------------- // union of long int and pointer union vtkPythonUtilPointerUnion { void *p; uintptr_t l; }; //---------------- // union of long int and pointer union vtkPythonUtilConstPointerUnion { const void *p; uintptr_t l; }; //-------------------------------------------------------------------- PyObject *vtkPythonUtil::GetObjectFromObject( PyObject *arg, const char *type) { union vtkPythonUtilPointerUnion u; PyObject *tmp = nullptr; #ifdef Py_USING_UNICODE if (PyUnicode_Check(arg)) { tmp = PyUnicode_AsUTF8String(arg); arg = tmp; } #endif if (PyBytes_Check(arg)) { vtkObjectBase *ptr; char *ptrText = PyBytes_AsString(arg); char typeCheck[1024]; // typeCheck is currently not used unsigned long long l; int i = sscanf(ptrText,"_%llx_%s", &l, typeCheck); u.l = static_cast(l); if (i <= 0) { i = sscanf(ptrText,"Addr=0x%llx", &l); u.l = static_cast(l); } if (i <= 0) { i = sscanf(ptrText, "%p", &u.p); } if (i <= 0) { Py_XDECREF(tmp); PyErr_SetString(PyExc_ValueError, "could not extract hexadecimal address from argument string"); return nullptr; } ptr = static_cast(u.p); if (!ptr->IsA(type)) { char error_string[2048]; snprintf(error_string,sizeof(error_string),"method requires a %.500s address, a %.500s address was provided.", type, ptr->GetClassName()); Py_XDECREF(tmp); PyErr_SetString(PyExc_TypeError, error_string); return nullptr; } Py_XDECREF(tmp); return vtkPythonUtil::GetObjectFromPointer(ptr); } Py_XDECREF(tmp); PyErr_SetString(PyExc_TypeError, "method requires a string argument"); return nullptr; } //-------------------------------------------------------------------- void *vtkPythonUtil::GetPointerFromSpecialObject( PyObject *obj, const char *result_type, PyObject **newobj) { if (vtkPythonMap == nullptr) { PyErr_SetString(PyExc_TypeError, "method requires a vtkPythonMap"); return nullptr; } const char *object_type = vtkPythonUtil::StripModule(Py_TYPE(obj)->tp_name); // do a lookup on the desired type vtkPythonSpecialTypeMap::iterator it = vtkPythonMap->SpecialTypeMap->find(result_type); if (it != vtkPythonMap->SpecialTypeMap->end()) { PyVTKSpecialType *info = &it->second; // 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 PyObject *sobj = nullptr; PyMethodDef *meth = vtkPythonOverload::FindConversionMethod(info->vtk_constructors, obj); // If a constructor signature exists for "obj", call it if (meth && meth->ml_meth) { PyObject *args = PyTuple_New(1); PyTuple_SET_ITEM(args, 0, obj); Py_INCREF(obj); sobj = meth->ml_meth(nullptr, args); Py_DECREF(args); } if (sobj && newobj) { *newobj = sobj; return ((PyVTKSpecialObject *)sobj)->vtk_ptr; } else if (sobj) { char error_text[2048]; Py_DECREF(sobj); snprintf(error_text, sizeof(error_text), "cannot pass %.500s as a non-const %.500s reference", object_type, result_type); PyErr_SetString(PyExc_TypeError, error_text); return nullptr; } // If a TypeError occurred, clear it and set our own error PyObject *ex = PyErr_Occurred(); if (ex != nullptr) { if (PyErr_GivenExceptionMatches(ex, PyExc_TypeError)) { PyErr_Clear(); } else { return nullptr; } } } #ifdef VTKPYTHONDEBUG vtkGenericWarningMacro("vtk bad argument, type conversion failed."); #endif char error_string[2048]; snprintf(error_string, sizeof(error_string), "method requires a %.500s, a %.500s was provided.", result_type, object_type); PyErr_SetString(PyExc_TypeError, error_string); return nullptr; } //-------------------------------------------------------------------- void vtkPythonUtil::AddNamespaceToMap(PyObject *module) { if (!PyVTKNamespace_Check(module)) { return; } vtkPythonUtilCreateIfNeeded(); const char *name = PyVTKNamespace_GetName(module); // let's make sure it isn't already there vtkPythonNamespaceMap::iterator i = vtkPythonMap->NamespaceMap->find(name); if (i != vtkPythonMap->NamespaceMap->end()) { return; } (*vtkPythonMap->NamespaceMap)[name] = module; } //-------------------------------------------------------------------- // This method is called from PyVTKNamespace_Delete void vtkPythonUtil::RemoveNamespaceFromMap(PyObject *obj) { if (vtkPythonMap && PyVTKNamespace_Check(obj)) { const char *name = PyVTKNamespace_GetName(obj); vtkPythonNamespaceMap::iterator it = vtkPythonMap->NamespaceMap->find(name); if (it != vtkPythonMap->NamespaceMap->end() && it->second == obj) { // The map has a pointer to the object, but does not hold a // reference, therefore there is no decref. vtkPythonMap->NamespaceMap->erase(it); } } } //-------------------------------------------------------------------- PyObject *vtkPythonUtil::FindNamespace(const char *name) { if (vtkPythonMap) { vtkPythonNamespaceMap::iterator it = vtkPythonMap->NamespaceMap->find(name); if (it != vtkPythonMap->NamespaceMap->end()) { return it->second; } } return nullptr; } //-------------------------------------------------------------------- void vtkPythonUtil::AddEnumToMap(PyTypeObject *enumtype) { vtkPythonUtilCreateIfNeeded(); // Only add to map if it isn't already there const char *enumname = vtkPythonUtil::StripModule(enumtype->tp_name); vtkPythonEnumMap::iterator i = vtkPythonMap->EnumMap->find(StripModule(enumname)); if (i == vtkPythonMap->EnumMap->end()) { (*vtkPythonMap->EnumMap)[enumname] = enumtype; } } //-------------------------------------------------------------------- PyTypeObject *vtkPythonUtil::FindEnum(const char *name) { PyTypeObject *pytype = nullptr; 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) { static char ptrText[128]; int ndigits = 2*(int)sizeof(void *); union vtkPythonUtilConstPointerUnion u; u.p = ptr; snprintf(ptrText, sizeof(ptrText), "_%*.*llx_%s", ndigits, ndigits, static_cast(u.l), type); return ptrText; } //-------------------------------------------------------------------- // unmangle a void pointer from a SWIG-style string void *vtkPythonUtil::UnmanglePointer(char *ptrText, int *len, const char *type) { int i; union vtkPythonUtilPointerUnion u; char text[1024]; char typeCheck[1024]; typeCheck[0] = '\0'; // Do some minimal checks that it might be a swig pointer. if (*len < 256 && *len > 4 && ptrText[0] == '_') { strncpy(text, ptrText, *len); text[*len] = '\0'; i = *len; // Allow one null byte, in case trailing null is part of *len if (i > 0 && text[i-1] == '\0') { i--; } // Verify that there are no other null bytes while (i > 0 && text[i-1] != '\0') { i--; } // If no null bytes, then do a full check for a swig pointer if (i == 0) { unsigned long long l; i = sscanf(text, "_%llx_%s", &l ,typeCheck); u.l = static_cast(l); if (strcmp(type,typeCheck) == 0) { // successfully unmangle *len = 0; return u.p; } else if (i == 2) { // mangled pointer of wrong type *len = -1; return nullptr; } } } // couldn't unmangle: return string as void pointer if it didn't look // like a SWIG mangled pointer return (void *)ptrText; } //-------------------------------------------------------------------- Py_hash_t vtkPythonUtil::VariantHash(const vtkVariant *v) { Py_hash_t h = -1; // This uses the same rules as the vtkVariant "==" operator. // All types except for vtkObject are converted to strings. // Quite inefficient, but it gets the job done. Fortunately, // the python vtkVariant is immutable, so its hash can be cached. switch (v->GetType()) { case VTK_OBJECT: { h = _Py_HashPointer(v->ToVTKObject()); break; } #ifdef Py_USING_UNICODE case VTK_UNICODE_STRING: { vtkUnicodeString u = v->ToUnicodeString(); const char *s = u.utf8_str(); PyObject *tmp = PyUnicode_DecodeUTF8(s, strlen(s), "strict"); if (tmp == nullptr) { PyErr_Clear(); return 0; } h = PyObject_Hash(tmp); Py_DECREF(tmp); break; } #endif default: { vtkStdString s = v->ToString(); PyObject *tmp = PyString_FromString(s.c_str()); h = PyObject_Hash(tmp); Py_DECREF(tmp); break; } } return h; } //-------------------------------------------------------------------- void vtkPythonVoidFunc(void *arg) { PyObject *arglist, *result; PyObject *func = (PyObject *)arg; // Sometimes it is possible for the function to be invoked after // Py_Finalize is called, this will cause nasty errors so we return if // the interpreter is not initialized. if (Py_IsInitialized() == 0) { return; } #ifndef VTK_NO_PYTHON_THREADS vtkPythonScopeGilEnsurer gilEnsurer(true); #endif arglist = Py_BuildValue("()"); result = PyEval_CallObject(func, arglist); Py_DECREF(arglist); if (result) { Py_XDECREF(result); } else { if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { cerr << "Caught a Ctrl-C within python, exiting program.\n"; Py_Exit(1); } PyErr_Print(); } } //-------------------------------------------------------------------- void vtkPythonVoidFuncArgDelete(void *arg) { PyObject *func = (PyObject *)arg; // Sometimes it is possible for the function to be invoked after // Py_Finalize is called, this will cause nasty errors so we return if // the interpreter is not initialized. if (Py_IsInitialized() == 0) { return; } #ifndef VTK_NO_PYTHON_THREADS vtkPythonScopeGilEnsurer gilEnsurer(true); #endif if (func) { Py_DECREF(func); } } #ifdef VTK_WRAP_PYTHON_SIP // utilities to provide access to Python objects wrapped with SIP static const sipAPIDef *get_sip_api() { static sipAPIDef *sip_api = nullptr; if(!sip_api) { PyObject *c_api = nullptr; PyObject *sip_module; PyObject *sip_module_dict; /* Import the SIP module. */ sip_module = PyImport_ImportModule("sip"); if (sip_module == nullptr) { return nullptr; } /* Get the module's dictionary. */ sip_module_dict = PyModule_GetDict(sip_module); /* Get the "_C_API" attribute. */ c_api = PyDict_GetItemString(sip_module_dict, "_C_API"); if (c_api == nullptr) { return nullptr; } /* Sanity check that it is the right type. */ if (PyCObject_Check(c_api)) sip_api = (sipAPIDef *)PyCObject_AsVoidPtr(c_api); /* some versions of SIP use PyCapsule instead of PyCObject */ #if PY_VERSION_HEX >= 0x02070000 if (PyCapsule_CheckExact(c_api)) { sip_api = (sipAPIDef *)PyCapsule_GetPointer(c_api, "sip._C_API"); } #endif } /* Get the actual pointer from the object. */ return sip_api; } #endif void* vtkPythonUtil::SIPGetPointerFromObject(PyObject *obj, const char *classname) { #ifdef VTK_WRAP_PYTHON_SIP char etext[512]; const sipAPIDef * api = get_sip_api(); if(!api) { snprintf(etext, sizeof(etext), "unable to convert to %.200s without SIP api", classname); PyErr_SetString(PyExc_TypeError, etext); return nullptr; } const sipTypeDef * td = api->api_find_type(classname); if(!td) { snprintf(etext, sizeof(etext), "unable to convert to %.200s without a typedef", classname); PyErr_SetString(PyExc_TypeError, etext); return nullptr; } if(sipTypeIsEnum(td)) { if (!api->api_can_convert_to_enum(obj, td)) { snprintf(etext, sizeof(etext), "unable to convert to %.200s enum", classname); PyErr_SetString(PyExc_TypeError, etext); return nullptr; } // Call PyInt_AsLong() to retrieve the value return obj; } if(!api->api_can_convert_to_type(obj, td, 0)) { snprintf(etext, sizeof(etext), "unable to convert to %.200s", classname); PyErr_SetString(PyExc_TypeError, etext); return nullptr; } int iserr = 0; void* ptr = api->api_convert_to_type(obj, td, nullptr, 0, nullptr, &iserr); if(iserr) { snprintf(etext, sizeof(etext), "error while converting to %.200s", classname); PyErr_SetString(PyExc_TypeError, etext); return nullptr; } return ptr; #else (void)obj; (void)classname; PyErr_SetString(PyExc_TypeError, "method requires VTK built with SIP support"); return nullptr; #endif } PyObject* vtkPythonUtil::SIPGetObjectFromPointer(const void *ptr, const char* classname, bool is_new) { #ifdef VTK_WRAP_PYTHON_SIP const sipAPIDef * api = get_sip_api(); if(!api) { PyErr_SetString(PyExc_TypeError, "Unable to convert to SIP type without api"); return nullptr; } const sipTypeDef * td = api->api_find_type(classname); if(!td) { PyErr_SetString(PyExc_TypeError, "Unable to convert to SIP type without typedef"); return nullptr; } if(sipTypeIsEnum(td)) { size_t v = reinterpret_cast(ptr); return api->api_convert_from_enum(v, td); } if(is_new) { return api->api_convert_from_new_type(const_cast(ptr), td, nullptr); } return api->api_convert_from_type(const_cast(ptr), td, nullptr); #else (void)ptr; (void)classname; (void)is_new; PyErr_SetString(PyExc_TypeError, "method requires VTK built with SIP support"); return nullptr; #endif }