Logo ROOT  
Reference Guide
PyzPythonHelpers.cxx
Go to the documentation of this file.
1 // Author: Stefan Wunsch CERN 08/2018
2 // Original PyROOT code by Wim Lavrijsen, LBL
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /**
13 
14 Set of helper functions that are invoked from the pythonizors, on the
15 Python side. For that purpose, they are included in the interface of the
16 PyROOT extension module.
17 
18 */
19 
20 #include "CPyCppyy.h"
21 #include "CPPInstance.h"
22 #include "CPPOverload.h"
23 
24 #include "PyROOTPythonize.h"
25 
26 #include "RConfig.h"
27 #include "TInterpreter.h"
28 
29 #include <sstream>
30 
31 // needed to properly resolve (dllimport) symbols on Windows
32 namespace CPyCppyy {
33  namespace PyStrings {
35  }
36 }
37 
38 ////////////////////////////////////////////////////////////////////////////
39 /// \brief Get size of C++ data-type
40 /// \param[in] self Always null, since this is a module function.
41 /// \param[in] args C++ data-type as Python string
42 ///
43 /// This function returns the length of a C++ data-type in bytes
44 /// as a Python integer.
46 {
47  // Get name of data-type
48  PyObject *pydtype = PyTuple_GetItem(args, 0);
49  std::string dtype = CPyCppyy_PyText_AsString(pydtype);
50 
51  // Call interpreter to get size of data-type using `sizeof`
52  size_t size = 0;
53  std::stringstream code;
54  code << "*((size_t*)" << std::showbase << (uintptr_t)&size << ") = (size_t)sizeof(" << dtype << ")";
55  gInterpreter->Calc(code.str().c_str());
56 
57  // Return size of data-type as integer
58  PyObject *pysize = PyInt_FromLong(size);
59  return pysize;
60 }
61 
62 ////////////////////////////////////////////////////////////////////////////
63 /// \brief Get pointer to the data of an object
64 /// \param[in] self Always null, since this is a module function.
65 /// \param[in] args[0] Python representation of the C++ object.
66 /// \param[in] args[1] Data-type of the C++ object as Python string
67 /// \param[in] args[2] Method to be called on the C++ object to get the data pointer as Python string
68 ///
69 /// This function returns the pointer to the data of an object as an Python
70 /// integer retrieved by the given method.
72 {
73  // Get pointer of C++ object
74  PyObject *pyobj = PyTuple_GetItem(args, 0);
75  auto instance = (CPyCppyy::CPPInstance *)(pyobj);
76  auto cppobj = instance->GetObject();
77 
78  // Get name of C++ object as string
79  PyObject *pycppname = PyTuple_GetItem(args, 1);
80  std::string cppname = CPyCppyy_PyText_AsString(pycppname);
81 
82  // Get name of method to be called to get the data pointer
83  PyObject *pymethodname = PyTuple_GetItem(args, 2);
84  std::string methodname = CPyCppyy_PyText_AsString(pymethodname);
85 
86  // Call interpreter to get pointer to data
87  uintptr_t pointer = 0;
88  std::stringstream code;
89  code << "*((intptr_t*)" << std::showbase << (uintptr_t)&pointer << ") = reinterpret_cast<uintptr_t>(reinterpret_cast<"
90  << cppname << "*>(" << std::showbase << (uintptr_t)cppobj << ")->" << methodname << "())";
91  gInterpreter->Calc(code.str().c_str());
92 
93  // Return pointer as integer
94  PyObject *pypointer = PyLong_FromUnsignedLongLong(pointer);
95  return pypointer;
96 }
97 
98 ////////////////////////////////////////////////////////////////////////////
99 /// \brief Get endianess of the system
100 /// \param[in] self Always null, since this is a module function.
101 /// \param[in] args Pointer to an empty Python tuple.
102 /// \return Endianess as Python string
103 ///
104 /// This function returns endianess of the system as a Python integer. The
105 /// return value is either '<' or '>' for little or big endian, respectively.
106 PyObject *PyROOT::GetEndianess(PyObject * /* self */, PyObject * /* args */)
107 {
108 #ifdef R__BYTESWAP
109  return CPyCppyy_PyText_FromString("<");
110 #else
111  return CPyCppyy_PyText_FromString(">");
112 #endif
113 }
114 
115 using namespace CPyCppyy;
116 
117 // Helper to add base class methods to the derived class one
118 static bool AddUsingToClass(PyObject *pyclass, const char *method)
119 {
120  CPPOverload *derivedMethod = (CPPOverload *)PyObject_GetAttrString(pyclass, const_cast<char *>(method));
121  if (!CPPOverload_Check(derivedMethod)) {
122  Py_XDECREF(derivedMethod);
123  return false;
124  }
125 
126  PyObject *mro = PyObject_GetAttr(pyclass, PyStrings::gMRO);
127  if (!mro || !PyTuple_Check(mro)) {
128  Py_XDECREF(mro);
129  Py_DECREF(derivedMethod);
130  return false;
131  }
132 
133  CPPOverload *baseMethod = nullptr;
134  for (int i = 1; i < PyTuple_GET_SIZE(mro); ++i) {
135  baseMethod = (CPPOverload *)PyObject_GetAttrString(PyTuple_GET_ITEM(mro, i), const_cast<char *>(method));
136 
137  if (!baseMethod) {
138  PyErr_Clear();
139  continue;
140  }
141 
142  if (CPPOverload_Check(baseMethod))
143  break;
144 
145  Py_DECREF(baseMethod);
146  baseMethod = nullptr;
147  }
148 
149  Py_DECREF(mro);
150 
151  if (!CPPOverload_Check(baseMethod)) {
152  Py_XDECREF(baseMethod);
153  Py_DECREF(derivedMethod);
154  return false;
155  }
156 
157  for (PyCallable *pc : baseMethod->fMethodInfo->fMethods) {
158  derivedMethod->AdoptMethod(pc->Clone());
159  }
160 
161  Py_DECREF(baseMethod);
162  Py_DECREF(derivedMethod);
163 
164  return true;
165 }
166 
167 ////////////////////////////////////////////////////////////////////////////
168 /// \brief Add base class overloads of a given method to a derived class
169 /// \param[in] self Always null, since this is a module function.
170 /// \param[in] args[0] Derived class.
171 /// \param[in] args[1] Name of the method whose base class overloads to
172 /// inject in the derived class.
173 ///
174 /// This function adds base class overloads to a derived class for a given
175 /// method. This covers the 'using' case, which is not supported by default
176 /// by the bindings.
178 {
179  // Get derived class to pythonize
180  PyObject *pyclass = PyTuple_GetItem(args, 0);
181 
182  // Get method name where to add overloads
183  PyObject *pyname = PyTuple_GetItem(args, 1);
184  auto cppname = CPyCppyy_PyText_AsString(pyname);
185 
186  AddUsingToClass(pyclass, cppname);
187 
189 }
CPyCppyy
Set of helper functions that are invoked from the pythonizors, on the Python side.
Definition: TPyClassGenerator.cxx:31
CPPInstance.h
PyROOT::GetDataPointer
PyObject * GetDataPointer(PyObject *self, PyObject *args)
Get pointer to the data of an object.
Definition: PyzPythonHelpers.cxx:71
PyObject
_object PyObject
Definition: PyMethodBase.h:42
pyname
#define pyname
Definition: TMCParticle.cxx:19
PyROOTPythonize.h
gInterpreter
#define gInterpreter
Definition: TInterpreter.h:560
CPyCppyy::CPPInstance
Definition: CPPInstance.h:26
CPyCppyy::PyCallable
Definition: PyCallable.h:12
TGeant4Unit::pc
static constexpr double pc
Definition: TGeant4SystemOfUnits.h:130
PyROOT::GetSizeOfType
PyObject * GetSizeOfType(PyObject *self, PyObject *args)
Get size of C++ data-type.
Definition: PyzPythonHelpers.cxx:45
CPyCppyy::PyStrings::gMRO
PyObject * gMRO
Definition: PyzPythonHelpers.cxx:34
CPyCppyy_PyText_FromString
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
CPyCppyy::CPPOverload_Check
bool CPPOverload_Check(T *object)
Definition: CPPOverload.h:79
CPyCppyy.h
AddUsingToClass
static bool AddUsingToClass(PyObject *pyclass, const char *method)
Definition: PyzPythonHelpers.cxx:118
CPyCppyy::CPPOverload::AdoptMethod
void AdoptMethod(PyCallable *pc)
Definition: CPPOverload.cxx:942
CPyCppyy_PyText_AsString
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
RooFit_internal::instance
static Roo_reg_AGKInteg1D instance
Definition: RooAdaptiveGaussKronrodIntegrator1D.cxx:153
PyInt_FromLong
PyInt_FromLong
Definition: Converters.cxx:858
TInterpreter.h
PyROOT::GetEndianess
PyObject * GetEndianess(PyObject *self, PyObject *args)
Get endianess of the system.
Definition: PyzPythonHelpers.cxx:106
CPPOverload.h
PyROOT::AddUsingToClass
PyObject * AddUsingToClass(PyObject *self, PyObject *args)
Add base class overloads of a given method to a derived class.
Definition: PyzPythonHelpers.cxx:177
CPyCppyy::CPPOverload
Definition: CPPOverload.h:36
R__EXTERN
#define R__EXTERN
Definition: DllImport.h:27
CPyCppyy::CPPOverload::MethodInfo_t::fMethods
CPPOverload::Methods_t fMethods
Definition: CPPOverload.h:47
CPyCppyy::CPPOverload::fMethodInfo
MethodInfo_t * fMethodInfo
Definition: CPPOverload.h:68
Py_RETURN_NONE
#define Py_RETURN_NONE
Definition: CPyCppyy.h:281