The Gaudi Framework  v29r0 (ff2e7097)
PyROOTPickle.cpp
Go to the documentation of this file.
1 
8 #ifdef __ICC
9 // disable icc remark #2259: non-pointer conversion from "X" to "Y" may lose significant bits
10 // TODO: To be removed, since it comes from ROOT
11 #pragma warning( disable : 2259 )
12 #endif
13 
14 #include "GaudiMP/PyROOTPickle.h"
15 #include "RVersion.h"
16 #include "TBufferFile.h"
17 #include "TClass.h"
18 #include "TClassRef.h"
19 #include "TPython.h"
20 
21 //- data _______________________________________________________________________
22 #if ROOT_VERSION_CODE < ROOT_VERSION( 5, 19, 0 )
23 static PyObject* gExpand = 0;
24 #endif
25 
26 namespace GaudiMP
27 {
28 
29 #if ROOT_VERSION_CODE < ROOT_VERSION( 5, 19, 0 )
30 
35  PyObject* ObjectProxyReduce( PyObject* self )
36  {
37  // Turn the object proxy instance into a character stream and return for
38  // pickle, together with the callable object that can restore the stream
39  // into the object proxy instance.
40 
41  void* vself = TPython::ObjectProxy_AsVoidPtr( self ); // checks type
42  if ( !vself ) {
43  PyErr_SetString( PyExc_TypeError, "__reduce__ requires an object proxy instance as first argument" );
44  return 0;
45  }
46 
47  PyObject* nattr = PyObject_GetAttrString( (PyObject*)self->ob_type, (char*)"__name__" );
48  PyObject* pyname = PyObject_Str( nattr );
49  Py_DECREF( nattr );
50 
51  static TClass* bufferclass = TClass::GetClass( "TBufferFile" );
52  TClass* klass = TClass::GetClass( PyString_AS_STRING( pyname ) );
53 
54  // no cast is needed, but WriteObject taking a TClass argument is protected,
55  // so use WriteObjectAny()
56  TBufferFile* buf = 0;
57  if ( klass == bufferclass ) {
58  buf = (TBufferFile*)vself;
59  } else {
60  static TBufferFile buffer( TBuffer::kWrite );
61  buffer.Reset();
62  if ( buffer.WriteObjectAny( vself, klass ) != 1 ) {
63  PyErr_Format( PyExc_IOError, "could not stream object of type %s", PyString_AS_STRING( pyname ) );
64  Py_DECREF( pyname );
65  return 0;
66  }
67  buf = &buffer;
68  }
69 
70  // use a string for the serialized result, as a python buffer will not copy
71  // the buffer contents; use a string for the class name, used when casting
72  // on reading back in
73  PyObject* res2 = PyTuple_New( 2 );
74  PyTuple_SET_ITEM( res2, 0, PyString_FromStringAndSize( buf->Buffer(), buf->Length() ) );
75  PyTuple_SET_ITEM( res2, 1, pyname );
76 
77  PyObject* result = PyTuple_New( 2 );
78  Py_INCREF( gExpand );
79  PyTuple_SET_ITEM( result, 0, gExpand );
80  PyTuple_SET_ITEM( result, 1, res2 );
81 
82  return result;
83  }
84 
85  class ObjectProxy
86  {
87  public:
88  enum EFlags { kNone = 0x0, kIsOwner = 0x0001, kIsReference = 0x0002 };
89 
90  public:
91  void HoldOn() { fFlags |= kIsOwner; }
92  void Release() { fFlags &= ~kIsOwner; }
93 
94  public: // public, as the python C-API works with C structs
95  PyObject_HEAD void* fObject;
96  TClassRef fClass;
97  int fFlags;
98 
99  private: // private, as the python C-API will handle creation
100  ObjectProxy() {}
101  };
102 
107  PyObject* ObjectProxyExpand( PyObject*, PyObject* args )
108  {
109  // This method is a helper for (un)pickling of ObjectProxy instances.
110  PyObject* pybuf = 0;
111  const char* clname = 0;
112  if ( !PyArg_ParseTuple( args, const_cast<char*>( "O!s:__expand__" ), &PyString_Type, &pybuf, &clname ) ) return 0;
113 
114  // use the PyString macro's to by-pass error checking; do not adopt the buffer,
115  // as the local TBufferFile can go out of scope (there is no copying)
116  void* result;
117  if ( strcmp( clname, "TBufferFile" ) == 0 ) {
118  TBufferFile* buf = new TBufferFile( TBuffer::kWrite );
119  buf->WriteFastArray( PyString_AS_STRING( pybuf ), PyString_GET_SIZE( pybuf ) );
120  result = buf;
121  } else {
122  TBufferFile buf( TBuffer::kRead, PyString_GET_SIZE( pybuf ), PyString_AS_STRING( pybuf ), kFALSE );
123  result = buf.ReadObjectAny( 0 );
124  }
125  PyObject* pobj = TPython::ObjectProxy_FromVoidPtr( result, clname );
126  // set Ownership of the returned object
127  ObjectProxy* obj = (ObjectProxy*)pobj;
128  obj->HoldOn();
129  return pobj;
130  }
131 
137  void PyROOTPickle::Initialize( PyObject* libpyroot_pymodule, PyObject* objectproxy_pytype )
138  {
139  Py_INCREF( libpyroot_pymodule );
140  PyTypeObject* pytype = (PyTypeObject*)objectproxy_pytype;
141 
142  static PyMethodDef s_pdefExp = {(char*)"_ObjectProxy__expand__", (PyCFunction)ObjectProxyExpand, METH_VARARGS,
143  (char*)"internal function"};
144 
145  PyObject* pymname = PyString_FromString( PyModule_GetName( libpyroot_pymodule ) );
146  gExpand = PyCFunction_NewEx( &s_pdefExp, NULL, pymname );
147  Py_DECREF( pymname );
148  Bool_t isOk = PyObject_SetAttrString( libpyroot_pymodule, s_pdefExp.ml_name, gExpand ) == 0;
149  Py_DECREF( gExpand ); // is moderately risky, but Weakref not allowed (?)
150 
151  if ( !isOk ) {
152  Py_DECREF( libpyroot_pymodule );
153  PyErr_SetString( PyExc_TypeError, "could not add expand function to libPyROOT" );
154  return;
155  }
156 
157  static PyMethodDef s_pdefRed = {(char*)"__reduce__", (PyCFunction)ObjectProxyReduce, METH_NOARGS,
158  (char*)"internal function"};
159 
160  PyObject* descr = PyDescr_NewMethod( pytype, &s_pdefRed );
161  isOk = PyDict_SetItemString( pytype->tp_dict, s_pdefRed.ml_name, descr ) == 0;
162  Py_DECREF( descr );
163  if ( !isOk ) {
164  Py_DECREF( libpyroot_pymodule );
165  PyErr_SetString( PyExc_TypeError, "could not add __reduce__ function to ObjectProxy" );
166  return;
167  }
168 
169  Py_DECREF( libpyroot_pymodule );
170  }
171 
172 #else // ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
173 
174  void PyROOTPickle::Initialize( PyObject*, PyObject* ) { /* dummy. It is not needed for this version of ROOT */}
175 
176 #endif // ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
177 
178 } // namespace GaudiMP
A class to serialize/deserialize TES objects to and from a TBufferFile Author: P. ...
Definition: PyROOTPickle.h:31
static void Initialize(PyObject *libpyroot_pymodule, PyObject *objectproxy_pytype)
Install the pickling of ObjectProxy&#39;s functionality.
T strcmp(T...args)
Port pickling functionality while awaiting newer release.