DocumentObject::~DocumentObject(void) { if (!PythonObject.is(Py::_None())){ // Remark: The API of Py::Object has been changed to set whether the wrapper owns the passed // Python object or not. In the constructor we forced the wrapper to own the object so we need // not to dec'ref the Python object any more. // But we must still invalidate the Python object because it need not to be // destructed right now because the interpreter can own several references to it. Base::PyObjectBase* obj = (Base::PyObjectBase*)PythonObject.ptr(); // Call before decrementing the reference counter, otherwise a heap error can occur obj->setInvalid(); } }
PyObject *PropertyPartShape::getPyObject(void) { Base::PyObjectBase* prop; const TopoDS_Shape& sh = _Shape._Shape; if (sh.IsNull()) { prop = new TopoShapePy(new TopoShape(sh)); } else { TopAbs_ShapeEnum type = sh.ShapeType(); switch (type) { case TopAbs_COMPOUND: prop = new TopoShapeCompoundPy(new TopoShape(sh)); break; case TopAbs_COMPSOLID: prop = new TopoShapeCompSolidPy(new TopoShape(sh)); break; case TopAbs_SOLID: prop = new TopoShapeSolidPy(new TopoShape(sh)); break; case TopAbs_SHELL: prop = new TopoShapeShellPy(new TopoShape(sh)); break; case TopAbs_FACE: prop = new TopoShapeFacePy(new TopoShape(sh)); break; case TopAbs_WIRE: prop = new TopoShapeWirePy(new TopoShape(sh)); break; case TopAbs_EDGE: prop = new TopoShapeEdgePy(new TopoShape(sh)); break; case TopAbs_VERTEX: prop = new TopoShapeVertexPy(new TopoShape(sh)); break; case TopAbs_SHAPE: default: prop = new TopoShapePy(new TopoShape(sh)); break; } } if (prop) prop->setConst(); return prop; }
PyObject* Application::sListDocuments(PyObject * /*self*/, PyObject *args,PyObject * /*kwd*/) { if (!PyArg_ParseTuple(args, "")) // convert args: Python->C return NULL; // NULL triggers exception PY_TRY { PyObject *pDict = PyDict_New(); PyObject *pKey; Base::PyObjectBase* pValue; for (std::map<std::string,Document*>::const_iterator It = GetApplication().DocMap.begin(); It != GetApplication().DocMap.end();++It) { pKey = PyString_FromString(It->first.c_str()); // GetPyObject() increments pValue = static_cast<Base::PyObjectBase*>(It->second->getPyObject()); PyDict_SetItem(pDict, pKey, pValue); // now we can decrement again as PyDict_SetItem also has incremented pValue->DecRef(); } return pDict; } PY_CATCH; }
QMap<QString, CallTip> CallTipsList::extractTips(const QString& context) const { Base::PyGILStateLocker lock; QMap<QString, CallTip> tips; if (context.isEmpty()) return tips; try { Py::Module module("__main__"); Py::Dict dict = module.getDict(); #if 0 QStringList items = context.split(QLatin1Char('.')); QString modname = items.front(); items.pop_front(); if (!dict.hasKey(std::string(modname.toLatin1()))) return tips; // unknown object // get the Python object we need Py::Object obj = dict.getItem(std::string(modname.toLatin1())); while (!items.isEmpty()) { QByteArray name = items.front().toLatin1(); std::string attr = name.constData(); items.pop_front(); if (obj.hasAttr(attr)) obj = obj.getAttr(attr); else return tips; } #else // Don't use hasattr & getattr because if a property is bound to a method this will be executed twice. PyObject* code = Py_CompileString(static_cast<const char*>(context.toLatin1()), "<CallTipsList>", Py_eval_input); if (!code) { PyErr_Clear(); return tips; } PyObject* eval = 0; if (PyCode_Check(code)) { eval = PyEval_EvalCode(reinterpret_cast<PyCodeObject*>(code), dict.ptr(), dict.ptr()); } Py_DECREF(code); if (!eval) { PyErr_Clear(); return tips; } Py::Object obj(eval, true); #endif // Checks whether the type is a subclass of PyObjectBase because to get the doc string // of a member we must get it by its type instead of its instance otherwise we get the // wrong string, namely that of the type of the member. // Note: 3rd party libraries may use their own type object classes so that we cannot // reliably use Py::Type. To be on the safe side we should use Py::Object to assign // the used type object to. //Py::Object type = obj.type(); Py::Object type(PyObject_Type(obj.ptr()), true); Py::Object inst = obj; // the object instance union PyType_Object typeobj = {&Base::PyObjectBase::Type}; union PyType_Object typedoc = {&App::DocumentObjectPy::Type}; union PyType_Object basetype = {&PyBaseObject_Type}; if (PyObject_IsSubclass(type.ptr(), typedoc.o) == 1) { // From the template Python object we don't query its type object because there we keep // a list of additional methods that we won't see otherwise. But to get the correct doc // strings we query the type's dict in the class itself. // To see if we have a template Python object we check for the existence of supportedProperties if (!type.hasAttr("supportedProperties")) { obj = type; } } else if (PyObject_IsSubclass(type.ptr(), typeobj.o) == 1) { obj = type; } else if (PyInstance_Check(obj.ptr())) { // instances of old style classes PyInstanceObject* inst = reinterpret_cast<PyInstanceObject*>(obj.ptr()); PyObject* classobj = reinterpret_cast<PyObject*>(inst->in_class); obj = Py::Object(classobj); } else if (PyObject_IsInstance(obj.ptr(), basetype.o) == 1) { // New style class which can be a module, type, list, tuple, int, float, ... // Make sure it's not a type objec union PyType_Object typetype = {&PyType_Type}; if (PyObject_IsInstance(obj.ptr(), typetype.o) != 1) { // this should be now a user-defined Python class // http://stackoverflow.com/questions/12233103/in-python-at-runtime-determine-if-an-object-is-a-class-old-and-new-type-instan if (Py_TYPE(obj.ptr())->tp_flags & Py_TPFLAGS_HEAPTYPE) { obj = type; } } } // If we have an instance of PyObjectBase then determine whether it's valid or not if (PyObject_IsInstance(inst.ptr(), typeobj.o) == 1) { Base::PyObjectBase* baseobj = static_cast<Base::PyObjectBase*>(inst.ptr()); const_cast<CallTipsList*>(this)->validObject = baseobj->isValid(); } else { // PyObject_IsInstance might set an exception PyErr_Clear(); } Py::List list(obj.dir()); // If we derive from PropertyContainerPy we can search for the properties in the // C++ twin class. union PyType_Object proptypeobj = {&App::PropertyContainerPy::Type}; if (PyObject_IsSubclass(type.ptr(), proptypeobj.o) == 1) { // These are the attributes of the instance itself which are NOT accessible by // its type object extractTipsFromProperties(inst, tips); } // If we derive from App::DocumentPy we have direct access to the objects by their internal // names. So, we add these names to the list, too. union PyType_Object appdoctypeobj = {&App::DocumentPy::Type}; if (PyObject_IsSubclass(type.ptr(), appdoctypeobj.o) == 1) { App::DocumentPy* docpy = (App::DocumentPy*)(inst.ptr()); App::Document* document = docpy->getDocumentPtr(); // Make sure that the C++ object is alive if (document) { std::vector<App::DocumentObject*> objects = document->getObjects(); Py::List list; for (std::vector<App::DocumentObject*>::iterator it = objects.begin(); it != objects.end(); ++it) list.append(Py::String((*it)->getNameInDocument())); extractTipsFromObject(inst, list, tips); } } // If we derive from Gui::DocumentPy we have direct access to the objects by their internal // names. So, we add these names to the list, too. union PyType_Object guidoctypeobj = {&Gui::DocumentPy::Type}; if (PyObject_IsSubclass(type.ptr(), guidoctypeobj.o) == 1) { Gui::DocumentPy* docpy = (Gui::DocumentPy*)(inst.ptr()); if (docpy->getDocumentPtr()) { App::Document* document = docpy->getDocumentPtr()->getDocument(); // Make sure that the C++ object is alive if (document) { std::vector<App::DocumentObject*> objects = document->getObjects(); Py::List list; for (std::vector<App::DocumentObject*>::iterator it = objects.begin(); it != objects.end(); ++it) list.append(Py::String((*it)->getNameInDocument())); extractTipsFromObject(inst, list, tips); } } } // These are the attributes from the type object extractTipsFromObject(obj, list, tips); } catch (Py::Exception& e) { // Just clear the Python exception e.clear(); } return tips; }
Py::Object TopoShapeFacePy::getSurface() const { const TopoDS_Face& f = TopoDS::Face(getTopoShapePtr()->getShape()); BRepAdaptor_Surface adapt(f); Base::PyObjectBase* surface = 0; switch(adapt.GetType()) { case GeomAbs_Plane: { GeomPlane* plane = new GeomPlane(); Handle(Geom_Plane) this_surf = Handle(Geom_Plane)::DownCast (plane->handle()); this_surf->SetPln(adapt.Plane()); surface = new PlanePy(plane); break; } case GeomAbs_Cylinder: { GeomCylinder* cylinder = new GeomCylinder(); Handle(Geom_CylindricalSurface) this_surf = Handle(Geom_CylindricalSurface)::DownCast (cylinder->handle()); this_surf->SetCylinder(adapt.Cylinder()); surface = new CylinderPy(cylinder); break; } case GeomAbs_Cone: { GeomCone* cone = new GeomCone(); Handle(Geom_ConicalSurface) this_surf = Handle(Geom_ConicalSurface)::DownCast (cone->handle()); this_surf->SetCone(adapt.Cone()); surface = new ConePy(cone); break; } case GeomAbs_Sphere: { GeomSphere* sphere = new GeomSphere(); Handle(Geom_SphericalSurface) this_surf = Handle(Geom_SphericalSurface)::DownCast (sphere->handle()); this_surf->SetSphere(adapt.Sphere()); surface = new SpherePy(sphere); break; } case GeomAbs_Torus: { GeomToroid* toroid = new GeomToroid(); Handle(Geom_ToroidalSurface) this_surf = Handle(Geom_ToroidalSurface)::DownCast (toroid->handle()); this_surf->SetTorus(adapt.Torus()); surface = new ToroidPy(toroid); break; } case GeomAbs_BezierSurface: { GeomBezierSurface* surf = new GeomBezierSurface(adapt.Bezier()); surface = new BezierSurfacePy(surf); break; } case GeomAbs_BSplineSurface: { GeomBSplineSurface* surf = new GeomBSplineSurface(adapt.BSpline()); surface = new BSplineSurfacePy(surf); break; } case GeomAbs_SurfaceOfRevolution: { Handle(Geom_Surface) s = BRep_Tool::Surface(f); Handle(Geom_SurfaceOfRevolution) rev = Handle(Geom_SurfaceOfRevolution)::DownCast(s); if (rev.IsNull()) { Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); rev = Handle(Geom_SurfaceOfRevolution)::DownCast(rect->BasisSurface()); } if (!rev.IsNull()) { GeomSurfaceOfRevolution* surf = new GeomSurfaceOfRevolution(rev); surface = new SurfaceOfRevolutionPy(surf); break; } else { throw Py::RuntimeError("Failed to convert to surface of revolution"); } } case GeomAbs_SurfaceOfExtrusion: { Handle(Geom_Surface) s = BRep_Tool::Surface(f); Handle(Geom_SurfaceOfLinearExtrusion) ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(s); if (ext.IsNull()) { Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); ext = Handle(Geom_SurfaceOfLinearExtrusion)::DownCast(rect->BasisSurface()); } if (!ext.IsNull()) { GeomSurfaceOfExtrusion* surf = new GeomSurfaceOfExtrusion(ext); surface = new SurfaceOfExtrusionPy(surf); break; } else { throw Py::RuntimeError("Failed to convert to surface of extrusion"); } } case GeomAbs_OffsetSurface: { Handle(Geom_Surface) s = BRep_Tool::Surface(f); Handle(Geom_OffsetSurface) off = Handle(Geom_OffsetSurface)::DownCast(s); if (off.IsNull()) { Handle(Geom_RectangularTrimmedSurface) rect = Handle(Geom_RectangularTrimmedSurface)::DownCast(s); off = Handle(Geom_OffsetSurface)::DownCast(rect->BasisSurface()); } if (!off.IsNull()) { GeomOffsetSurface* surf = new GeomOffsetSurface(off); surface = new OffsetSurfacePy(surf); break; } else { throw Py::RuntimeError("Failed to convert to offset surface"); } } case GeomAbs_OtherSurface: break; } if (surface) { surface->setNotTracking(); return Py::asObject(surface); } throw Py::TypeError("undefined surface type"); }
QMap<QString, CallTip> CallTipsList::extractTips(const QString& context) const { Base::PyGILStateLocker lock; QMap<QString, CallTip> tips; if (context.isEmpty()) return tips; try { QStringList items = context.split(QLatin1Char('.')); Py::Module module("__main__"); Py::Dict dict = module.getDict(); QString modname = items.front(); items.pop_front(); if (!dict.hasKey(std::string(modname.toAscii()))) return tips; // unknown object // get the Python object we need Py::Object obj = dict.getItem(std::string(modname.toAscii())); while (!items.isEmpty()) { QByteArray name = items.front().toAscii(); std::string attr = name.constData(); items.pop_front(); if (obj.hasAttr(attr)) obj = obj.getAttr(attr); else return tips; } // Checks whether the type is a subclass of PyObjectBase because to get the doc string // of a member we must get it by its type instead of its instance otherwise we get the // wrong string, namely that of the type of the member. // Note: 3rd party libraries may use their own type object classes so that we cannot // reliably use Py::Type. To be on the safe side we should use Py::Object to assign // the used type object to. //Py::Object type = obj.type(); Py::Object type(PyObject_Type(obj.ptr()), true); Py::Object inst = obj; // the object instance union PyType_Object typeobj = {&Base::PyObjectBase::Type}; union PyType_Object typedoc = {&App::DocumentObjectPy::Type}; if (PyObject_IsSubclass(type.ptr(), typedoc.o) == 1) { // From the template Python object we don't query its type object because there we keep // a list of additional methods that we won't see otherwise. But to get the correct doc // strings we query the type's dict in the class itself. // To see if we have a template Python object we check for the existence of supportedProperties if (!type.hasAttr("supportedProperties")) { obj = type; } } else if (PyObject_IsSubclass(type.ptr(), typeobj.o) == 1) { obj = type; } // If we have an instance of PyObjectBase then determine whether it's valid or not if (PyObject_IsInstance(inst.ptr(), typeobj.o) == 1) { Base::PyObjectBase* baseobj = static_cast<Base::PyObjectBase*>(inst.ptr()); const_cast<CallTipsList*>(this)->validObject = baseobj->isValid(); } else { // PyObject_IsInstance might set an exception PyErr_Clear(); } Py::List list(PyObject_Dir(obj.ptr()), true); // If we derive from PropertyContainerPy we can search for the properties in the // C++ twin class. union PyType_Object proptypeobj = {&App::PropertyContainerPy::Type}; if (PyObject_IsSubclass(type.ptr(), proptypeobj.o) == 1) { // These are the attributes of the instance itself which are NOT accessible by // its type object extractTipsFromProperties(inst, tips); } // If we derive from App::DocumentPy we have direct access to the objects by their internal // names. So, we add these names to the list, too. union PyType_Object appdoctypeobj = {&App::DocumentPy::Type}; if (PyObject_IsSubclass(type.ptr(), appdoctypeobj.o) == 1) { App::DocumentPy* docpy = (App::DocumentPy*)(inst.ptr()); App::Document* document = docpy->getDocumentPtr(); // Make sure that the C++ object is alive if (document) { std::vector<App::DocumentObject*> objects = document->getObjects(); Py::List list; for (std::vector<App::DocumentObject*>::iterator it = objects.begin(); it != objects.end(); ++it) list.append(Py::String((*it)->getNameInDocument())); extractTipsFromObject(inst, list, tips); } } // If we derive from Gui::DocumentPy we have direct access to the objects by their internal // names. So, we add these names to the list, too. union PyType_Object guidoctypeobj = {&Gui::DocumentPy::Type}; if (PyObject_IsSubclass(type.ptr(), guidoctypeobj.o) == 1) { Gui::DocumentPy* docpy = (Gui::DocumentPy*)(inst.ptr()); if (docpy->getDocumentPtr()) { App::Document* document = docpy->getDocumentPtr()->getDocument(); // Make sure that the C++ object is alive if (document) { std::vector<App::DocumentObject*> objects = document->getObjects(); Py::List list; for (std::vector<App::DocumentObject*>::iterator it = objects.begin(); it != objects.end(); ++it) list.append(Py::String((*it)->getNameInDocument())); extractTipsFromObject(inst, list, tips); } } } // These are the attributes from the type object extractTipsFromObject(obj, list, tips); } catch (Py::Exception& e) { // Just clear the Python exception e.clear(); } return tips; }