App: fix DocumentObjectPy::getSubObject:

* do not set pyMat to Py_None by default but nullptr and do type check in PyArg_ParseTupleAndKeywords
* if refType is out of range raise a ValueError instead of TypeError
* replace (undocumented) magic numbers with an enum class
* implement a lambda function to avoid code duplication
* fix bug for retType=3 or retType=4 if subname is a list of strings
This commit is contained in:
wmayer
2022-05-14 15:54:27 +02:00
parent 6340dcdd63
commit eb6adf17fa

View File

@@ -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<std::string> 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<Base::MatrixPy*>(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;i<ret.size();++i) {
if(retType==0)
tuple.setItem(i,ret[i].pyObj);
else if(retType==1 && pyMat==Py_None)
tuple.setItem(i,ret[i].obj);
else if(!ret[i].sobj)
tuple.setItem(i, Py::Object());
else if(retType==3)
tuple.setItem(i,Py::Placement(Base::Placement(ret[0].mat)));
else if(retType==4)
tuple.setItem(i,Py::Matrix(ret[0].mat));
else if(retType==5 || retType==6) {
ret[i].sobj->getLinkedObject(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<ret.size(); ++i) {
tuple.setItem(i, getReturnValue(ret[i]));
}
return Py::new_reference_to(tuple);
}PY_CATCH
}
PY_CATCH
}
PyObject* DocumentObjectPy::getSubObjectList(PyObject *args) {