diff --git a/src/uproot/models/RNTuple.py b/src/uproot/models/RNTuple.py index ef65f2171..f38e00a02 100644 --- a/src/uproot/models/RNTuple.py +++ b/src/uproot/models/RNTuple.py @@ -30,7 +30,7 @@ _rntuple_cluster_summary_format = struct.Struct(" 0: + kindex = numpy.delete(kindex, invalid) + tags = numpy.delete(tags, invalid) + invalid -= numpy.arange(len(invalid)) + optional_index = numpy.insert( + numpy.arange(len(kindex), dtype=numpy.int64), invalid, -1 + ) + else: + optional_index = numpy.arange(len(kindex), dtype=numpy.int64) + container_dict[f"{key}-index"] = optional_index + container_dict[f"{key}-union-index"] = kindex + container_dict[f"{key}-union-tags"] = tags else: # don't distinguish data and offsets container_dict[f"{key}-data"] = content @@ -565,9 +593,9 @@ def arrays( cluster_offset = cluster_starts[start_cluster_idx] entry_start -= cluster_offset entry_stop -= cluster_offset - return ak.from_buffers(form, cluster_num_entries, container_dict)[ - entry_start:entry_stop - ] + return ak.from_buffers( + form, cluster_num_entries, container_dict, allow_noncanonical_form=True + )[entry_start:entry_stop] # Supporting function and classes @@ -592,9 +620,9 @@ def _recursive_find(form, res): class PageDescription: def read(self, chunk, cursor, context): out = MetaData(type(self).__name__) - out.num_elements = cursor.field( - chunk, _rntuple_page_num_elements_format, context - ) + num_elements = cursor.field(chunk, _rntuple_page_num_elements_format, context) + out.has_checksum = num_elements < 0 + out.num_elements = abs(num_elements) out.locator = LocatorReader().read(chunk, cursor, context) return out diff --git a/tests/test_1223_more_rntuple_types.py b/tests/test_1223_more_rntuple_types.py new file mode 100644 index 000000000..686d82afb --- /dev/null +++ b/tests/test_1223_more_rntuple_types.py @@ -0,0 +1,87 @@ +# BSD 3-Clause License; see https://github.com/scikit-hep/uproot5/blob/main/LICENSE + +import pytest +import skhep_testdata + +import uproot + + +def test_atomic(): + filename = skhep_testdata.data_path("test_ntuple_atomic_bitset.root") + with uproot.open(filename) as f: + obj = f["ntuple"] + + a = obj.arrays("atomic_int") + + assert a.atomic_int.tolist() == [1, 2, 3] + + +def test_bitset(): + filename = skhep_testdata.data_path("test_ntuple_atomic_bitset.root") + with uproot.open(filename) as f: + obj = f["ntuple"] + + a = obj.arrays("bitset") + + assert len(a.bitset) == 3 + assert len(a.bitset[0]) == 42 + assert a.bitset[0].tolist()[:6] == [0, 1, 0, 1, 0, 1] + assert all(a.bitset[0][6:] == 0) + assert a.bitset[1].tolist()[:16] == [ + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + ] + assert all(a.bitset[1][16:] == 0) + assert a.bitset[2].tolist()[:16] == [ + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + ] + assert all(a.bitset[2][16:] == 0) + + +def test_empty_struct(): + filename = skhep_testdata.data_path("test_ntuple_emptystruct_invalidvar.root") + with uproot.open(filename) as f: + obj = f["ntuple"] + + a = obj.arrays("empty_struct") + + assert a.empty_struct.tolist() == [{}, {}, {}] + + +def test_invalid_variant(): + filename = skhep_testdata.data_path("test_ntuple_emptystruct_invalidvar.root") + with uproot.open(filename) as f: + obj = f["ntuple"] + + a = obj.arrays("variant") + + assert a.variant.tolist() == [1, 1, None]