PyObjectBase.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (c) Jürgen Riegel          (juergen.riegel@web.de) 2002     *
00003  *                                                                         *
00004  *   This file is part of the FreeCAD CAx development system.              *
00005  *                                                                         *
00006  *   This library is free software; you can redistribute it and/or         *
00007  *   modify it under the terms of the GNU Library General Public           *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2 of the License, or (at your option) any later version.      *
00010  *                                                                         *
00011  *   This library  is distributed in the hope that it will be useful,      *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00014  *   GNU Library General Public License for more details.                  *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Library General Public     *
00017  *   License along with this library; see the file COPYING.LIB. If not,    *
00018  *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
00019  *   Suite 330, Boston, MA  02111-1307, USA                                *
00020  *                                                                         *
00021  ***************************************************************************/
00022 
00023 
00024 #include "PreCompiled.h"
00025 
00026 #ifndef _PreComp_
00027 # include <sstream>
00028 # include <stdlib.h>
00029 #endif
00030 
00031 #include "PyObjectBase.h"
00032 #include "Console.h"
00033 
00034 using namespace Base;
00035 
00036 // Constructor
00037 PyObjectBase::PyObjectBase(void* p,PyTypeObject *T)
00038   : _pcTwinPointer(p), parent(0), attribute(0)
00039 {
00040     this->ob_type = T;
00041     _Py_NewReference(this);
00042 #ifdef FC_LOGPYOBJECTS
00043     Base::Console().Log("PyO+: %s (%p)\n",T->tp_name, this);
00044 #endif
00045     StatusBits.set(0); // valid, the second bit is NOT set, i.e. it's mutable
00046 }
00047 
00049 PyObjectBase::~PyObjectBase() 
00050 {
00051 #ifdef FC_LOGPYOBJECTS
00052     Base::Console().Log("PyO-: %s (%p)\n",this->ob_type->tp_name, this);
00053 #endif
00054     if (this->parent)
00055         this->parent->DecRef();
00056     if (this->attribute)
00057         free(this->attribute); /* it's a strdup */
00058 }
00059 
00060 /*------------------------------
00061  * PyObjectBase Type            -- Every class, even the abstract one should have a Type
00062 ------------------------------*/
00063 
00073 PyTypeObject PyObjectBase::Type = {
00074     PyObject_HEAD_INIT(&PyType_Type)
00075     0,                                                      /*ob_size*/
00076     "PyObjectBase",                                         /*tp_name*/
00077     sizeof(PyObjectBase),                                   /*tp_basicsize*/
00078     0,                                                      /*tp_itemsize*/
00079     /* --- methods ---------------------------------------------- */
00080     PyDestructor,                                           /*tp_dealloc*/
00081     0,                                                      /*tp_print*/
00082     __getattr,                                              /*tp_getattr*/
00083     __setattr,                                              /*tp_setattr*/
00084     0,                                                      /*tp_compare*/
00085     __repr,                                                 /*tp_repr*/
00086     0,                                                      /*tp_as_number*/
00087     0,                                                      /*tp_as_sequence*/
00088     0,                                                      /*tp_as_mapping*/
00089     0,                                                      /*tp_hash*/
00090     0,                                                      /*tp_call */
00091     0,                                                      /*tp_str  */
00092     0,                                                      /*tp_getattro*/
00093     0,                                                      /*tp_setattro*/
00094     /* --- Functions to access object as input/output buffer ---------*/
00095     0,                                                      /* tp_as_buffer */
00096     /* --- Flags to define presence of optional/expanded features */
00097     Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_CLASS,              /*tp_flags */
00098     "The most base class for Python binding",               /*tp_doc */
00099     0,                                                      /*tp_traverse */
00100     0,                                                      /*tp_clear */
00101     0,                                                      /*tp_richcompare */
00102     0,                                                      /*tp_weaklistoffset */
00103     0,                                                      /*tp_iter */
00104     0,                                                      /*tp_iternext */
00105     0,                                                      /*tp_methods */
00106     0,                                                      /*tp_members */
00107     0,                                                      /*tp_getset */
00108     0,                                                      /*tp_base */
00109     0,                                                      /*tp_dict */
00110     0,                                                      /*tp_descr_get */
00111     0,                                                      /*tp_descr_set */
00112     0,                                                      /*tp_dictoffset */
00113     0,                                                      /*tp_init */
00114     0,                                                      /*tp_alloc */
00115     0,                                                      /*tp_new */
00116     0,                                                      /*tp_free   Low-level free-memory routine */
00117     0,                                                      /*tp_is_gc  For PyObject_IS_GC */
00118     0,                                                      /*tp_bases */
00119     0,                                                      /*tp_mro    method resolution order */
00120     0,                                                      /*tp_cache */
00121     0,                                                      /*tp_subclasses */
00122     0,                                                      /*tp_weaklist */
00123     0                                                       /*tp_del */
00124 };
00125 
00126 /*------------------------------
00127  * PyObjectBase Methods         -- Every class, even the abstract one should have a Methods
00128 ------------------------------*/
00129 PyMethodDef PyObjectBase::Methods[] = {
00130     {NULL, NULL, 0, NULL}        /* Sentinel */
00131 };
00132 
00133 /*------------------------------
00134  * PyObjectBase Parents         -- Every class, even the abstract one should have parents
00135 ------------------------------*/
00136 PyParentObject PyObjectBase::Parents[] = {&PyObjectBase::Type, NULL};
00137 
00138 PyObject* PyObjectBase::__getattr(PyObject * obj, char *attr)
00139 {
00140     // This should be the entry in Type
00141     PyObjectBase* pyObj = static_cast<PyObjectBase*>(obj);
00142     if (!pyObj->isValid()){
00143         PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr);
00144         return NULL;
00145     }
00146 
00147     PyObject* value = pyObj->_getattr(attr);
00148 #if 1
00149     if (value && PyObject_TypeCheck(value, &(PyObjectBase::Type))) {
00150         if (!static_cast<PyObjectBase*>(value)->isConst())
00151             static_cast<PyObjectBase*>(value)->setAttributeOf(attr, pyObj);
00152     }
00153 #endif
00154     return value;
00155 }
00156 
00157 int PyObjectBase::__setattr(PyObject *obj, char *attr, PyObject *value)
00158 {
00159     //FIXME: In general we don't allow to delete attributes (i.e. value=0). However, if we want to allow
00160     //we must check then in _setattr() of all subclasses whether value is 0.
00161     if ( value==0 ) {
00162         PyErr_Format(PyExc_AttributeError, "Cannot delete attribute: '%s'", attr);
00163         return -1;
00164     }
00165     else if (!static_cast<PyObjectBase*>(obj)->isValid()){
00166         PyErr_Format(PyExc_ReferenceError, "Cannot access attribute '%s' of deleted object", attr);
00167         return -1;
00168     }
00169 
00170     int ret = static_cast<PyObjectBase*>(obj)->_setattr(attr, value);
00171 #if 1
00172     if (ret == 0) {
00173         static_cast<PyObjectBase*>(obj)->startNotify();
00174     }
00175 #endif
00176     return ret;
00177 }
00178 
00179 /*------------------------------
00180  * PyObjectBase attributes      -- attributes
00181 ------------------------------*/
00182 PyObject *PyObjectBase::_getattr(char *attr)
00183 {
00184     if (streq(attr, "__class__")) {
00185         // Note: We must return the type object here, 
00186         // so that our own types feel as really Python objects 
00187         Py_INCREF(this->ob_type);
00188         return (PyObject *)(this->ob_type);
00189     }
00190     else if (streq(attr, "__members__")) {
00191         // Use __dict__ instead as __members__ is deprecated
00192         return NULL;
00193     }
00194     else if (streq(attr,"__dict__")) {
00195         // Return the default dict
00196         PyTypeObject *tp = this->ob_type;
00197         Py_XINCREF(tp->tp_dict);
00198         return tp->tp_dict;
00199     }
00200     else if (streq(attr,"softspace")) {
00201         // Internal Python stuff
00202         return NULL;
00203     }
00204     else {
00205         // As fallback solution use Python's default method to get generic attributes
00206         PyObject *w, *res;
00207         w = PyString_InternFromString(attr);
00208         if (w != NULL) {
00209             res = PyObject_GenericGetAttr(this, w);
00210             Py_XDECREF(w);
00211             return res;
00212         } else {
00213             // Throw an exception for unknown attributes
00214             PyTypeObject *tp = this->ob_type;
00215             PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr);
00216             return NULL;
00217         }
00218     }
00219 }
00220 
00221 int PyObjectBase::_setattr(char *attr, PyObject *value)
00222 {
00223     if (streq(attr,"softspace"))
00224         return -1; // filter out softspace
00225     PyObject *w;
00226     // As fallback solution use Python's default method to get generic attributes
00227     w = PyString_InternFromString(attr); // new reference
00228     if (w != NULL) {
00229         // call methods from tp_getset if defined
00230         int res = PyObject_GenericSetAttr(this, w, value);
00231         Py_DECREF(w);
00232         return res;
00233     } else {
00234         // Throw an exception for unknown attributes
00235         PyTypeObject *tp = this->ob_type;
00236         PyErr_Format(PyExc_AttributeError, "%.50s instance has no attribute '%.400s'", tp->tp_name, attr);
00237         return -1;
00238     }
00239 }
00240 
00241 /*------------------------------
00242  * PyObjectBase repr    representations
00243 ------------------------------*/
00244 PyObject *PyObjectBase::_repr(void)
00245 {
00246     std::stringstream a;
00247     a << "<base object at " << _pcTwinPointer << ">";
00248 # ifdef FCDebug
00249     Console().Log("PyObjectBase::_repr() not overwritten representation!");
00250 # endif
00251     return Py_BuildValue("s", a.str().c_str());
00252 }
00253 
00254 void PyObjectBase::setAttributeOf(const char* attr, const PyObjectBase* par)
00255 {
00256     if (this->parent != par) {
00257         Py_XDECREF(this->parent);
00258         this->parent = const_cast<PyObjectBase*>(par);
00259         Py_XINCREF(this->parent);
00260     }
00261 
00262     if (this->attribute) {
00263         if (strcmp(this->attribute, attr) != 0) {
00264             free(this->attribute);
00265 #if defined (__GNUC__)
00266             this->attribute =  strdup(attr);
00267 #else
00268             this->attribute = _strdup(attr);
00269 #endif
00270         }
00271     }
00272     else {
00273 #if defined (__GNUC__)
00274         this->attribute =  strdup(attr);
00275 #else
00276         this->attribute = _strdup(attr);
00277 #endif
00278     }
00279 }
00280 
00281 void PyObjectBase::startNotify()
00282 {
00283     if (this->attribute && this->parent) {
00284         __setattr(this->parent, this->attribute, this);
00285         if (PyErr_Occurred())
00286             PyErr_Clear();
00287     }
00288 }

Generated on Wed Nov 23 19:00:31 2011 for FreeCAD by  doxygen 1.6.1