py3: change of getattr -> getattro

issue 0000995
This commit is contained in:
looooo
2017-06-02 11:53:39 +02:00
committed by wmayer
parent 3168f8ed3f
commit bc696e5ab5
5 changed files with 215 additions and 92 deletions

View File

@@ -40,7 +40,7 @@ PyObject* Base::BaseExceptionFreeCADError = 0;
PyObjectBase::PyObjectBase(void* p,PyTypeObject *T)
: _pcTwinPointer(p), attrDict(0)
{
this->ob_type = T;
Py_TYPE(this) = T;
_Py_NewReference(this);
#ifdef FC_LOGPYOBJECTS
Base::Console().Log("PyO+: %s (%p)\n",T->tp_name, this);
@@ -54,7 +54,7 @@ PyObjectBase::~PyObjectBase()
{
PyGILStateLocker lock;
#ifdef FC_LOGPYOBJECTS
Base::Console().Log("PyO-: %s (%p)\n",this->ob_type->tp_name, this);
Base::Console().Log("PyO-: %s (%p)\n",Py_TYPE(this)->tp_name, this);
#endif
Py_XDECREF(attrDict);
}
@@ -73,16 +73,15 @@ PyObjectBase::~PyObjectBase()
*/
PyTypeObject PyObjectBase::Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
PyVarObject_HEAD_INIT(&PyType_Type,0)
"PyObjectBase", /*tp_name*/
sizeof(PyObjectBase), /*tp_basicsize*/
0, /*tp_itemsize*/
/* --- methods ---------------------------------------------- */
PyDestructor, /*tp_dealloc*/
0, /*tp_print*/
__getattr, /*tp_getattr*/
__setattr, /*tp_setattr*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
__repr, /*tp_repr*/
0, /*tp_as_number*/
@@ -91,12 +90,12 @@ PyTypeObject PyObjectBase::Type = {
0, /*tp_hash*/
0, /*tp_call */
0, /*tp_str */
0, /*tp_getattro*/
0, /*tp_setattro*/
__getattro, /*tp_getattro*/
__setattro, /*tp_setattro*/
/* --- Functions to access object as input/output buffer ---------*/
0, /* tp_as_buffer */
/* --- Flags to define presence of optional/expanded features */
Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_CLASS, /*tp_flags */
Py_TPFLAGS_BASETYPE|Py_TPFLAGS_DEFAULT, /*tp_flags */
"The most base class for Python binding", /*tp_doc */
0, /*tp_traverse */
0, /*tp_clear */
@@ -124,6 +123,9 @@ PyTypeObject PyObjectBase::Type = {
0, /*tp_weaklist */
0, /*tp_del */
0 /*tp_version_tag */
#if PY_MAJOR_VERSION >= 3
,0 /*tp_finalize */
#endif
};
/*------------------------------
@@ -133,8 +135,16 @@ PyMethodDef PyObjectBase::Methods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr)
PyObject* PyObjectBase::__getattro(PyObject * obj, PyObject *attro)
{
char *attr;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(attro))
attr = PyUnicode_AsUTF8(attro);
#else
if (PyString_Check(attro))
attr = PyString_AsString(attro);
#endif
// This should be the entry in Type
PyObjectBase* pyObj = static_cast<PyObjectBase*>(obj);
if (!pyObj->isValid()){
@@ -152,7 +162,7 @@ PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr)
}
}
PyObject* value = pyObj->_getattr(attr);
PyObject* value = pyObj->_getattro(attro);
#if 1
if (value && PyObject_TypeCheck(value, &(PyObjectBase::Type))) {
if (!static_cast<PyObjectBase*>(value)->isConst()) {
@@ -180,10 +190,18 @@ PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr)
return value;
}
int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value)
int PyObjectBase::__setattro(PyObject *obj, PyObject *attro, PyObject *value)
{
char *attr;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(attro))
attr = PyUnicode_AsUTF8(attro);
#else
if (PyString_Check(attro))
attr = PyString_AsString(attro);
#endif
//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.
//we must check then in _setattro() of all subclasses whether value is 0.
if ( value==0 ) {
PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr);
return -1;
@@ -204,7 +222,7 @@ int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value)
}
}
int ret = static_cast<PyObjectBase*>(obj)->_setattr(attr, value);
int ret = static_cast<PyObjectBase*>(obj)->_setattro(attro, value);
#if 1
if (ret == 0) {
static_cast<PyObjectBase*>(obj)->startNotify();
@@ -216,13 +234,21 @@ int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value)
/*------------------------------
* PyObjectBase attributes -- attributes
------------------------------*/
PyObject *PyObjectBase::_getattr(char *attr)
PyObject *PyObjectBase::_getattro(PyObject *attro)
{
char *attr;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(attro))
attr = PyUnicode_AsUTF8(attro);
#else
if (PyString_Check(attro))
attr = PyString_AsString(attro);
#endif
if (streq(attr, "__class__")) {
// Note: We must return the type object here,
// so that our own types feel as really Python objects
Py_INCREF(this->ob_type);
return (PyObject *)(this->ob_type);
Py_INCREF(Py_TYPE(this));
return (PyObject *)(Py_TYPE(this));
}
else if (streq(attr, "__members__")) {
// Use __dict__ instead as __members__ is deprecated
@@ -230,7 +256,7 @@ PyObject *PyObjectBase::_getattr(char *attr)
}
else if (streq(attr,"__dict__")) {
// Return the default dict
PyTypeObject *tp = this->ob_type;
PyTypeObject *tp = Py_TYPE(this);
Py_XINCREF(tp->tp_dict);
return tp->tp_dict;
}
@@ -240,36 +266,39 @@ PyObject *PyObjectBase::_getattr(char *attr)
}
else {
// As fallback solution use Python's default method to get generic attributes
PyObject *w, *res;
w = PyString_InternFromString(attr);
if (w != NULL) {
res = PyObject_GenericGetAttr(this, w);
Py_XDECREF(w);
PyObject *res;
if (attro != NULL) {
res = PyObject_GenericGetAttr(this, attro);
return res;
} else {
// Throw an exception for unknown attributes
PyTypeObject *tp = this->ob_type;
PyTypeObject *tp = Py_TYPE(this);
PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr);
return NULL;
}
}
}
int PyObjectBase::_setattr(char *attr, PyObject *value)
int PyObjectBase::_setattro(PyObject *attro, PyObject *value)
{
char *attr;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(attro))
attr = PyUnicode_AsUTF8(attro);
#else
if (PyString_Check(attro))
attr = PyString_AsString(attro);
#endif
if (streq(attr,"softspace"))
return -1; // filter out softspace
PyObject *w;
// As fallback solution use Python's default method to get generic attributes
w = PyString_InternFromString(attr); // new reference
if (w != NULL) {
if (attro != NULL) {
// call methods from tp_getset if defined
int res = PyObject_GenericSetAttr(this, w, value);
Py_DECREF(w);
int res = PyObject_GenericSetAttr(this, attro, value);
return res;
} else {
// Throw an exception for unknown attributes
PyTypeObject *tp = this->ob_type;
PyTypeObject *tp = Py_TYPE(this);
PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr);
return -1;
}
@@ -293,8 +322,13 @@ void PyObjectBase::resetAttribute()
if (attrDict) {
// This is the attribute name to the parent structure
// which we search for in the dict
#if PY_MAJOR_VERSION < 3
PyObject* key1 = PyString_FromString("__attribute_of_parent__");
PyObject* key2 = PyString_FromString("__instance_of_parent__");
#else
PyObject* key1 = PyBytes_FromString("__attribute_of_parent__");
PyObject* key2 = PyBytes_FromString("__instance_of_parent__");
#endif
PyObject* attr = PyDict_GetItem(attrDict, key1);
PyObject* inst = PyDict_GetItem(attrDict, key2);
if (attr) {
@@ -313,10 +347,14 @@ void PyObjectBase::setAttributeOf(const char* attr, PyObject* par)
if (!attrDict) {
attrDict = PyDict_New();
}
#if PY_MAJOR_VERSION < 3
PyObject* key1 = PyString_FromString("__attribute_of_parent__");
PyObject* key2 = PyString_FromString("__instance_of_parent__");
PyObject* attro = PyString_FromString(attr);
#else
PyObject* key1 = PyBytes_FromString("__attribute_of_parent__");
PyObject* key2 = PyBytes_FromString("__instance_of_parent__");
#endif
PyObject* attro = PyUnicode_FromString(attr);
PyDict_SetItem(attrDict, key1, attro);
PyDict_SetItem(attrDict, key2, par);
Py_DECREF(attro);
@@ -332,8 +370,13 @@ void PyObjectBase::startNotify()
if (attrDict) {
// This is the attribute name to the parent structure
// which we search for in the dict
#if PY_MAJOR_VERSION < 3
PyObject* key1 = PyString_FromString("__attribute_of_parent__");
PyObject* key2 = PyString_FromString("__instance_of_parent__");
#else
PyObject* key1 = PyBytes_FromString("__attribute_of_parent__");
PyObject* key2 = PyBytes_FromString("__instance_of_parent__");
#endif
PyObject* attr = PyDict_GetItem(attrDict, key1);
PyObject* parent = PyDict_GetItem(attrDict, key2);
if (attr && parent) {
@@ -345,7 +388,7 @@ void PyObjectBase::startNotify()
Py_INCREF(attr);
Py_INCREF(this);
__setattr(parent, PyString_AsString(attr), this);
__setattro(parent, attr, this);
Py_DECREF(parent); // might be destroyed now
Py_DECREF(attr); // might be destroyed now