| # Gaudi Framework, version v21r11 |

Home |  | Generated: 30 Sep 2010

# PyROOTPickle.cpp

Go to the documentation of this file.

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