PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/pyroot/PyROOTPickle.cxx

https://bitbucket.org/binet/mana-core-rootutils
C++ | 134 lines | 76 code | 27 blank | 31 comment | 8 complexity | 210496e20239d8e4f5df2d2708cef63c MD5 | raw file
  1. /**
  2. * @file RootUtils/src/pyroot/PyROOTPickle.cxx
  3. * @author Wim Lavrijsen
  4. * @date Apr 2008
  5. * @brief Port pickling functionality while awaiting newer release.
  6. */
  7. #include "RootUtils/PyROOTPickle.h"
  8. #include "Python.h"
  9. #include "TClass.h"
  10. #include "TBufferFile.h"
  11. #include "TPython.h"
  12. //- data _______________________________________________________________________
  13. static PyObject* gExpand = 0;
  14. namespace RootUtils {
  15. /**
  16. * @brief PyROOT object proxy pickle support
  17. * @param self object proxy instance to be pickled
  18. */
  19. PyObject* ObjectProxyReduce( PyObject* self )
  20. {
  21. // Turn the object proxy instance into a character stream and return for
  22. // pickle, together with the callable object that can restore the stream
  23. // into the object proxy instance.
  24. void* vself = TPython::ObjectProxy_AsVoidPtr( self ); // checks type
  25. if ( ! vself ) {
  26. PyErr_SetString( PyExc_TypeError,
  27. "__reduce__ requires an object proxy instance as first argument" );
  28. return 0;
  29. }
  30. PyObject* nattr = PyObject_GetAttrString( (PyObject*)self->ob_type, (char*)"__name__" );
  31. PyObject* pyname = PyObject_Str( nattr );
  32. Py_DECREF( nattr );
  33. TClass* klass = TClass::GetClass( PyString_AS_STRING( pyname ) );
  34. // no cast is needed, but WriteObject taking a TClass argument is protected,
  35. // so use WriteObjectAny()
  36. TBufferFile buf( TBuffer::kWrite );
  37. if ( buf.WriteObjectAny( vself, klass ) != 1 ) {
  38. PyErr_Format( PyExc_IOError,
  39. "could not stream object of type %s", PyString_AS_STRING( pyname ) );
  40. Py_DECREF( pyname );
  41. return 0;
  42. }
  43. // use a string for the serialized result, as a python buffer will not copy
  44. // the buffer contents; use a string for the class name, used when casting
  45. // on reading back in
  46. PyObject* res2 = PyTuple_New( 2 );
  47. PyTuple_SET_ITEM( res2, 0, PyString_FromStringAndSize( buf.Buffer(), buf.Length() ) );
  48. PyTuple_SET_ITEM( res2, 1, pyname );
  49. PyObject* result = PyTuple_New( 2 );
  50. Py_INCREF( gExpand );
  51. PyTuple_SET_ITEM( result, 0, gExpand );
  52. PyTuple_SET_ITEM( result, 1, res2 );
  53. return result;
  54. }
  55. /**
  56. * @brief Helper for (un)pickling of ObjectProxy's
  57. * @param args The Python arguments.
  58. */
  59. PyObject* ObjectProxyExpand( PyObject*, PyObject* args )
  60. {
  61. // This method is a helper for (un)pickling of ObjectProxy instances.
  62. PyObject* pybuf = 0;
  63. const char* clname = 0;
  64. if ( ! PyArg_ParseTuple( args, const_cast< char* >( "O!s:__expand__" ),
  65. &PyString_Type, &pybuf, &clname ) )
  66. return 0;
  67. // use the PyString macros to by-pass error checking; do not adopt the buffer,
  68. // as the local TBufferFile can go out of scope (there is no copying)
  69. TBufferFile buf( TBuffer::kRead,
  70. PyString_GET_SIZE( pybuf ), PyString_AS_STRING( pybuf ), kFALSE );
  71. void* result = buf.ReadObjectAny( 0 );
  72. return TPython::ObjectProxy_FromVoidPtr( result, clname );
  73. }
  74. /**
  75. * @brief Install the pickling of ObjectProxy's functionality.
  76. * @param libpyroot_pymodule The libPyROOT python module
  77. * @param objectproxy_pytype The ObjectProxy python type
  78. */
  79. void PyROOTPickle::Initialize( PyObject* libpyroot_pymodule, PyObject* objectproxy_pytype )
  80. {
  81. Py_INCREF( libpyroot_pymodule );
  82. PyTypeObject* pytype = (PyTypeObject*)objectproxy_pytype;
  83. static PyMethodDef s_pdefExp = { (char*)"_ObjectProxy__expand__",
  84. (PyCFunction)ObjectProxyExpand, METH_VARARGS, (char*)"internal function" };
  85. PyObject* pymname = PyString_FromString( PyModule_GetName( libpyroot_pymodule ) );
  86. gExpand = PyCFunction_NewEx( &s_pdefExp, NULL, pymname );
  87. Py_DECREF( pymname );
  88. Bool_t isOk = PyObject_SetAttrString( libpyroot_pymodule, s_pdefExp.ml_name, gExpand ) == 0;
  89. Py_DECREF( gExpand ); // is moderately risky, but Weakref not allowed (?)
  90. if ( ! isOk ) {
  91. Py_DECREF( libpyroot_pymodule );
  92. PyErr_SetString( PyExc_TypeError, "could not add expand function to libPyROOT" );
  93. return;
  94. }
  95. static PyMethodDef s_pdefRed = { (char*)"__reduce__",
  96. (PyCFunction)ObjectProxyReduce, METH_NOARGS, (char*)"internal function" };
  97. PyObject* descr = PyDescr_NewMethod( pytype, &s_pdefRed );
  98. isOk = PyDict_SetItemString( pytype->tp_dict, s_pdefRed.ml_name, descr) == 0;
  99. Py_DECREF( descr );
  100. if ( ! isOk ) {
  101. Py_DECREF( libpyroot_pymodule );
  102. PyErr_SetString( PyExc_TypeError, "could not add __reduce__ function to ObjectProxy" );
  103. return;
  104. }
  105. Py_DECREF( libpyroot_pymodule );
  106. }
  107. } // namespace RootUtils