Logo ROOT  
Reference Guide
PyzCppHelpers.cxx
Go to the documentation of this file.
1 // Author: Danilo Piparo CERN 08/2018
2 
3 /*************************************************************************
4  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 /**
12 
13 Set of helper functions that are invoked from the C++ implementation of
14 pythonizations.
15 
16 */
17 #include "PyzCppHelpers.hxx"
18 
19 // Call method with signature: obj->meth()
20 PyObject *CallPyObjMethod(PyObject *obj, const char *meth)
21 {
22  return PyObject_CallMethod(obj, const_cast<char *>(meth), const_cast<char *>(""));
23 }
24 
25 // Call method with signature: obj->meth(arg1)
26 PyObject *CallPyObjMethod(PyObject *obj, const char *meth, PyObject *arg1)
27 {
28  return PyObject_CallMethod(obj, const_cast<char *>(meth), const_cast<char *>("O"), arg1);
29 }
30 
31 // Convert generic python object into a boolean value
33 {
34  if (PyObject_IsTrue(value) == 1) {
35  Py_DECREF(value);
37  } else {
38  Py_XDECREF(value);
40  }
41 }
42 
43 // Get the TClass of the C++ object proxied by pyobj
45 {
46  return TClass::GetClass(Cppyy::GetScopedFinalName(pyobj->ObjectIsA()).c_str());
47 }
48 
49 ////////////////////////////////////////////////////////////////////////////
50 /// \brief Convert Numpy data-type string to the according C++ data-type string
51 /// \param[in] dtype Numpy data-type string
52 /// \return C++ data-type string
53 ///
54 /// If the input data-tyep is not known, the function returns an empty string.
55 std::string GetCppTypeFromNumpyType(const std::string& dtype) {
56  if (dtype == "i4") {
57  return "int";
58  } else if (dtype == "u4") {
59  return "unsigned int";
60  } else if (dtype == "i8") {
61  return "Long64_t";
62  } else if (dtype == "u8") {
63  return "ULong64_t";
64  } else if (dtype == "f4") {
65  return "float";
66  } else if (dtype == "f8") {
67  return "double";
68  } else {
69  PyErr_SetString(PyExc_RuntimeError, ("Object not convertible: Python object has unknown data-type '" + dtype + "'.").c_str());
70  return "";
71  }
72 }
73 
74 ////////////////////////////////////////////////////////////////////////////
75 /// \brief Get Numpy array interface and perform error handling
76 /// \param[in] obj PyObject with array interface dictionary
77 /// \return Array interface dictionary
79 {
80  auto pyinterface = PyObject_GetAttrString(obj, "__array_interface__");
81  if (!pyinterface) {
82  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: __array_interface__ does not exist.");
83  return NULL;
84  }
85  if (!PyDict_Check(pyinterface)) {
86  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: __array_interface__ is not a dictionary.");
87  return NULL;
88  }
89  return pyinterface;
90 }
91 
92 ////////////////////////////////////////////////////////////////////////////
93 /// \brief Get data pointer from Numpy array interface and perform error handling
94 /// \param[in] obj Array interface dictionary
95 /// \return Data pointer
97 {
98  auto pydata = PyDict_GetItemString(obj, "data");
99  if (!pydata) {
100  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: __array_interface__['data'] does not exist.");
101  return 0;
102  }
103  return PyLong_AsLong(PyTuple_GetItem(pydata, 0));
104 }
105 
106 ////////////////////////////////////////////////////////////////////////////
107 /// \brief Get type string from Numpy array interface and perform error handling
108 /// \param[in] obj Array interface dictionary
109 /// \return Type string
111 {
112  auto pytypestr = PyDict_GetItemString(obj, "typestr");
113  if (!pytypestr) {
114  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: __array_interface__['typestr'] does not exist.");
115  return "";
116  }
117  std::string typestr = CPyCppyy_PyText_AsString(pytypestr);
118  const auto length = typestr.length();
119  if(length != 3) {
120  PyErr_SetString(PyExc_RuntimeError,
121  ("Object not convertible: __array_interface__['typestr'] returned '" + typestr + "' with invalid length unequal 3.").c_str());
122  return "";
123  }
124  return typestr;
125 }
126 
127 ////////////////////////////////////////////////////////////////////////////
128 /// \brief Get size of data type in bytes from Numpy type string
129 /// \param[in] typestr Numpy type string
130 /// \return Size in bytes
131 unsigned int GetDatatypeSizeFromTypestr(const std::string& typestr)
132 {
133  const auto length = typestr.size();
134  const auto dtypesizestr = typestr.substr(length - 1, length);
135  return std::stoi(dtypesizestr);
136 }
137 
138 ////////////////////////////////////////////////////////////////////////////
139 /// \brief Check whether endianess in type string matches the endianess of ROOT
140 /// \param[in] typestr Numpy type string
141 /// \return Boolean indicating whether they match
142 bool CheckEndianessFromTypestr(const std::string& typestr)
143 {
144  const auto endianess = typestr.substr(1, 2);
145 #ifdef R__BYTESWAP
146  const auto byteswap = "<";
147 #else
148  const auto byteswap = ">";
149 #endif
150  if (!endianess.compare(byteswap)) {
151  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Endianess of __array_interface__['typestr'] does not match endianess of ROOT.");
152  return false;
153  }
154  return true;
155 }
PyObject
_object PyObject
Definition: PyMethodBase.h:42
CallPyObjMethod
PyObject * CallPyObjMethod(PyObject *obj, const char *meth)
Set of helper functions that are invoked from the C++ implementation of pythonizations.
Definition: PyzCppHelpers.cxx:20
GetTypestrFromArrayInterface
std::string GetTypestrFromArrayInterface(PyObject *obj)
Get type string from Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:110
CPyCppyy::CPPInstance
Definition: CPPInstance.h:26
BoolNot
PyObject * BoolNot(PyObject *value)
Definition: PyzCppHelpers.cxx:32
GetCppTypeFromNumpyType
std::string GetCppTypeFromNumpyType(const std::string &dtype)
Convert Numpy data-type string to the according C++ data-type string.
Definition: PyzCppHelpers.cxx:55
Py_RETURN_FALSE
#define Py_RETURN_FALSE
Definition: CPyCppyy.h:289
CheckEndianessFromTypestr
bool CheckEndianessFromTypestr(const std::string &typestr)
Check whether endianess in type string matches the endianess of ROOT.
Definition: PyzCppHelpers.cxx:142
GetDataPointerFromArrayInterface
unsigned long long GetDataPointerFromArrayInterface(PyObject *obj)
Get data pointer from Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:96
GetTClass
TClass * GetTClass(const CPyCppyy::CPPInstance *pyobj)
Definition: PyzCppHelpers.cxx:44
Py_RETURN_TRUE
#define Py_RETURN_TRUE
Definition: CPyCppyy.h:285
GetArrayInterface
PyObject * GetArrayInterface(PyObject *obj)
Get Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:78
TClass::GetClass
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2946
Cppyy::GetScopedFinalName
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
Definition: clingwrapper.cxx:1161
CPyCppyy_PyText_AsString
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
GetDatatypeSizeFromTypestr
unsigned int GetDatatypeSizeFromTypestr(const std::string &typestr)
Get size of data type in bytes from Numpy type string.
Definition: PyzCppHelpers.cxx:131
PyzCppHelpers.hxx
TClass
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:80
CPyCppyy::CPPInstance::ObjectIsA
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
Definition: CPPInstance.h:106