int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value) { //FIXME: In general we don't allow to delete attributes (i.e. value=0). However, if we want to allow //we must check then in _setattr() of all subclasses whether value is 0. if ( value==0 ) { PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr); return -1; } else if (!static_cast<PyObjectBase*>(obj)->isValid()){ PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr); return -1; } // If an attribute references this as parent then reset it // before setting the new attribute PyObject* cur = static_cast<PyObjectBase*>(obj)->getTrackedAttribute(attr); if (cur) { if (PyObject_TypeCheck(cur, &(PyObjectBase::Type))) { PyObjectBase* base = static_cast<PyObjectBase*>(cur); base->resetAttribute(); static_cast<PyObjectBase*>(obj)->untrackAttribute(attr); } } int ret = static_cast<PyObjectBase*>(obj)->_setattr(attr, value); #if 1 if (ret == 0) { static_cast<PyObjectBase*>(obj)->startNotify(); } #endif return ret; }
PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr) { // This should be the entry in Type PyObjectBase* pyObj = static_cast<PyObjectBase*>(obj); if (!pyObj->isValid()){ PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr); return NULL; } PyObject* value = pyObj->_getattr(attr); #if 1 if (value && PyObject_TypeCheck(value, &(PyObjectBase::Type))) { if (!static_cast<PyObjectBase*>(value)->isConst()) static_cast<PyObjectBase*>(value)->setAttributeOf(attr, pyObj); } #endif return value; }
PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr) { // This should be the entry in Type PyObjectBase* pyObj = static_cast<PyObjectBase*>(obj); if (!pyObj->isValid()){ PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr); return NULL; } // If an attribute references this as parent then reset it (bug #0002902) PyObject* cur = pyObj->getTrackedAttribute(attr); if (cur) { if (PyObject_TypeCheck(cur, &(PyObjectBase::Type))) { PyObjectBase* base = static_cast<PyObjectBase*>(cur); base->resetAttribute(); pyObj->untrackAttribute(attr); } } PyObject* value = pyObj->_getattr(attr); #if 1 if (value && PyObject_TypeCheck(value, &(PyObjectBase::Type))) { if (!static_cast<PyObjectBase*>(value)->isConst()) { static_cast<PyObjectBase*>(value)->setAttributeOf(attr, pyObj); pyObj->trackAttribute(attr, value); } } else if (value && PyCFunction_Check(value)) { // ExtensionContainerPy::initialization() transfers the methods of an // extension object by creating PyCFunction objects. // At this point no 'self' object is passed but is handled and determined // in ExtensionContainerPy::getCustomAttributes(). // So, if we come through this section then it's an indication that // something is wrong with the Python types. For example, a C++ class // that adds an extension uses the same Python type as a wrapper than // another C++ class without this extension. PyCFunctionObject* cfunc = reinterpret_cast<PyCFunctionObject*>(value); if (!cfunc->m_self) { Py_DECREF(cfunc); value = 0; PyErr_Format(PyExc_AttributeError, "<no object bound to built-in method %s>", attr); } } #endif return value; }