ObjectProxy.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: ObjectProxy.cxx 35619 2010-09-23 00:48:33Z wlav $
00002 // Author: Wim Lavrijsen, Jan 2005
00003 
00004 // Bindings
00005 #include "PyROOT.h"
00006 #include "PyStrings.h"
00007 #include "ObjectProxy.h"
00008 #include "Utility.h"
00009 
00010 // ROOT
00011 #include "TObject.h"
00012 #include "TBufferFile.h"      // for pickling
00013 
00014 
00015 //- data _______________________________________________________________________
00016 R__EXTERN PyObject* gRootModule;
00017 
00018 //____________________________________________________________________________
00019 void PyROOT::op_dealloc_nofree( ObjectProxy* pyobj ) {
00020    if ( pyobj->fObject && ( pyobj->fFlags & ObjectProxy::kIsOwner ) ) {
00021       pyobj->ObjectIsA()->Destructor( pyobj->fObject );
00022    }
00023 }
00024 
00025 
00026 //____________________________________________________________________________
00027 namespace PyROOT {
00028 
00029 namespace {
00030 
00031 //= PyROOT object proxy nullness checking ====================================
00032    PyObject* op_nonzero( ObjectProxy* self )
00033    {
00034       PyObject* result = self->GetObject() ? Py_True : Py_False;
00035       Py_INCREF( result );
00036       return result;
00037    }
00038 
00039 
00040 //= PyROOT object proxy pickle support =======================================
00041    PyObject* op_reduce( ObjectProxy* self )
00042    {
00043    // Turn the object proxy instance into a character stream and return for
00044    // pickle, together with the callable object that can restore the stream
00045    // into the object proxy instance.
00046 
00047    // keep a borrowed reference around to the callable function for expanding;
00048    // because it is borrowed, it means that there can be no pickling during the
00049    // shutdown of the libPyROOT module
00050       static PyObject* s_expand = PyDict_GetItemString(
00051          PyModule_GetDict( gRootModule ),  const_cast< char* >( "_ObjectProxy__expand__" ) );
00052 
00053    // TBuffer and its derived classes can't write themselves, but can be created
00054    // directly from the buffer, so handle them in a special case
00055       static TClassRef s_bfClass( "TBufferFile" );
00056 
00057       TBufferFile* buff = 0;
00058       if ( s_bfClass == self->ObjectIsA() ) {
00059          buff = (TBufferFile*)self->GetObject();
00060       } else {
00061       // no cast is needed, but WriteObject taking a TClass argument is protected,
00062       // so use WriteObjectAny()
00063          static TBufferFile s_buff( TBuffer::kWrite );
00064          s_buff.Reset();
00065          if ( s_buff.WriteObjectAny( self->GetObject(), self->ObjectIsA() ) != 1 ) {
00066             PyErr_Format( PyExc_IOError,
00067                "could not stream object of type %s", self->ObjectIsA()->GetName() );
00068             return 0;
00069          }
00070          buff = &s_buff;
00071       }
00072 
00073    // use a string for the serialized result, as a python buffer will not copy
00074    // the buffer contents; use a string for the class name, used when casting
00075    // on reading back in (see RootModule.cxx:TObjectExpand)
00076       PyObject* res2 = PyTuple_New( 2 );
00077       PyTuple_SET_ITEM( res2, 0, PyBytes_FromStringAndSize( buff->Buffer(), buff->Length() ) );
00078       PyTuple_SET_ITEM( res2, 1, PyBytes_FromString( self->ObjectIsA()->GetName() ) );
00079 
00080       PyObject* result = PyTuple_New( 2 );
00081       Py_INCREF( s_expand );
00082       PyTuple_SET_ITEM( result, 0, s_expand );
00083       PyTuple_SET_ITEM( result, 1, res2 );
00084 
00085       return result;
00086    }
00087 
00088 //____________________________________________________________________________
00089    PyMethodDef op_methods[] = {
00090       { (char*)"__nonzero__", (PyCFunction)op_nonzero, METH_NOARGS, NULL },
00091       { (char*)"__bool__",    (PyCFunction)op_nonzero, METH_NOARGS, NULL }, // for p3
00092       { (char*)"__reduce__",  (PyCFunction)op_reduce,  METH_NOARGS, NULL },
00093       { (char*)NULL, NULL, 0, NULL }
00094    };
00095 
00096 
00097 //= PyROOT object proxy construction/destruction =============================
00098    ObjectProxy* op_new( PyTypeObject* subtype, PyObject*, PyObject* )
00099    {
00100       ObjectProxy* pyobj = (ObjectProxy*)subtype->tp_alloc( subtype, 0 );
00101       pyobj->fObject = NULL;
00102       pyobj->fFlags  = 0;
00103 
00104       return pyobj;
00105    }
00106 
00107 //____________________________________________________________________________
00108    void op_dealloc( ObjectProxy* pyobj )
00109    {
00110       op_dealloc_nofree( pyobj );
00111       Py_TYPE(pyobj)->tp_free( (PyObject*)pyobj );
00112    }
00113 
00114 //____________________________________________________________________________
00115    PyObject* op_richcompare( ObjectProxy* self, ObjectProxy* other, int op )
00116    {
00117       if ( op != Py_EQ && op != Py_NE ) {
00118          Py_INCREF( Py_NotImplemented );
00119          return Py_NotImplemented;
00120       }
00121 
00122       bool bIsEq = false;
00123 
00124    // special case for None to compare True to a null-pointer
00125       if ( (PyObject*)other == Py_None && ! self->fObject )
00126          bIsEq = true;
00127 
00128    // type + held pointer value defines identity (will cover if other is not
00129    // actually an ObjectProxy, as ob_type will be unequal)
00130       else if ( Py_TYPE(self) == Py_TYPE(other) && self->fObject == other->fObject )
00131          bIsEq = true;
00132 
00133       if ( ( op == Py_EQ && bIsEq ) || ( op == Py_NE && ! bIsEq ) ) {
00134          Py_INCREF( Py_True );
00135          return Py_True;
00136       }
00137 
00138       Py_INCREF( Py_False );
00139       return Py_False;
00140    }
00141 
00142 //____________________________________________________________________________
00143    PyObject* op_repr( ObjectProxy* pyobj )
00144    {
00145       TClass* klass = pyobj->ObjectIsA();
00146       std::string clName = klass ? klass->GetName() : "<unknown>";
00147       if ( pyobj->fFlags & ObjectProxy::kIsReference )
00148          clName.append( "*" );
00149 
00150    // need to prevent accidental derefs when just printing (usually unsafe)
00151       if ( ! PyObject_HasAttr( (PyObject*)pyobj, PyStrings::gDeref ) ) {
00152          PyObject* name = PyObject_CallMethod( (PyObject*)pyobj,
00153             const_cast< char* >( "GetName" ), const_cast< char* >( "" ) );
00154 
00155          if ( name ) {
00156             if ( PyROOT_PyUnicode_GET_SIZE( name ) != 0 ) {
00157                PyObject* repr = PyROOT_PyUnicode_FromFormat( "<ROOT.%s object (\"%s\") at %p>",
00158                   clName.c_str(), PyROOT_PyUnicode_AsString( name ), pyobj->fObject );
00159                Py_DECREF( name );
00160                return repr;
00161             }
00162             Py_DECREF( name );
00163          } else
00164             PyErr_Clear();
00165       }
00166 
00167    // get here if object has no method GetName() or name = ""
00168       return PyROOT_PyUnicode_FromFormat( const_cast< char* >( "<ROOT.%s object at %p>" ),
00169          clName.c_str(), pyobj->fObject );
00170    }
00171 
00172 
00173 //= PyROOT type number stubs to allow dynamic overrides ======================
00174 #define PYROOT_STUB( name, op, pystring )                                     \
00175    PyObject* op_##name##_stub( PyObject* self, PyObject* other )              \
00176    {                                                                          \
00177    /* place holder to lazily install __name__ if a global overload is available */ \
00178       if ( ! Utility::AddBinaryOperator( self, other, #op, "__"#name"__" ) ) {\
00179          Py_INCREF( Py_NotImplemented );                                      \
00180          return Py_NotImplemented;                                            \
00181       }                                                                       \
00182                                                                               \
00183    /* redo the call, which will now go to the newly installed method */       \
00184       return PyObject_CallMethodObjArgs( self, pystring, other, NULL );       \
00185    }
00186 
00187 PYROOT_STUB( add, +, PyStrings::gAdd )
00188 PYROOT_STUB( sub, -, PyStrings::gSub )
00189 PYROOT_STUB( mul, *, PyStrings::gMul )
00190 PYROOT_STUB( div, /, PyStrings::gDiv )
00191 
00192 //____________________________________________________________________________
00193    PyNumberMethods op_as_number = {
00194       (binaryfunc)op_add_stub,        // nb_add
00195       (binaryfunc)op_sub_stub,        // nb_subtract
00196       (binaryfunc)op_mul_stub,        // nb_multiply
00197 #if PY_VERSION_HEX < 0x03000000
00198       (binaryfunc)op_div_stub,        // nb_divide
00199 #endif
00200       0,                              // nb_remainder
00201       0,                              // nb_divmod
00202       0,                              // nb_power
00203       0,                              // nb_negative
00204       0,                              // nb_positive
00205       0,                              // nb_absolute
00206       0,                              // tp_nonzero (nb_bool in p3)
00207       0,                              // nb_invert
00208       0,                              // nb_lshift
00209       0,                              // nb_rshift
00210       0,                              // nb_and
00211       0,                              // nb_xor
00212       0,                              // nb_or
00213 #if PY_VERSION_HEX < 0x03000000
00214       0,                              // nb_coerce
00215 #endif
00216       0,                              // nb_int
00217       0,                              // nb_long (nb_reserved in p3)
00218       0,                              // nb_float
00219 #if PY_VERSION_HEX < 0x03000000
00220       0,                              // nb_oct
00221       0,                              // nb_hex
00222 #endif
00223       0,                              // nb_inplace_add
00224       0,                              // nb_inplace_subtract
00225       0,                              // nb_inplace_multiply
00226 #if PY_VERSION_HEX < 0x03000000
00227       0,                              // nb_inplace_divide
00228 #endif
00229       0,                              // nb_inplace_remainder
00230       0,                              // nb_inplace_power
00231       0,                              // nb_inplace_lshift
00232       0,                              // nb_inplace_rshift
00233       0,                              // nb_inplace_and
00234       0,                              // nb_inplace_xor
00235       0                               // nb_inplace_or
00236 #if PY_VERSION_HEX >= 0x02020000
00237       , 0                             // nb_floor_divide
00238 #if PY_VERSION_HEX < 0x03000000
00239       , 0                             // nb_true_divide
00240 #else
00241       , (binaryfunc)op_div_stub       // nb_true_divide
00242 #endif
00243       , 0                             // nb_inplace_floor_divide
00244       , 0                             // nb_inplace_true_divide
00245 #endif
00246 #if PY_VERSION_HEX >= 0x02050000
00247       , 0                             // nb_index
00248 #endif
00249    };
00250 
00251 } // unnamed namespace
00252 
00253 
00254 //= PyROOT object proxy type =================================================
00255 PyTypeObject ObjectProxy_Type = {
00256    PyVarObject_HEAD_INIT( &PyRootType_Type, 0 )
00257    (char*)"ROOT.ObjectProxy", // tp_name
00258    sizeof(ObjectProxy),       // tp_basicsize
00259    0,                         // tp_itemsize
00260    (destructor)op_dealloc,    // tp_dealloc
00261    0,                         // tp_print
00262    0,                         // tp_getattr
00263    0,                         // tp_setattr
00264    0,                         // tp_compare
00265    (reprfunc)op_repr,         // tp_repr
00266    &op_as_number,             // tp_as_number
00267    0,                         // tp_as_sequence
00268    0,                         // tp_as_mapping
00269    0,                         // tp_hash
00270    0,                         // tp_call
00271    0,                         // tp_str
00272    0,                         // tp_getattro
00273    0,                         // tp_setattro
00274    0,                         // tp_as_buffer
00275    Py_TPFLAGS_DEFAULT |
00276       Py_TPFLAGS_BASETYPE |
00277       Py_TPFLAGS_HAVE_GC |
00278       Py_TPFLAGS_CHECKTYPES,  // tp_flags
00279    (char*)"PyROOT object proxy (internal)",      // tp_doc
00280    0,                         // tp_traverse
00281    0,                         // tp_clear
00282    (richcmpfunc)op_richcompare,                  // tp_richcompare
00283    0,                         // tp_weaklistoffset
00284    0,                         // tp_iter
00285    0,                         // tp_iternext
00286    op_methods,                // tp_methods
00287    0,                         // tp_members
00288    0,                         // tp_getset
00289    0,                         // tp_base
00290    0,                         // tp_dict
00291    0,                         // tp_descr_get
00292    0,                         // tp_descr_set
00293    0,                         // tp_dictoffset
00294    0,                         // tp_init
00295    0,                         // tp_alloc
00296    (newfunc)op_new,           // tp_new
00297    0,                         // tp_free
00298    0,                         // tp_is_gc
00299    0,                         // tp_bases
00300    0,                         // tp_mro
00301    0,                         // tp_cache
00302    0,                         // tp_subclasses
00303    0                          // tp_weaklist
00304 #if PY_VERSION_HEX >= 0x02030000
00305    , 0                        // tp_del
00306 #endif
00307 #if PY_VERSION_HEX >= 0x02060000
00308    , 0                        // tp_version_tag
00309 #endif
00310 };
00311 
00312 } // namespace PyROOT

Generated on Tue Jul 5 14:10:13 2011 for ROOT_528-00b_version by  doxygen 1.5.1