diff --git a/src/App/DocumentObjectPyImp.cpp b/src/App/DocumentObjectPyImp.cpp index 99aae5b42f..adf9841a2b 100644 --- a/src/App/DocumentObjectPyImp.cpp +++ b/src/App/DocumentObjectPyImp.cpp @@ -417,28 +417,41 @@ PyObject* DocumentObjectPy::getStatusString(PyObject *args) PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds) { + enum class ReturnType { + PyObject = 0, + DocObject = 1, + DocAndPyObject = 2, + Placement = 3, + Matrix = 4, + LinkAndPlacement = 5, + LinkAndMatrix = 6 + }; + PyObject *obj; short retType = 0; - PyObject *pyMat = Py_None; + PyObject *pyMat = nullptr; PyObject *doTransform = Py_True; short depth = 0; - static char *kwlist[] = {"subname","retType","matrix","transform","depth", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hOOh", kwlist, - &obj,&retType,&pyMat,&doTransform,&depth)) + + static char *kwlist[] = {"subname", "retType", "matrix", "transform", "depth", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|hO!Oh", kwlist, + &obj, &retType, &Base::MatrixPy::Type, &pyMat, &doTransform, &depth)) return nullptr; - if (retType<0 || retType>6) { - PyErr_SetString(PyExc_TypeError, "invalid retType, can only be integer 0~6"); + if (retType < 0 || retType > 6) { + PyErr_SetString(PyExc_ValueError, "invalid retType, can only be integer 0~6"); return nullptr; } + ReturnType retEnum = ReturnType(retType); std::vector subs; - bool single=true; + bool single = true; + if (PyUnicode_Check(obj)) { subs.push_back(PyUnicode_AsUTF8(obj)); } else if (PySequence_Check(obj)) { - single=false; + single = false; Py::Sequence shapeSeq(obj); for (Py::Sequence::iterator it = shapeSeq.begin(); it != shapeSeq.end(); ++it) { PyObject* item = (*it).ptr(); @@ -467,11 +480,7 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds) }; Base::Matrix4D mat; - if(pyMat!=Py_None) { - if(!PyObject_TypeCheck(pyMat,&Base::MatrixPy::Type)) { - PyErr_SetString(PyExc_TypeError, "expect argument 'matrix' to be of type Base.Matrix"); - return nullptr; - } + if (pyMat) { mat = *static_cast(pyMat)->getMatrixPtr(); } @@ -481,70 +490,59 @@ PyObject* DocumentObjectPy::getSubObject(PyObject *args, PyObject *keywds) ret.emplace_back(mat); auto &info = ret.back(); PyObject *pyObj = nullptr; - info.sobj = getDocumentObjectPtr()->getSubObject( - sub.c_str(),retType!=0&&retType!=2?nullptr:&pyObj,&info.mat,transform,depth); - if(pyObj) - info.pyObj = Py::Object(pyObj,true); - if(info.sobj) - info.obj = Py::Object(info.sobj->getPyObject(),true); + + info.sobj = getDocumentObjectPtr()->getSubObject(sub.c_str(), + retEnum != ReturnType::PyObject && + retEnum != ReturnType::DocAndPyObject ? nullptr : &pyObj, + &info.mat, transform, depth); + if (pyObj) + info.pyObj = Py::asObject(pyObj); + if (info.sobj) + info.obj = Py::asObject(info.sobj->getPyObject()); } - if(ret.empty()) + + if (ret.empty()) Py_Return; - if(single) { - if(retType==0) - return Py::new_reference_to(ret[0].pyObj); - else if(retType==1 && pyMat==Py_None) - return Py::new_reference_to(ret[0].obj); - else if(!ret[0].sobj) - Py_Return; - else if(retType==3) - return Py::new_reference_to(Py::Placement(Base::Placement(ret[0].mat))); - else if(retType==4) - return Py::new_reference_to(Py::Matrix(ret[0].mat)); - else if(retType==5 || retType==6) { - ret[0].sobj->getLinkedObject(true,&ret[0].mat,false); - if(retType==5) - return Py::new_reference_to(Py::Placement(Base::Placement(ret[0].mat))); + auto getReturnValue = [retEnum, pyMat](SubInfo& ret) -> Py::Object { + if (retEnum == ReturnType::PyObject) + return ret.pyObj; + else if (retEnum == ReturnType::DocObject && !pyMat) + return ret.obj; + else if (!ret.sobj) + return Py::None(); + else if (retEnum == ReturnType::Placement) + return Py::Placement(Base::Placement(ret.mat)); + else if (retEnum == ReturnType::Matrix) + return Py::Matrix(ret.mat); + else if (retEnum == ReturnType::LinkAndPlacement || retEnum == ReturnType::LinkAndMatrix) { + ret.sobj->getLinkedObject(true, &ret.mat, false); + if (retEnum == ReturnType::LinkAndPlacement) + return Py::Placement(Base::Placement(ret.mat)); else - return Py::new_reference_to(Py::Matrix(ret[0].mat)); + return Py::Matrix(ret.mat); } - Py::Tuple rret(retType==1?2:3); - rret.setItem(0,ret[0].obj); - rret.setItem(1,Py::asObject(new Base::MatrixPy(ret[0].mat))); - if(retType!=1) - rret.setItem(2,ret[0].pyObj); - return Py::new_reference_to(rret); + else { + Py::Tuple rret(retEnum == ReturnType::DocObject ? 2 : 3); + rret.setItem(0, ret.obj); + rret.setItem(1, Py::asObject(new Base::MatrixPy(ret.mat))); + if (retEnum != ReturnType::DocObject) + rret.setItem(2, ret.pyObj); + return rret; + } + }; + + if (single) { + return Py::new_reference_to(getReturnValue(ret[0])); } + Py::Tuple tuple(ret.size()); - for(size_t i=0;igetLinkedObject(true,&ret[i].mat,false); - if(retType==5) - tuple.setItem(i,Py::Placement(Base::Placement(ret[i].mat))); - else - tuple.setItem(i,Py::Matrix(ret[i].mat)); - } else { - Py::Tuple rret(retType==1?2:3); - rret.setItem(0,ret[i].obj); - rret.setItem(1,Py::asObject(new Base::MatrixPy(ret[i].mat))); - if(retType!=1) - rret.setItem(2,ret[i].pyObj); - tuple.setItem(i,rret); - } + for(size_t i=0; i