Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 #if ROOT_VERSION_CODE < ROOT_VERSION( 5, 19, 0 )
29 
34  PyObject* ObjectProxyReduce( PyObject* self ) {
35  // Turn the object proxy instance into a character stream and return for
36  // pickle, together with the callable object that can restore the stream
37  // into the object proxy instance.
38 
39  void* vself = TPython::ObjectProxy_AsVoidPtr( self ); // checks type
40  if ( !vself ) {
41  PyErr_SetString( PyExc_TypeError, "__reduce__ requires an object proxy instance as first argument" );
42  return 0;
43  }
44 
45  PyObject* nattr = PyObject_GetAttrString( (PyObject*)self->ob_type, (char*)"__name__" );
46  PyObject* pyname = PyObject_Str( nattr );
47  Py_DECREF( nattr );
48 
49  static TClass* bufferclass = TClass::GetClass( "TBufferFile" );
50  TClass* klass = TClass::GetClass( PyString_AS_STRING( pyname ) );
51 
52  // no cast is needed, but WriteObject taking a TClass argument is protected,
53  // so use WriteObjectAny()
54  TBufferFile* buf = 0;
55  if ( klass == bufferclass ) {
56  buf = (TBufferFile*)vself;
57  } else {
58  static TBufferFile buffer( TBuffer::kWrite );
59  buffer.Reset();
60  if ( buffer.WriteObjectAny( vself, klass ) != 1 ) {
61  PyErr_Format( PyExc_IOError, "could not stream object of type %s", PyString_AS_STRING( pyname ) );
62  Py_DECREF( pyname );
63  return 0;
64  }
65  buf = &buffer;
66  }
67 
68  // use a string for the serialized result, as a python buffer will not copy
69  // the buffer contents; use a string for the class name, used when casting
70  // on reading back in
71  PyObject* res2 = PyTuple_New( 2 );
72  PyTuple_SET_ITEM( res2, 0, PyString_FromStringAndSize( buf->Buffer(), buf->Length() ) );
73  PyTuple_SET_ITEM( res2, 1, pyname );
74 
75  PyObject* result = PyTuple_New( 2 );
76  Py_INCREF( gExpand );
77  PyTuple_SET_ITEM( result, 0, gExpand );
78  PyTuple_SET_ITEM( result, 1, res2 );
79 
80  return result;
81  }
82 
83  class ObjectProxy {
84  public:
85  enum EFlags { kNone = 0x0, kIsOwner = 0x0001, kIsReference = 0x0002 };
86 
87  public:
88  void HoldOn() { fFlags |= kIsOwner; }
89  void Release() { fFlags &= ~kIsOwner; }
90 
91  public: // public, as the python C-API works with C structs
92  PyObject_HEAD void* fObject;
93  TClassRef fClass;
94  int fFlags;
95 
96  private: // private, as the python C-API will handle creation
97  ObjectProxy() {}
98  };
99 
104  PyObject* ObjectProxyExpand( PyObject*, PyObject* args ) {
105  // This method is a helper for (un)pickling of ObjectProxy instances.
106  PyObject* pybuf = 0;
107  const char* clname = 0;
108  if ( !PyArg_ParseTuple( args, const_cast<char*>( "O!s:__expand__" ), &PyString_Type, &pybuf, &clname ) ) return 0;
109 
110  // use the PyString macro's to by-pass error checking; do not adopt the buffer,
111  // as the local TBufferFile can go out of scope (there is no copying)
112  void* result;
113  if ( strcmp( clname, "TBufferFile" ) == 0 ) {
114  TBufferFile* buf = new TBufferFile( TBuffer::kWrite );
115  buf->WriteFastArray( PyString_AS_STRING( pybuf ), PyString_GET_SIZE( pybuf ) );
116  result = buf;
117  } else {
118  TBufferFile buf( TBuffer::kRead, PyString_GET_SIZE( pybuf ), PyString_AS_STRING( pybuf ), kFALSE );
119  result = buf.ReadObjectAny( 0 );
120  }
121  PyObject* pobj = TPython::ObjectProxy_FromVoidPtr( result, clname );
122  // set Ownership of the returned object
123  ObjectProxy* obj = (ObjectProxy*)pobj;
124  obj->HoldOn();
125  return pobj;
126  }
127 
133  void PyROOTPickle::Initialize( PyObject* libpyroot_pymodule, PyObject* objectproxy_pytype ) {
134  Py_INCREF( libpyroot_pymodule );
135  PyTypeObject* pytype = (PyTypeObject*)objectproxy_pytype;
136 
137  static PyMethodDef s_pdefExp = {(char*)"_ObjectProxy__expand__", (PyCFunction)ObjectProxyExpand, METH_VARARGS,
138  (char*)"internal function"};
139 
140  PyObject* pymname = PyString_FromString( PyModule_GetName( libpyroot_pymodule ) );
141  gExpand = PyCFunction_NewEx( &s_pdefExp, NULL, pymname );
142  Py_DECREF( pymname );
143  Bool_t isOk = PyObject_SetAttrString( libpyroot_pymodule, s_pdefExp.ml_name, gExpand ) == 0;
144  Py_DECREF( gExpand ); // is moderately risky, but Weakref not allowed (?)
145 
146  if ( !isOk ) {
147  Py_DECREF( libpyroot_pymodule );
148  PyErr_SetString( PyExc_TypeError, "could not add expand function to libPyROOT" );
149  return;
150  }
151 
152  static PyMethodDef s_pdefRed = {(char*)"__reduce__", (PyCFunction)ObjectProxyReduce, METH_NOARGS,
153  (char*)"internal function"};
154 
155  PyObject* descr = PyDescr_NewMethod( pytype, &s_pdefRed );
156  isOk = PyDict_SetItemString( pytype->tp_dict, s_pdefRed.ml_name, descr ) == 0;
157  Py_DECREF( descr );
158  if ( !isOk ) {
159  Py_DECREF( libpyroot_pymodule );
160  PyErr_SetString( PyExc_TypeError, "could not add __reduce__ function to ObjectProxy" );
161  return;
162  }
163 
164  Py_DECREF( libpyroot_pymodule );
165  }
166 
167 #else // ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
168 
169  void PyROOTPickle::Initialize( PyObject*, PyObject* ) { /* dummy. It is not needed for this version of ROOT */
170  }
171 
172 #endif // ROOT_VERSION_CODE < ROOT_VERSION(5,19,0)
173 
174 } // 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.