From e7a3dc48e834591e5553d5c37ef997e70d177a94 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 21 Oct 2015 00:22:40 +0200 Subject: [PATCH] + support of Python feature classes without an execute() method + if execute() method of Python feature is missing or if it returns false call the execute() method of the C++ feature + fix SketchObjectPython --- src/App/FeaturePython.cpp | 40 +++++++++++++++++---------- src/App/FeaturePython.h | 12 ++++++-- src/App/FeaturePythonPyImp.inl | 4 +-- src/Mod/Sketcher/App/SketchObject.cpp | 8 ++++++ 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/src/App/FeaturePython.cpp b/src/App/FeaturePython.cpp index 6c7d845a9d03..582b760f0ae4 100644 --- a/src/App/FeaturePython.cpp +++ b/src/App/FeaturePython.cpp @@ -44,7 +44,11 @@ FeaturePythonImp::~FeaturePythonImp() { } -DocumentObjectExecReturn *FeaturePythonImp::execute() +/*! + Calls the execute() method of the Python feature class. If the Python feature class doesn't have an execute() + method or if it returns False this method also return false and true otherwise. + */ +bool FeaturePythonImp::execute() { // Run the execute method of the proxy object. Base::PyGILStateLocker lock; @@ -52,16 +56,24 @@ DocumentObjectExecReturn *FeaturePythonImp::execute() Property* proxy = object->getPropertyByName("Proxy"); if (proxy && proxy->getTypeId() == PropertyPythonObject::getClassTypeId()) { Py::Object feature = static_cast(proxy)->getValue(); - if (feature.hasAttr("__object__")) { - Py::Callable method(feature.getAttr(std::string("execute"))); - Py::Tuple args; - method.apply(args); - } - else { - Py::Callable method(feature.getAttr(std::string("execute"))); - Py::Tuple args(1); - args.setItem(0, Py::Object(object->getPyObject(), true)); - method.apply(args); + if (feature.hasAttr(std::string("execute"))) { + if (feature.hasAttr("__object__")) { + Py::Callable method(feature.getAttr(std::string("execute"))); + Py::Tuple args; + Py::Object res = method.apply(args); + if (res.isBoolean() && !res.isTrue()) + return false; + return true; + } + else { + Py::Callable method(feature.getAttr(std::string("execute"))); + Py::Tuple args(1); + args.setItem(0, Py::Object(object->getPyObject(), true)); + Py::Object res = method.apply(args); + if (res.isBoolean() && !res.isTrue()) + return false; + return true; + } } } } @@ -70,10 +82,10 @@ DocumentObjectExecReturn *FeaturePythonImp::execute() e.ReportException(); std::stringstream str; str << object->Label.getValue() << ": " << e.what(); - return new App::DocumentObjectExecReturn(str.str()); + throw Base::RuntimeError(str.str()); } - return DocumentObject::StdReturn; + return false; } void FeaturePythonImp::onBeforeChange(const Property* prop) @@ -175,5 +187,3 @@ template<> const char* App::GeometryPython::getViewProviderName(void) const { } // explicit template instantiation template class AppExport FeaturePythonT; } - - diff --git a/src/App/FeaturePython.h b/src/App/FeaturePython.h index 86247f66710e..d0bc3fc473ff 100644 --- a/src/App/FeaturePython.h +++ b/src/App/FeaturePython.h @@ -44,7 +44,7 @@ class AppExport FeaturePythonImp FeaturePythonImp(App::DocumentObject*); ~FeaturePythonImp(); - DocumentObjectExecReturn *execute(); + bool execute(); void onBeforeChange(const Property* prop); void onChanged(const Property* prop); PyObject *getPyObject(void); @@ -84,7 +84,15 @@ class FeaturePythonT : public FeatureT } /// recalculate the Feature virtual DocumentObjectExecReturn *execute(void) { - return imp->execute(); + try { + bool handled = imp->execute(); + if (!handled) + return FeatureT::execute(); + } + catch (const Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } + return DocumentObject::StdReturn; } /// returns the type name of the ViewProvider virtual const char* getViewProviderName(void) const { diff --git a/src/App/FeaturePythonPyImp.inl b/src/App/FeaturePythonPyImp.inl index 6c4f0fb2adfc..fb0e24df954f 100644 --- a/src/App/FeaturePythonPyImp.inl +++ b/src/App/FeaturePythonPyImp.inl @@ -85,12 +85,12 @@ PyMethodDef FeaturePythonPyT::Methods[] = { {"addProperty", (PyCFunction) staticCallback_addProperty, METH_VARARGS, - "addProperty(string, string) -- Add a generic property.\nThe first argument specifies the type, the second the\nname of the property.\n " + "addProperty(string, string) -- Add a generic property.\nThe first argument specifies the type, the second the\nname of the property.\n" }, {"removeProperty", (PyCFunction) staticCallback_removeProperty, METH_VARARGS, - "removeProperty(string) -- Remove a generic property.\nNote, you can only remove user-defined properties but not built-in ones.\n " + "removeProperty(string) -- Remove a generic property.\nNote, you can only remove user-defined properties but not built-in ones.\n" }, {"supportedProperties", (PyCFunction) staticCallback_supportedProperties, diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index 646321f5411f..802b9c1ee5bd 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -49,6 +49,7 @@ #include #include +#include #include #include #include @@ -4016,6 +4017,13 @@ PROPERTY_SOURCE_TEMPLATE(Sketcher::SketchObjectPython, Sketcher::SketchObject) template<> const char* Sketcher::SketchObjectPython::getViewProviderName(void) const { return "SketcherGui::ViewProviderPython"; } +template<> PyObject* Sketcher::SketchObjectPython::getPyObject(void) { + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new FeaturePythonPyT(this),true); + } + return Py::new_reference_to(PythonObject); +} /// @endcond // explicit template instantiation