NumPy ints not accepted in TTree::GetEntry() in ROOT 6.32

Dear All,

It seems like ROOT 6.32 introduced a quite substantial, annoying incompatibility. NumPy int32/64 are not any longer treated as ints by PyROOT, at least in the case of TTree::GetEntry(). The following code, where t is any tree:

t.GetEntry(0) # Works

a = np.arange(0,10)
t.GetEntry(a[0]) #Fails

Fails with the following error:

TypeError: int TTree::GetEntry(Long64_t entry, Int_t getall = 0) =>
    TypeError: could not convert argument 1 (int/long conversion expects an integer object)

ROOT Version: 6.32.02
Platform: Fedora 40


Hi,

Thanks for giving a try to 6.32.02 so quickly.

This behaviour should be there also for 6.32.00 and is due to the changes which were put in place to accommodate the new version of the C+±Python compatibility engine of ROOT: cppyy. In this particular case, the fix should be easy, also according to cppy documentation (see e.g. here)

t.GetEntry(int(a[0]))  #Works

Cheers,
Danilo

Hello,

Thanks, I know the fix. However, would it be possible to make the fix inside of ROOT?

This is breaking compatibility with minor version change, and in addition, it removes the compatibility with the major python package in our field. I would bet serious money that PyROOTers more often use numpy.int64 than python’s int.

In addition, a call to a function int() is introduced, which consumes some time…

In addition, the int case is simple. What to do with unsigned int, char and in general all the “complicated” types C supports, while vanilla Python doesn’t?

Trying to keep this topic alive

This is not a regression in ROOT 6.32. I just checked that it also doesn’t work with older versions, like ROOT 6.26.00:

import cppyy
import numpy as np

cppyy.cppdef("""
   int foo(int x) { return x; }
""")

cppyy.gbl.foo(np.int64(10))
Traceback (most recent call last):
  File "repro.py", line 8, in <module>
    cppyy.gbl.foo(np.int64(10))
TypeError: int ::foo(int x) =>
    TypeError: could not convert argument 1 (int/long conversion expects an integer object)

Which previous ROOT version did it work with before?

If you want this feature in cppyy (which PyROOT is based on), you should request it in the cppyy issue tracker:

Just checked with ROOT 6.30/06:

In [1]: import ROOT

In [2]: f = ROOT.TFile("shower_3952437815-3952437815_L0_0000.root")

In [3]: t = f.Get("tshower")

In [4]: t.GetEntries()
Out[4]: 1

In [5]: a = np.arange(0,10, dtype=np.int32)

In [6]: a
Out[6]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int32)

In [7]: t.GetEntry(a[0])
Out[7]: 170

In [8]: ROOT.__version__
Out[8]: '6.30/06'

I’ve tried also on 6.26.10 on a remote machine (mistake inside to make it more believable :wink: ):

In [1]: import ROOT

In [2]: f = ROOT.TFile("shower_14-24971_L0_0000.root")

In [3]: t = f.Get("tshower")

In [4]: t.GetEntries()
Out[4]: 1000

In [5]: a = np.arange(10, dtype=np.int32)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 a = np.arange(10, dtype=np.int32)

NameError: name 'np' is not defined

In [6]: import numpy as np

In [7]: a = np.arange(10, dtype=np.int32)

In [8]: t.GetEntry(a[0])
Out[8]: 171

In [9]: ROOT.__version__
Out[9]: '6.26/10'

I am also almost certain it worked in 6.28 since I was using it until recently, and I would have noticed this problem instantly due to the intensive use of numpy.

Thanks for double checking. I see, so before it used to work if the Numpy type and C++ type was of the same size in bytes (which was not the case in my reproducer).

So indeed this is a regression then, and I have opened an issue about it:

We’ll work on this together with the cppyy developers, so this can be fixed in one of the upcoming ROOT versions.

Hmm, I am not sure how the things are cast, but on 6.30 it works also with np.int64:

In [9]: b = np.arange(0,10, dtype=np.int64)

In [10]: t.GetEntry(b[0])
Out[10]: 170

Ok I see, so the conversion worked if the C++ type has at least the size of the NumPy type.

Here, GetEntry() accepts a Long64_t, so it works with int32 and int64.

1 Like