move handling of dynamic properties from FeaturePythonPyT to DocumentObjectPy
This commit is contained in:
parent
07a2182674
commit
76279882da
|
@ -257,13 +257,42 @@ PyObject* DocumentObjectPy::setExpression(PyObject * args)
|
|||
}
|
||||
|
||||
|
||||
PyObject *DocumentObjectPy::getCustomAttributes(const char* /*attr*/) const
|
||||
PyObject *DocumentObjectPy::getCustomAttributes(const char* attr) const
|
||||
{
|
||||
return 0;
|
||||
// search for dynamic property
|
||||
Property* prop = getDocumentObjectPtr()->getDynamicPropertyByName(attr);
|
||||
if (prop)
|
||||
return prop->getPyObject();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DocumentObjectPy::setCustomAttributes(const char* attr, PyObject *obj)
|
||||
{
|
||||
// explicitly search for dynamic property
|
||||
try {
|
||||
Property* prop = getDocumentObjectPtr()->getDynamicPropertyByName(attr);
|
||||
if (prop) {
|
||||
prop->setPyObject(obj);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch (Base::ValueError &exc) {
|
||||
std::stringstream s;
|
||||
s << "Property '" << attr << "': " << exc.what();
|
||||
throw Py::ValueError(s.str());
|
||||
}
|
||||
catch (Base::Exception &exc) {
|
||||
std::stringstream s;
|
||||
s << "Attribute (Name: " << attr << ") error: '" << exc.what() << "' ";
|
||||
throw Py::AttributeError(s.str());
|
||||
}
|
||||
catch (...) {
|
||||
std::stringstream s;
|
||||
s << "Unknown error in attribute " << attr;
|
||||
throw Py::AttributeError(s.str());
|
||||
}
|
||||
|
||||
// search in PropertyList
|
||||
Property *prop = getDocumentObjectPtr()->getPropertyByName(attr);
|
||||
if (prop) {
|
||||
|
|
|
@ -31,8 +31,9 @@
|
|||
#include <Base/Interpreter.h>
|
||||
#include <Base/Reader.h>
|
||||
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include "FeaturePython.h"
|
||||
#include "FeaturePythonPyImp.h"
|
||||
#include "FeaturePythonPyImp.h"
|
||||
|
||||
using namespace App;
|
||||
|
||||
|
@ -192,7 +193,7 @@ PyObject *FeaturePythonImp::getPyObject(void)
|
|||
// ---------------------------------------------------------
|
||||
|
||||
namespace App {
|
||||
PROPERTY_SOURCE_TEMPLATE(App::FeaturePython, App::DocumentObject)
|
||||
PROPERTY_SOURCE_TEMPLATE(App::FeaturePython, App::DocumentObject)
|
||||
template<> const char* App::FeaturePython::getViewProviderName(void) const {
|
||||
return "Gui::ViewProviderPythonFeature";
|
||||
}
|
||||
|
@ -208,11 +209,11 @@ template class AppExport FeaturePythonT<DocumentObject>;
|
|||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
|
||||
|
||||
namespace App {
|
||||
PROPERTY_SOURCE_TEMPLATE(App::GeometryPython, App::GeoFeature)
|
||||
PROPERTY_SOURCE_TEMPLATE(App::GeometryPython, App::GeoFeature)
|
||||
template<> const char* App::GeometryPython::getViewProviderName(void) const {
|
||||
return "Gui::ViewProviderPythonGeometry";
|
||||
}
|
||||
// explicit template instantiation
|
||||
template class AppExport FeaturePythonT<GeoFeature>;
}
|
||||
template class AppExport FeaturePythonT<GeoFeature>;}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <Base/Console.h>
|
||||
#include <App/DocumentObjectPy.h>
|
||||
#include <App/PropertyContainerPy.h>
|
||||
|
||||
namespace App
|
||||
{
|
||||
|
@ -39,21 +39,15 @@ class FeaturePythonPyT : public FeaturePyT
|
|||
{
|
||||
public:
|
||||
static PyTypeObject Type;
|
||||
static PyMethodDef Methods[];
|
||||
|
||||
public:
|
||||
FeaturePythonPyT(DocumentObject *pcObject, PyTypeObject *T = &Type);
|
||||
FeaturePythonPyT(PropertyContainer *pcObject, PyTypeObject *T = &Type);
|
||||
virtual ~FeaturePythonPyT();
|
||||
|
||||
/** @name callbacks and implementers for the python object methods */
|
||||
//@{
|
||||
static int __setattr(PyObject *PyObj, char *attr, PyObject *value);
|
||||
//@}
|
||||
|
||||
/// getter method for special attributes (e.g. dynamic ones)
|
||||
PyObject *getCustomAttributes(const char* attr) const;
|
||||
/// setter for special attributes (e.g. dynamic ones)
|
||||
int setCustomAttributes(const char* attr, PyObject *obj);
|
||||
PyObject *_getattr(char *attr); // __getattr__ function
|
||||
int _setattr(char *attr, PyObject *value); // __setattr__ function
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ PyTypeObject FeaturePythonPyT<FeaturePyT>::Type = {
|
|||
0, /*tp_weaklistoffset */
|
||||
0, /*tp_iter */
|
||||
0, /*tp_iternext */
|
||||
App::FeaturePythonPyT<FeaturePyT>::Methods, /*tp_methods */
|
||||
0, /*tp_methods */
|
||||
0, /*tp_members */
|
||||
0, /*tp_getset */
|
||||
&FeaturePyT::Type, /*tp_base */
|
||||
|
@ -80,14 +80,8 @@ PyTypeObject FeaturePythonPyT<FeaturePyT>::Type = {
|
|||
0 /*tp_version_tag */
|
||||
};
|
||||
|
||||
/// Methods structure of FeaturePythonPyT
|
||||
template<class FeaturePyT>
|
||||
PyMethodDef FeaturePythonPyT<FeaturePyT>::Methods[] = {
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
template<class FeaturePyT>
|
||||
FeaturePythonPyT<FeaturePyT>::FeaturePythonPyT(DocumentObject *pcObject, PyTypeObject *T)
|
||||
FeaturePythonPyT<FeaturePyT>::FeaturePythonPyT(PropertyContainer *pcObject, PyTypeObject *T)
|
||||
: FeaturePyT(reinterpret_cast<typename FeaturePyT::PointerType>(pcObject), T)
|
||||
{
|
||||
}
|
||||
|
@ -100,6 +94,8 @@ FeaturePythonPyT<FeaturePyT>::~FeaturePythonPyT()
|
|||
template<class FeaturePyT>
|
||||
int FeaturePythonPyT<FeaturePyT>::__setattr(PyObject *obj, char *attr, PyObject *value)
|
||||
{
|
||||
// This overwrites PyObjectBase::__setattr because this actively disallows to delete an attribute
|
||||
//
|
||||
if (!static_cast<Base::PyObjectBase*>(obj)->isValid()){
|
||||
PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr);
|
||||
return -1;
|
||||
|
@ -112,68 +108,9 @@ int FeaturePythonPyT<FeaturePyT>::__setattr(PyObject *obj, char *attr, PyObject
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<class FeaturePyT>
|
||||
PyObject *FeaturePythonPyT<FeaturePyT>::_getattr(char *attr)
|
||||
{
|
||||
try {
|
||||
// getter method for special Attributes (e.g. dynamic ones)
|
||||
PyObject *r = getCustomAttributes(attr);
|
||||
if(r) return r;
|
||||
}
|
||||
catch(const Base::Exception& e) {// catch the FreeCAD exceptions
|
||||
std::string str;
|
||||
str += "FreeCAD exception thrown (";
|
||||
str += e.what();
|
||||
str += ")";
|
||||
e.ReportException();
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError,str.c_str());
|
||||
return NULL;
|
||||
}
|
||||
catch(const Py::Exception&) {
|
||||
// The exception text is already set
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *rvalue = Py_FindMethod(Methods, this, attr);
|
||||
if (rvalue == NULL) {
|
||||
std::map<std::string, PyObject*>::iterator it = dyn_methods.find(attr);
|
||||
if (it != dyn_methods.end()) {
|
||||
Py_INCREF(it->second);
|
||||
rvalue = it->second;
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
if (rvalue == NULL) {
|
||||
PyErr_Clear();
|
||||
return FeaturePyT::_getattr(attr);
|
||||
}
|
||||
else {
|
||||
return rvalue;
|
||||
}
|
||||
}
|
||||
|
||||
template<class FeaturePyT>
|
||||
int FeaturePythonPyT<FeaturePyT>::_setattr(char *attr, PyObject *value)
|
||||
{
|
||||
try {
|
||||
// setter for special Attributes (e.g. dynamic ones)
|
||||
int r = setCustomAttributes(attr, value);
|
||||
if(r==1) return 0;
|
||||
}
|
||||
catch(const Base::Exception& e) { // catch the FreeCAD exceptions
|
||||
std::string str;
|
||||
str += "FreeCAD exception thrown (";
|
||||
str += e.what();
|
||||
str += ")";
|
||||
e.ReportException();
|
||||
PyErr_SetString(Base::BaseExceptionFreeCADError,str.c_str());
|
||||
return -1;
|
||||
}
|
||||
catch(const Py::Exception&) {
|
||||
// The exception text is already set
|
||||
return -1;
|
||||
}
|
||||
|
||||
int returnValue = FeaturePyT::_setattr(attr, value);
|
||||
if (returnValue == -1) {
|
||||
if (value) {
|
||||
|
@ -201,64 +138,49 @@ int FeaturePythonPyT<FeaturePyT>::_setattr(char *attr, PyObject *value)
|
|||
return returnValue;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------
|
||||
|
||||
template<class FeaturePyT>
|
||||
PyObject *FeaturePythonPyT<FeaturePyT>::getCustomAttributes(const char* attr) const
|
||||
PyObject *FeaturePythonPyT<FeaturePyT>::_getattr(char *attr)
|
||||
{
|
||||
PY_TRY{
|
||||
if (Base::streq(attr, "__dict__")){
|
||||
// Return the default dict
|
||||
PyTypeObject *tp = this->ob_type;
|
||||
// register type if needed
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_Ready(tp) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* dict = PyDict_Copy(tp->tp_dict);
|
||||
std::map<std::string,App::Property*> Map;
|
||||
FeaturePyT::getPropertyContainerPtr()->getPropertyMap(Map);
|
||||
for (std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it)
|
||||
PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString(""));
|
||||
for (std::map<std::string, PyObject*>::const_iterator it = dyn_methods.begin(); it != dyn_methods.end(); ++it)
|
||||
PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString(""));
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(dict);
|
||||
dict = 0;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
// search for dynamic property
|
||||
Property* prop = FeaturePyT::getDocumentObjectPtr()->getDynamicPropertyByName(attr);
|
||||
if (prop)
|
||||
return prop->getPyObject();
|
||||
else
|
||||
return 0;
|
||||
} PY_CATCH
|
||||
}
|
||||
|
||||
template<class FeaturePyT>
|
||||
int FeaturePythonPyT<FeaturePyT>::setCustomAttributes(const char* attr, PyObject *value)
|
||||
{
|
||||
// search for dynamic property
|
||||
Property* prop = FeaturePyT::getDocumentObjectPtr()->getDynamicPropertyByName(attr);
|
||||
|
||||
if (!prop)
|
||||
return FeaturePyT::setCustomAttributes(attr, value);
|
||||
else {
|
||||
try {
|
||||
prop->setPyObject(value);
|
||||
return 1;
|
||||
} catch (Base::Exception &exc) {
|
||||
PyErr_Format(PyExc_AttributeError, "Attribute (Name: %s) error: '%s' ", attr, exc.what());
|
||||
return -1;
|
||||
} catch (...) {
|
||||
PyErr_Format(PyExc_AttributeError, "Unknown error in attribute %s", attr);
|
||||
return -1;
|
||||
}
|
||||
// See CallTipsList::extractTips
|
||||
if (Base::streq(attr, "__fc_template__")) {
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
if (Base::streq(attr, "__dict__")) {
|
||||
// Return the default dict
|
||||
PyTypeObject *tp = this->ob_type;
|
||||
// register type if needed
|
||||
if (tp->tp_dict == NULL) {
|
||||
if (PyType_Ready(tp) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* dict = PyDict_Copy(tp->tp_dict);
|
||||
std::map<std::string,App::Property*> Map;
|
||||
FeaturePyT::getPropertyContainerPtr()->getPropertyMap(Map);
|
||||
for (std::map<std::string,App::Property*>::iterator it = Map.begin(); it != Map.end(); ++it)
|
||||
PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString(""));
|
||||
for (std::map<std::string, PyObject*>::const_iterator it = dyn_methods.begin(); it != dyn_methods.end(); ++it)
|
||||
PyDict_SetItem(dict, PyString_FromString(it->first.c_str()), PyString_FromString(""));
|
||||
if (PyErr_Occurred()) {
|
||||
Py_DECREF(dict);
|
||||
dict = 0;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject *rvalue = NULL;
|
||||
std::map<std::string, PyObject*>::iterator it = dyn_methods.find(attr);
|
||||
if (it != dyn_methods.end()) {
|
||||
Py_INCREF(it->second);
|
||||
rvalue = it->second;
|
||||
PyErr_Clear();
|
||||
return rvalue;
|
||||
}
|
||||
|
||||
PyErr_Clear();
|
||||
return FeaturePyT::_getattr(attr);
|
||||
}
|
||||
|
||||
} //namespace App
|
||||
|
|
|
@ -261,8 +261,9 @@ QMap<QString, CallTip> CallTipsList::extractTips(const QString& context) const
|
|||
// 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")) {
|
||||
// To see if we have a template Python object we check for the existence of '__fc_template__'
|
||||
// See also: FeaturePythonPyT
|
||||
if (!obj.hasAttr("__fc_template__")) {
|
||||
obj = type;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ class DocumentBasicCases(unittest.TestCase):
|
|||
enumeration_choices = ["one", "two"]
|
||||
obj = self.Doc.addObject("App::FeaturePython","Label_2")
|
||||
obj.addProperty("App::PropertyEnumeration", "myEnumeration", "Enum", "mytest")
|
||||
with self.assertRaises(FreeCAD.Base.FreeCADError):
|
||||
with self.assertRaises(ValueError):
|
||||
obj.myEnumeration = enumeration_choices[0]
|
||||
|
||||
def testMem(self):
|
||||
|
|
Loading…
Reference in New Issue
Block a user