| # 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