Gaudi Framework, version v20r4

Generated: 8 Jan 2009

PyROOTPickle.cpp

Go to the documentation of this file.
00001 
00008 #include "GaudiPython/PyROOTPickle.h"
00009 #include "Python.h"
00010 #include "TClass.h"
00011 #include "TClassRef.h"
00012 #include "TBufferFile.h"
00013 #include "TPython.h"
00014 #include "RVersion.h"
00015 
00016 //- data _______________________________________________________________________
00017 #if ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
00018 static PyObject* gExpand = 0;
00019 #endif
00020 
00021 namespace GaudiPython {
00022 
00023 #if ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
00024 
00029 PyObject* ObjectProxyReduce( PyObject* self )
00030 {
00031   // Turn the object proxy instance into a character stream and return for
00032   // pickle, together with the callable object that can restore the stream
00033   // into the object proxy instance.
00034 
00035   void* vself = TPython::ObjectProxy_AsVoidPtr( self );    // checks type
00036   if ( ! vself ) {
00037      PyErr_SetString( PyExc_TypeError,
00038        "__reduce__ requires an object proxy instance as first argument" );
00039      return 0;
00040   }
00041 
00042   PyObject* nattr = PyObject_GetAttrString( (PyObject*)self->ob_type, (char*)"__name__" );
00043   PyObject* pyname = PyObject_Str( nattr );
00044   Py_DECREF( nattr );
00045 
00046   static TClass* bufferclass =  TClass::GetClass("TBufferFile");
00047   TClass* klass = TClass::GetClass( PyString_AS_STRING( pyname ) );
00048 
00049   // no cast is needed, but WriteObject taking a TClass argument is protected,
00050   // so use WriteObjectAny()
00051   TBufferFile* buf = 0;
00052   if ( klass == bufferclass ) {
00053      buf = (TBufferFile*)vself;
00054   }
00055   else {
00056      static TBufferFile buffer( TBuffer::kWrite );
00057      buffer.Reset();
00058      if ( buffer.WriteObjectAny( vself, klass ) != 1 ) {
00059         PyErr_Format( PyExc_IOError,
00060            "could not stream object of type %s", PyString_AS_STRING( pyname ) );
00061         Py_DECREF( pyname );
00062         return 0;
00063      }
00064      buf = &buffer;
00065   }
00066 
00067   // use a string for the serialized result, as a python buffer will not copy
00068   // the buffer contents; use a string for the class name, used when casting
00069   // on reading back in
00070   PyObject* res2 = PyTuple_New( 2 );
00071   PyTuple_SET_ITEM( res2, 0, PyString_FromStringAndSize( buf->Buffer(), buf->Length() ) );
00072   PyTuple_SET_ITEM( res2, 1, pyname );
00073 
00074   PyObject* result = PyTuple_New( 2 );
00075   Py_INCREF( gExpand );
00076   PyTuple_SET_ITEM( result, 0, gExpand );
00077   PyTuple_SET_ITEM( result, 1, res2 );
00078 
00079   return result;
00080 }
00081 
00082 
00083 class ObjectProxy {
00084    public:
00085       enum EFlags { kNone = 0x0, kIsOwner = 0x0001, kIsReference = 0x0002 };
00086 
00087    public:
00088       void HoldOn() { fFlags |= kIsOwner; }
00089       void Release() { fFlags &= ~kIsOwner; }
00090    public:               // public, as the python C-API works with C structs
00091       PyObject_HEAD
00092       void*     fObject;
00093       TClassRef fClass;
00094       int       fFlags;
00095    private:              // private, as the python C-API will handle creation
00096       ObjectProxy() {}
00097 };
00098 
00099 
00104 PyObject* ObjectProxyExpand( PyObject*, PyObject* args )
00105 {
00106   // This method is a helper for (un)pickling of ObjectProxy instances.
00107   PyObject* pybuf = 0;
00108   const char* clname = 0;
00109   if ( ! PyArg_ParseTuple( args, const_cast< char* >( "O!s:__expand__" ),
00110            &PyString_Type, &pybuf, &clname ) )
00111     return 0;
00112 
00113   // use the PyString macro's to by-pass error checking; do not adopt the buffer,
00114   // as the local TBufferFile can go out of scope (there is no copying)
00115   void* result;
00116   if( strcmp(clname, "TBufferFile") == 0) {
00117     TBufferFile* buf = new TBufferFile( TBuffer::kWrite);
00118     buf->WriteFastArray( PyString_AS_STRING(pybuf), PyString_GET_SIZE( pybuf ));
00119     result = buf;
00120   }
00121   else {
00122     TBufferFile buf( TBuffer::kRead,
00123        PyString_GET_SIZE( pybuf ), PyString_AS_STRING( pybuf ), kFALSE );
00124     result = buf.ReadObjectAny( 0 );
00125   }
00126   PyObject* pobj =  TPython::ObjectProxy_FromVoidPtr( result, clname );
00127   // set Ownership of the returned object
00128   ObjectProxy* obj = (ObjectProxy*)pobj;
00129   obj->HoldOn();
00130   return pobj;
00131 }
00132 
00133 
00139 void PyROOTPickle::Initialize( PyObject* libpyroot_pymodule, PyObject* objectproxy_pytype )
00140 {
00141   Py_INCREF( libpyroot_pymodule );
00142   PyTypeObject* pytype = (PyTypeObject*)objectproxy_pytype;
00143 
00144   static PyMethodDef s_pdefExp = { (char*)"_ObjectProxy__expand__",
00145             (PyCFunction)ObjectProxyExpand, METH_VARARGS, (char*)"internal function" };
00146 
00147   PyObject* pymname = PyString_FromString( PyModule_GetName( libpyroot_pymodule ) );
00148   gExpand = PyCFunction_NewEx( &s_pdefExp, NULL, pymname );
00149   Py_DECREF( pymname );
00150   Bool_t isOk = PyObject_SetAttrString( libpyroot_pymodule, s_pdefExp.ml_name, gExpand ) == 0;
00151   Py_DECREF( gExpand );      // is moderately risky, but Weakref not allowed (?)
00152 
00153   if ( ! isOk ) {
00154     Py_DECREF( libpyroot_pymodule );
00155     PyErr_SetString( PyExc_TypeError, "could not add expand function to libPyROOT" );
00156     return;
00157   }
00158 
00159   static PyMethodDef s_pdefRed = { (char*)"__reduce__",
00160             (PyCFunction)ObjectProxyReduce, METH_NOARGS, (char*)"internal function" };
00161 
00162   PyObject* descr = PyDescr_NewMethod( pytype, &s_pdefRed );
00163   isOk = PyDict_SetItemString( pytype->tp_dict, s_pdefRed.ml_name, descr) == 0;
00164   Py_DECREF( descr );
00165   if ( ! isOk ) {
00166     Py_DECREF( libpyroot_pymodule );
00167     PyErr_SetString( PyExc_TypeError, "could not add __reduce__ function to ObjectProxy" );
00168     return;
00169   }
00170 
00171   Py_DECREF( libpyroot_pymodule );
00172 }
00173 
00174 #else //  ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
00175 
00176 void PyROOTPickle::Initialize( PyObject*, PyObject* )
00177 {
00178   /* dummy. It is not needed for this version of ROOT */
00179 }
00180 
00181 #endif //  ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
00182 
00183 } // namespace GaudiPython

Generated at Thu Jan 8 17:44:22 2009 for Gaudi Framework, version v20r4 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004