Allow to add methods at runtime to FeaturePython objects

This commit is contained in:
wmayer 2013-03-23 22:09:33 +01:00
parent b7658c04f6
commit 295f6c3058
2 changed files with 53 additions and 2 deletions

View File

@ -23,6 +23,8 @@
#ifndef APP_FEATUREPYTHONPYIMP_H
#define APP_FEATUREPYTHONPYIMP_H
#include <map>
#include <string>
#include <Base/Console.h>
#include <App/DocumentObjectPy.h>
@ -45,6 +47,7 @@ public:
/** @name callbacks and implementers for the python object methods */
//@{
static int __setattr(PyObject *PyObj, char *attr, PyObject *value);
/// callback for the addProperty() method
static PyObject * staticCallback_addProperty (PyObject *self, PyObject *args);
/// implementer for the addProperty() method
@ -67,6 +70,7 @@ public:
int _setattr(char *attr, PyObject *value); // __setattr__ function
protected:
std::map<std::string, PyObject*> dyn_methods;
private:
};

View File

@ -36,7 +36,7 @@ PyTypeObject FeaturePythonPyT<FeaturePyT>::Type = {
FeaturePyT::PyDestructor, /*tp_dealloc*/
0, /*tp_print*/
FeaturePyT::__getattr, /*tp_getattr*/
FeaturePyT::__setattr, /*tp_setattr*/
__setattr, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
@ -219,6 +219,21 @@ FeaturePythonPyT<FeaturePyT>::~FeaturePythonPyT()
{
}
template<class FeaturePyT>
int FeaturePythonPyT<FeaturePyT>::__setattr(PyObject *obj, char *attr, PyObject *value)
{
if (!static_cast<Base::PyObjectBase*>(obj)->isValid()){
PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr);
return -1;
}
int ret = static_cast<Base::PyObjectBase*>(obj)->_setattr(attr, value);
if (ret == 0) {
static_cast<Base::PyObjectBase*>(obj)->startNotify();
}
return ret;
}
template<class FeaturePyT>
PyObject *FeaturePythonPyT<FeaturePyT>::_getattr(char *attr)
{
@ -242,6 +257,14 @@ PyObject *FeaturePythonPyT<FeaturePyT>::_getattr(char *attr)
}
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);
@ -273,7 +296,31 @@ int FeaturePythonPyT<FeaturePyT>::_setattr(char *attr, PyObject *value)
return -1;
}
return FeaturePyT::_setattr(attr, value);
int returnValue = FeaturePyT::_setattr(attr, value);
if (returnValue == -1) {
if (value) {
if (PyFunction_Check(value)) {
std::map<std::string, PyObject*>::iterator it = dyn_methods.find(attr);
if (it != dyn_methods.end()) {
Py_XDECREF(it->second);
}
dyn_methods[attr] = PyMethod_New(value, this, 0);
returnValue = 0;
PyErr_Clear();
}
}
else {
// delete
std::map<std::string, PyObject*>::iterator it = dyn_methods.find(attr);
if (it != dyn_methods.end()) {
Py_XDECREF(it->second);
dyn_methods.erase(it);
returnValue = 0;
PyErr_Clear();
}
}
}
return returnValue;
}
// -------------------------------------------------------------