Skip to content

fix: Pandas global indices for how=dict and RNTuple entry ranges - #1696

Draft
ariostas wants to merge 1 commit into
scikit-hep:mainfrom
ariostas:fix-pandas-global-index
Draft

ariostas wants to merge 1 commit into
scikit-hep:mainfrom
ariostas:fix-pandas-global-index

Conversation

@ariostas

@ariostas ariostas commented Aug 5, 2026

Copy link
Copy Markdown
Member

🤖 AI text below 🤖

Addresses the two Pandas findings from #1688 (grouped as "PR 6" there).

how=dict fails in the multi-file APIs

Pandas.global_index re-indexes each file's output so that entry numbers are global rather than restarting at 0 per file. It recursed through tuple and list, but not dict, so both of these raised AttributeError: 'dict' object has no attribute 'index' — even with a single file:

uproot.concatenate({path: "t"}, ["x"], library="pd", how=dict)
uproot.iterate({path: "t"}, ["x"], library="pd", how=dict)

TTree.arrays(how=dict) and TTree.iterate(how=dict) were unaffected, because they never call global_index.

RNTuple Pandas indices were cluster-relative

RNTuple.arrays subtracts the first read cluster's offset from entry_start so it can slice into the concatenated cluster buffers, then reused that cluster-relative value to build the RangeIndex. Reading entries [4:6] of an RNTuple whose clusters break at entry 4 returned the right values indexed [0, 1]; the equivalent TTree returns [4, 5].

Kept as global_entry_start before the subtraction and used for the index only.

Tests

tests/test_1688_pandas_global_index.py: how=dict for one and two files through both concatenate and iterate, how=tuple/how=list as controls, and RNTuple entry ranges inside, spanning, and beyond the first cluster, plus a direct comparison against the TTree index. 7 of the 12 fail on main.

Full suite passes locally (1028 passed, 90 skipped).

uproot.concatenate and uproot.iterate re-index each file's Pandas output so
that entry numbers are global rather than per-file, but Pandas.global_index
only recursed through tuples and lists. With library="pd" and how=dict both
raised AttributeError: 'dict' object has no attribute 'index', even for a
single file.

RNTuple.arrays subtracts the first read cluster's offset from entry_start to
index into the concatenated cluster buffers, then reused that cluster-relative
value to build the Pandas RangeIndex. Reading entries [4:6] of an RNTuple whose
clusters break at entry 4 returned the right values indexed [0, 1] instead of
[4, 5], which is what the equivalent TTree returns.

Assisted-by: claude-code:claude-opus-5[1m]
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.00%. Comparing base (e598b61) to head (0d02368).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
Files with missing lines Coverage Δ
src/uproot/behaviors/RNTuple.py 74.82% <100.00%> (+0.04%) ⬆️
src/uproot/interpretation/library.py 69.21% <100.00%> (+4.82%) ⬆️

... and 1 file with indirect coverage changes

@TaiSakuma TaiSakuma added the type/fix PR title type: fix (set automatically) label Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/fix PR title type: fix (set automatically)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants