From f1e51c68fc81b469b62d9e0ce71b3be334a58a5c Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Thu, 29 May 2025 18:20:46 +0200 Subject: [PATCH 01/11] feature to get necessary branches --- servicex_analysis_utils/read-buffers.py | 107 ++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 servicex_analysis_utils/read-buffers.py diff --git a/servicex_analysis_utils/read-buffers.py b/servicex_analysis_utils/read-buffers.py new file mode 100644 index 0000000..82c3add --- /dev/null +++ b/servicex_analysis_utils/read-buffers.py @@ -0,0 +1,107 @@ +# Copyright (c) 2025, IRIS-HEP +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import awkward as ak +from awkward.forms import RecordForm, NumpyForm, ListOffsetForm + + +def add_keys(original_form): + """ + Add a form_key to the parent Record and to every child ListOffset/content associated to a field. + + Parameters: + original_form (ak.forms.Form): Form of the awkward array the typetracer will be built upon. + This should be a RecordForm, which contains fields and contents. + + Returns: + RecordForm: + """ + + # RecordForm: zip contents + field names, recurse on each child, + # then rebuild with each child's form_key set to its field name + if isinstance(original_form, RecordForm): + new_contents = [] + for child, name in zip(original_form.contents, original_form.fields): + child = child.copy(form_key=name) + new_contents.append(child) + return RecordForm( + new_contents, + original_form.fields, + form_key="RecordForm_key", # Give name to parent RecordForm + parameters=original_form.parameters, + ) + + else: + raise ValueError( + f"Unsupported form type: {type(original_form)}. " + "This function only supports RecordForm." + ) + + +def is_branch_buffer(form_key, attribute, form): + # rename any node that has no form_key + if form_key is None: + return "Not-a-branch" + return f"{form_key}" + + +def build_typetracer(form): + """ + Build a typetracer from an awkward form, adding keys to the RecordForm and ListOffsetForm. + + Parameters: + form (ak.forms.Form): Form of the awkward array the typetracer will be built upon. + + Returns: + tracer, report: ak.typetracer.TypeTracer: the typetracer built from the array form. + """ + stamped_form = add_keys(form) + + tracer, report = ak.typetracer.TypeTracer( + stamped_form, + buffer_key=is_branch_buffer, + highlevel=True, + behavior=None, + attrs=None, + ) + return tracer, report + + +def necessary_branches(report): + """ + Utility function to get the necessary branches from a typetracer report. + + Parameters: + report (ak.typetracer.Report): Report from the typetracer. + + Returns: + list: List of necessary branches. + """ + return [ + br for br in report.data_touched if br != "Not-a-branch" + ] # filter out "Not-a-branch" From 99f75c8f5d7667994b7f257786ffc2e0fcef3174 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Thu, 29 May 2025 18:49:38 +0200 Subject: [PATCH 02/11] Correcting - symbol, adding function import to init --- servicex_analysis_utils/__init__.py | 3 ++- servicex_analysis_utils/{read-buffers.py => read_buffers.py} | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename servicex_analysis_utils/{read-buffers.py => read_buffers.py} (98%) diff --git a/servicex_analysis_utils/__init__.py b/servicex_analysis_utils/__init__.py index 8eae057..29f1abe 100644 --- a/servicex_analysis_utils/__init__.py +++ b/servicex_analysis_utils/__init__.py @@ -27,6 +27,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from .materialization import to_awk from .file_peeking import get_structure +from .read_buffers import necessary_branches __version__ = "1.0.2" -__all__ = ["to_awk", "get_structure"] +__all__ = ["to_awk", "get_structure", "necessary_branches"] diff --git a/servicex_analysis_utils/read-buffers.py b/servicex_analysis_utils/read_buffers.py similarity index 98% rename from servicex_analysis_utils/read-buffers.py rename to servicex_analysis_utils/read_buffers.py index 82c3add..d85c05c 100644 --- a/servicex_analysis_utils/read-buffers.py +++ b/servicex_analysis_utils/read_buffers.py @@ -82,7 +82,7 @@ def build_typetracer(form): """ stamped_form = add_keys(form) - tracer, report = ak.typetracer.TypeTracer( + tracer, report = ak.typetracer.typetracer_with_report( stamped_form, buffer_key=is_branch_buffer, highlevel=True, From 4d63dc365e99af441cb4cc36055da68736d6c180 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Thu, 29 May 2025 18:50:01 +0200 Subject: [PATCH 03/11] Build test for type tracer build and needed branches --- tests/test_typetracer.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/test_typetracer.py diff --git a/tests/test_typetracer.py b/tests/test_typetracer.py new file mode 100644 index 0000000..65eb97b --- /dev/null +++ b/tests/test_typetracer.py @@ -0,0 +1,18 @@ +import awkward as ak +import pytest + +from servicex_analysis_utils import read_buffers + + +def test_simple_record_typetracer(): + arr = ak.Array([{"x": [1, 2, 3], "y": [4, 5]}]) + + form = arr.layout.form + tracer, report = read_buffers.build_typetracer(form) + + # “Touch” one of the two fields + _ = tracer["x"] + 0 + + # Collect the branches and assert exactly one branch is needed (x) + touched_branches = read_buffers.necessary_branches(report) + assert set(touched_branches) == {"x"} From a4b038efcea01dad5b571ed2c7acbd3f321b2938 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Fri, 30 May 2025 14:38:54 +0200 Subject: [PATCH 04/11] Adding utility imports to init --- servicex_analysis_utils/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/servicex_analysis_utils/__init__.py b/servicex_analysis_utils/__init__.py index 29f1abe..04b2bd1 100644 --- a/servicex_analysis_utils/__init__.py +++ b/servicex_analysis_utils/__init__.py @@ -27,7 +27,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from .materialization import to_awk from .file_peeking import get_structure -from .read_buffers import necessary_branches +from .read_buffers import get_necessary_branches __version__ = "1.0.2" -__all__ = ["to_awk", "get_structure", "necessary_branches"] +__all__ = ["to_awk", "get_structure", "get_necessary_branches"] From 60596c0ac2e405fc992d6b3502e720b4def95acc Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Fri, 30 May 2025 14:39:52 +0200 Subject: [PATCH 05/11] renaming function --- servicex_analysis_utils/read_buffers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/servicex_analysis_utils/read_buffers.py b/servicex_analysis_utils/read_buffers.py index d85c05c..0f89951 100644 --- a/servicex_analysis_utils/read_buffers.py +++ b/servicex_analysis_utils/read_buffers.py @@ -27,7 +27,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import awkward as ak -from awkward.forms import RecordForm, NumpyForm, ListOffsetForm +from awkward.forms import RecordForm def add_keys(original_form): @@ -70,7 +70,7 @@ def is_branch_buffer(form_key, attribute, form): return f"{form_key}" -def build_typetracer(form): +def build_typetracer_with_report(form): """ Build a typetracer from an awkward form, adding keys to the RecordForm and ListOffsetForm. @@ -92,7 +92,7 @@ def build_typetracer(form): return tracer, report -def necessary_branches(report): +def get_necessary_branches(report): """ Utility function to get the necessary branches from a typetracer report. From 4429239a3171dd77ef6db2c6a1b615cc6c4fab79 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Fri, 30 May 2025 17:25:20 +0200 Subject: [PATCH 06/11] Adding CI tests to typetracer builder, get_necessary_branches. Test on root file --- tests/test_typetracer.py | 140 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 6 deletions(-) diff --git a/tests/test_typetracer.py b/tests/test_typetracer.py index 65eb97b..b57a988 100644 --- a/tests/test_typetracer.py +++ b/tests/test_typetracer.py @@ -1,18 +1,146 @@ import awkward as ak +from awkward.forms import ListOffsetForm, NumpyForm import pytest - from servicex_analysis_utils import read_buffers +from skhep_testdata import data_path +import uproot -def test_simple_record_typetracer(): +@pytest.fixture +def setup_form(): + # Create a simple awkward array with a RecordForm arr = ak.Array([{"x": [1, 2, 3], "y": [4, 5]}]) - form = arr.layout.form - tracer, report = read_buffers.build_typetracer(form) + + # Build a form from a .root file + file = data_path("uproot-Zmumu.root") + ":events" + array = uproot.open(file).arrays(library="ak") + return form, array.layout.form + + +@pytest.fixture +def setup_type_tracer(setup_form, from_uproot): + array_form, uproot_form = setup_form + if from_uproot: + form = uproot_form + else: + form = array_form + # Build a typetracer with the form + tracer, report = read_buffers.build_typetracer_with_report(form) + return tracer, report + + +def test_instance_of_record_form(setup_form): + simple_form, root_form = setup_form + # Check instances of RecordForm + assert isinstance( + simple_form, ak.forms.RecordForm + ), f"Form is {type(simple_form)}, but should be RecordForm" + + assert isinstance( + root_form, ak.forms.RecordForm + ), f"Form is {type(root_form)}, but should be RecordForm" + + +@pytest.mark.parametrize("from_uproot", [True, False]) +def test_built_typetracer_instance(setup_type_tracer): + tracer, report = setup_type_tracer + # Check if the tracer is an instance of high-level Array + assert isinstance( + tracer, ak.highlevel.Array + ), f"Tracer should be a highlevel Array but is {type(tracer)}" + + # Check if the report is an instance of Report + assert isinstance(report, ak.typetracer.TypeTracerReport), "Report is not a Report" + # Check if the report has data_touched + assert hasattr( + report, "data_touched" + ), "Report does not have data_touched attribute" + + +@pytest.mark.parametrize("from_uproot", [False]) +def test_simple_record_typetracer(setup_type_tracer): + tracer, report = setup_type_tracer + + assert tracer.fields == ["x", "y"], "Fields of the tracer do not match expected" # “Touch” one of the two fields _ = tracer["x"] + 0 - # Collect the branches and assert exactly one branch is needed (x) - touched_branches = read_buffers.necessary_branches(report) + # Collect the touched branches + touched_branches = read_buffers.get_necessary_branches(report) assert set(touched_branches) == {"x"} + + +@pytest.mark.parametrize("from_uproot", [True]) +def test_root_record_typetracer(setup_type_tracer): + tracer, report = setup_type_tracer + expected_fields = [ + "Type", + "Run", + "Event", + "E1", + "px1", + "py1", + "pz1", + "pt1", + "eta1", + "phi1", + "Q1", + "E2", + "px2", + "py2", + "pz2", + "pt2", + "eta2", + "phi2", + "Q2", + "M", + ] + + assert ( + tracer.fields == expected_fields + ), "Fields of the tracer do not match expected" + + # Compute deltaR on typetracer + delta_r = ( + (tracer["eta1"] - tracer["eta2"]) ** 2 + (tracer["phi1"] - tracer["phi2"]) ** 2 + ) ** 0.5 + + # Check delta_r is still an array + assert isinstance( + delta_r, ak.highlevel.Array + ), f"delta_r should be a highlevel Array but is {type(delta_r)}" + + # Check no data is loaded in computation + # only TypeTracer placeholders should be present + first_element = delta_r[0] + assert "TypeTracer" in repr( + first_element + ), f"Expected a TypeTracer placeholder, got {repr(first_element)} instead." + + # Collect the touched branches + touched_branches = read_buffers.get_necessary_branches(report) + assert set(touched_branches) == { + "eta1", + "phi1", + "eta2", + "phi2", + }, "Touched branches do not match expected branches" + + +def test_error_on_wrong_form(): + # Test that ValueError is raised when an empty form is passed + with pytest.raises( + ValueError, + match="Unsupported form type: . This function only supports RecordForm.", + ): + read_buffers.add_keys(None) + + # Test that ValueError is raised when another form type is passed + dummy = ListOffsetForm("i64", NumpyForm("int32")) + with pytest.raises( + ValueError, + match="Unsupported form type: . This function only supports RecordForm.", + ): + read_buffers.add_keys(dummy) From 49dbf271b18a081177a45f9adfadbb00a07b7b67 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Thu, 5 Jun 2025 15:57:03 +0200 Subject: [PATCH 07/11] Adding Ak.Form type return --- servicex_analysis_utils/file_peeking.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/servicex_analysis_utils/file_peeking.py b/servicex_analysis_utils/file_peeking.py index 88a056e..5eff7e3 100644 --- a/servicex_analysis_utils/file_peeking.py +++ b/servicex_analysis_utils/file_peeking.py @@ -212,7 +212,7 @@ def parse_jagged_depth_and_dtype(dtype_str): return depth, None -def str_to_array(encoded_json_str): +def str_to_array(encoded_json_str, return_form=False): """ Helper to reconstruct ak.Arrays from a JSON-formatted file-structure string. Returns an array mimicking TTrees and TBranches with correct field names and dtypes. @@ -251,7 +251,10 @@ def str_to_array(encoded_json_str): if branches: reconstructed_data[treename] = ak.Array([branches]) - return ak.Array(reconstructed_data).type + if return_form: + return ak.Array(reconstructed_data).layout.form + else: + return ak.Array(reconstructed_data).type def get_structure(datasets, array_out=False, **kwargs): @@ -274,7 +277,7 @@ def get_structure(datasets, array_out=False, **kwargs): for sample, path in output.items(): with uproot.open(path[0]) as f: structure_str = f["servicex"]["branch"].array()[0] - sample_array = str_to_array(structure_str) + sample_array = str_to_array(structure_str, **kwargs) all_arrays[sample] = sample_array return all_arrays From 6af81b73d036ee01db2ccf777084a98ada16b99a Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Fri, 6 Jun 2025 10:18:30 +0200 Subject: [PATCH 08/11] return form per tree + variable renaming --- servicex_analysis_utils/file_peeking.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/servicex_analysis_utils/file_peeking.py b/servicex_analysis_utils/file_peeking.py index 5eff7e3..da668cf 100644 --- a/servicex_analysis_utils/file_peeking.py +++ b/servicex_analysis_utils/file_peeking.py @@ -212,7 +212,7 @@ def parse_jagged_depth_and_dtype(dtype_str): return depth, None -def str_to_array(encoded_json_str, return_form=False): +def str_to_array(encoded_json_str, tree_forms=False): """ Helper to reconstruct ak.Arrays from a JSON-formatted file-structure string. Returns an array mimicking TTrees and TBranches with correct field names and dtypes. @@ -223,7 +223,7 @@ def str_to_array(encoded_json_str, return_form=False): Returns: ak.Array: An array containing a dictionary of trees with branch structures and dummy typed values. """ - reconstructed_data = {} + reconstructed_file_data = {} structure_dict = json.loads(encoded_json_str) for treename, branch_dict in structure_dict.items(): @@ -249,12 +249,17 @@ def str_to_array(encoded_json_str, return_form=False): branches[branch_name] = ak.Array([dummy]) if branches: - reconstructed_data[treename] = ak.Array([branches]) + reconstructed_file_data[treename] = ak.Array([branches]) - if return_form: - return ak.Array(reconstructed_data).layout.form + if tree_forms: + # Dictionary of each tree's RecordForm + tree_forms = { + tree: arr.layout.form for tree, arr in reconstructed_file_data.items() + } + return tree_forms else: - return ak.Array(reconstructed_data).type + # ak.Array type with all trees and branches + return ak.Array(reconstructed_file_data).type def get_structure(datasets, array_out=False, **kwargs): @@ -273,13 +278,13 @@ def get_structure(datasets, array_out=False, **kwargs): output = deliver(spec_python) if array_out == True: - all_arrays = {} + all_requests = {} for sample, path in output.items(): with uproot.open(path[0]) as f: structure_str = f["servicex"]["branch"].array()[0] - sample_array = str_to_array(structure_str, **kwargs) - all_arrays[sample] = sample_array - return all_arrays + ak_structure = str_to_array(structure_str, **kwargs) + all_requests[sample] = ak_structure + return all_requests else: return print_structure_from_str(output, **kwargs) From 3828a9df95a99cd2affa0757b2ec810ac353025f Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Mon, 2 Jun 2025 16:27:28 +0200 Subject: [PATCH 09/11] adding helper for json loading --- servicex_analysis_utils/file_peeking.py | 35 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/servicex_analysis_utils/file_peeking.py b/servicex_analysis_utils/file_peeking.py index da668cf..4b3c6e8 100644 --- a/servicex_analysis_utils/file_peeking.py +++ b/servicex_analysis_utils/file_peeking.py @@ -31,6 +31,7 @@ import numpy as np import awkward as ak import json +import logging def run_query(input_filenames): @@ -123,6 +124,30 @@ def build_deliver_spec(datasets): return spec_python +def open_delivered_file(sample, path): + """ + Opens the first file delivered by ServiceX for a given sample and returns the + structure encoded in the "servicex/branch" branch. + If no files are found, logs a warning and returns None. + Parameters: + sample (str): The sample name for which to open the file. + path (list): List of file paths delivered by ServiceX for the sample. + """ + + if not path: + logging.warning( + f"Warning: No files found for sample '{sample}' in delivered results. Skipping." + ) + return None + + try: + with uproot.open(path[0]) as f: + return f["servicex"]["branch"].array()[0] + except Exception as e: + logging.error(f"Error opening file for sample '{sample}': {e}") + return None + + def print_structure_from_str( deliver_dict, filter_branch="", save_to_txt=False, do_print=False ): @@ -147,16 +172,18 @@ def print_structure_from_str( ) for sample_name, path in deliver_dict.items(): + structure_str = open_delivered_file(sample_name, path) + if structure_str is None: + continue + # Parse the JSON string into a dictionary + structure_dict = json.loads(structure_str) + output_lines.append( f"\n---------------------------\n" f"\U0001f4c1 Sample: {sample_name}\n" f"---------------------------" ) - with uproot.open(path[0]) as f: - json_str = f["servicex"]["branch"].array()[0] - structure_dict = json.loads(json_str) - for tree_name, branches in structure_dict.items(): output_lines.append(f"\n\U0001f333 Tree: {tree_name}") output_lines.append(" ├── Branches:") From 2a1c214cb0e28138441e5ca45c89e0bd25374675 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Mon, 25 Aug 2025 14:40:56 +0200 Subject: [PATCH 10/11] Adding skhep_testdata in test requirments --- pyproject.toml | 3 ++- tests/test_typetracer.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 25785f5..adf3e63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,8 @@ test = [ "numpy>=1.21", "pyarrow>=8.0.0", "pandas", - "miniopy-async==1.21.1" + "miniopy-async==1.21.1", + "scikit-hep-testdata", ] docs = [ diff --git a/tests/test_typetracer.py b/tests/test_typetracer.py index b57a988..ab4b5be 100644 --- a/tests/test_typetracer.py +++ b/tests/test_typetracer.py @@ -14,8 +14,8 @@ def setup_form(): # Build a form from a .root file file = data_path("uproot-Zmumu.root") + ":events" - array = uproot.open(file).arrays(library="ak") - return form, array.layout.form + uproot_array = uproot.open(file).arrays(library="ak") + return form, uproot_array.layout.form @pytest.fixture From 89666f8df06f70d8e092768e124c2999dd787631 Mon Sep 17 00:00:00 2001 From: Artur Cordeiro Oudot Choi Date: Mon, 25 Aug 2025 15:00:47 +0200 Subject: [PATCH 11/11] Build typetracer directly on array - skipping form --- servicex_analysis_utils/read_buffers.py | 8 +++++--- tests/test_typetracer.py | 17 ++--------------- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/servicex_analysis_utils/read_buffers.py b/servicex_analysis_utils/read_buffers.py index 0f89951..da3a368 100644 --- a/servicex_analysis_utils/read_buffers.py +++ b/servicex_analysis_utils/read_buffers.py @@ -70,16 +70,18 @@ def is_branch_buffer(form_key, attribute, form): return f"{form_key}" -def build_typetracer_with_report(form): +def build_typetracer_with_report(array): """ Build a typetracer from an awkward form, adding keys to the RecordForm and ListOffsetForm. Parameters: - form (ak.forms.Form): Form of the awkward array the typetracer will be built upon. + form (ak.HighLevel.Array): The awkward array the typetracer will be built upon. Returns: - tracer, report: ak.typetracer.TypeTracer: the typetracer built from the array form. + tracer, report: ak.typetracer.TypeTracer: the typetracer built from the array form and the report. """ + # Get the form from the array + form = array.layout.form stamped_form = add_keys(form) tracer, report = ak.typetracer.typetracer_with_report( diff --git a/tests/test_typetracer.py b/tests/test_typetracer.py index ab4b5be..a13d01c 100644 --- a/tests/test_typetracer.py +++ b/tests/test_typetracer.py @@ -9,13 +9,12 @@ @pytest.fixture def setup_form(): # Create a simple awkward array with a RecordForm - arr = ak.Array([{"x": [1, 2, 3], "y": [4, 5]}]) - form = arr.layout.form + simple_array = ak.Array([{"x": [1, 2, 3], "y": [4, 5]}]) # Build a form from a .root file file = data_path("uproot-Zmumu.root") + ":events" uproot_array = uproot.open(file).arrays(library="ak") - return form, uproot_array.layout.form + return simple_array, uproot_array @pytest.fixture @@ -30,18 +29,6 @@ def setup_type_tracer(setup_form, from_uproot): return tracer, report -def test_instance_of_record_form(setup_form): - simple_form, root_form = setup_form - # Check instances of RecordForm - assert isinstance( - simple_form, ak.forms.RecordForm - ), f"Form is {type(simple_form)}, but should be RecordForm" - - assert isinstance( - root_form, ak.forms.RecordForm - ), f"Form is {type(root_form)}, but should be RecordForm" - - @pytest.mark.parametrize("from_uproot", [True, False]) def test_built_typetracer_instance(setup_type_tracer): tracer, report = setup_type_tracer