diff --git a/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_rvec.py b/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_rvec.py index a875f6904d34d9b3314e7dd4a252a77dc033efaf..612c33370bb0972df8402dc935f8d64af050e7d0 100644 --- a/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_rvec.py +++ b/bindings/pyroot_experimental/PyROOT/python/ROOT/pythonization/_rvec.py @@ -33,7 +33,10 @@ def get_array_interface(self): dtype_size = GetSizeOfType(dtype) endianess = GetEndianess() size = self.size() - pointer = GetVectorDataPointer(self, cppname) + if self.empty(): # Numpy sees a null pointer as error even though the data is never accessed. + pointer = 1 + else: + pointer = GetVectorDataPointer(self, cppname) return { "shape": (size, ), "typestr": "{}{}{}".format(endianess, dtype_numpy, dtype_size), diff --git a/bindings/pyroot_experimental/PyROOT/src/PyzPythonHelpers.cxx b/bindings/pyroot_experimental/PyROOT/src/PyzPythonHelpers.cxx index bd5bbcef65fda4d40c676d732cb205563500c65d..91fa1ad43f120341c855caad394a56eb06eb0806 100644 --- a/bindings/pyroot_experimental/PyROOT/src/PyzPythonHelpers.cxx +++ b/bindings/pyroot_experimental/PyROOT/src/PyzPythonHelpers.cxx @@ -72,14 +72,14 @@ PyObject *PyROOT::GetVectorDataPointer(PyObject * /*self*/, PyObject *args) std::string cppname = CPyCppyy_PyUnicode_AsString(pycppname); // Call interpreter to get pointer to data (using `data` method) - long pointer; + unsigned long long pointer; std::stringstream code; code << "*((long*)" << &pointer << ") = reinterpret_cast<long>(reinterpret_cast<" << cppname << "*>(" << cppobj << ")->data())"; gInterpreter->Calc(code.str().c_str()); // Return pointer as integer - PyObject *pypointer = PyInt_FromLong(pointer); + PyObject *pypointer = PyLong_FromUnsignedLongLong(pointer); return pypointer; } diff --git a/bindings/pyroot_experimental/PyROOT/test/array_interface.py b/bindings/pyroot_experimental/PyROOT/test/array_interface.py index 544682795feb08ac0b5694b79339324db104c9c2..d64ced8fa89ec313b36e14dd6a91af2da47d663e 100644 --- a/bindings/pyroot_experimental/PyROOT/test/array_interface.py +++ b/bindings/pyroot_experimental/PyROOT/test/array_interface.py @@ -4,6 +4,11 @@ import numpy as np class ArrayInterface(unittest.TestCase): + """ + Test memory adoption of std::vector and ROOT::RVec with the numpy + array interface. + """ + # Helpers dtypes = [ "int", "unsigned int", "long", "unsigned long", "float", "double" @@ -32,6 +37,9 @@ class ArrayInterface(unittest.TestCase): # Tests def test_RVec(self): + """ + Test correct adoption of different datatypes for std::vector + """ for dtype in self.dtypes: root_obj = ROOT.ROOT.VecOps.RVec(dtype)(2) np_obj = np.asarray(root_obj) @@ -39,12 +47,33 @@ class ArrayInterface(unittest.TestCase): self.check_shape((2, ), np_obj) def test_STLVector(self): + """ + Test correct adoption of different datatypes for ROOT::RVec + """ for dtype in self.dtypes: root_obj = ROOT.std.vector(dtype)(2) np_obj = np.asarray(root_obj) self.check_memory_adoption(root_obj, np_obj) self.check_shape((2, ), np_obj) + def test_STLVector_empty(self): + """ + Test adoption of empty std::vector + """ + root_obj = ROOT.std.vector("float")() + np_obj = np.asarray(root_obj) + self.assertEqual(np_obj.shape, (0,)) + self.assertEqual(np_obj.__array_interface__["data"][0], 1) + + def test_RVec_empty(self): + """ + Test adoption of empty ROOT::RVec + """ + root_obj = ROOT.ROOT.VecOps.RVec("float")() + np_obj = np.asarray(root_obj) + self.assertEqual(np_obj.shape, (0,)) + self.assertEqual(np_obj.__array_interface__["data"][0], 1) + if __name__ == '__main__': unittest.main()