Skip to content

Commit df83802

Browse files
authored
RNTuple support (#586)
* RNTuple support * Update tests and documentation
1 parent 8f9e76b commit df83802

File tree

5 files changed

+44
-3
lines changed

5 files changed

+44
-3
lines changed

docs/transform_request.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The General Section
3232
^^^^^^^^^^^^^^^^^^^
3333
The General section of the request includes the following fields:
3434

35-
* (Optional) ``OutputFormat``: Can be ``root-ttree`` (default) or ``parquet`` (you can also use the enums ``servicex.OutputFormat.root_ttree`` and ``servicex.OutputFormat.parquet``)
35+
* (Optional) ``OutputFormat``: Can be ``root-ttree`` (default), ``root-rntuple``, or ``parquet`` (you can also use the enums ``servicex.OutputFormat.root_ttree``, ``servicex.OutputFormat.root_rntuple``, and ``servicex.OutputFormat.parquet``)
3636
* (Optional) ``Delivery``: Can be ``LocalCache`` (default) to download the results to the system on which you are running the client, or ``URLs`` to provide HTTPS URLs to the output on the ServiceX storage (you can also use the enums ``servicex.Delivery.LocalCache`` and ``servicex.Delivery.URLs``). The output files on the ServiceX storage will periodically get cleaned, so if you need to keep the results for long term use it is recommended that you download the output to local cache, but for transient use the URLs will be faster.
3737

3838
In general, if you are running on your laptop away from the ServiceX site and are working with a small amount of

docs/transformer_matrix.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ In brief, here are the currently supported combinations:
3333

3434
### Uproot-Raw
3535

36-
The Uproot-Raw query language can be thought of as essentially calling the [`TTree.arrays()`](https://uproot.readthedocs.io/en/latest/uproot.behaviors.TTree.TTree.html#arrays) function of `uproot` with the possibility to specify several of the arguments, and returning the result. Multiple queries can be bundled into one request. It is also possible to copy objects from the input file.
36+
The Uproot-Raw query language can be thought of as essentially calling the [`TTree.arrays()`](https://uproot.readthedocs.io/en/latest/uproot.behaviors.TTree.TTree.html#arrays) function of `uproot` with the possibility to specify several of the arguments, and returning the result. (Tree here should be understood to also include `RNtuple` objects; nothing needs to be changed to read those.) Multiple queries can be bundled into one request. It is also possible to copy objects from the input file.
3737

3838
Let's look at the structure of an Uproot-Raw query.
3939

@@ -56,7 +56,7 @@ Each dictionary either has a `treename` key (indicating that it is a query on a
5656

5757
* **Query dictionaries**: these dictionaries contain a `treename` key, which specifies the tree(s) to be queried. The keys are:
5858
* `treename`: either a string, a list of strings, or a dictionary. This selects the names of the tree(s) to which the query will be applied. In the case that a dictionary is passed, the keys will be used to choose the input trees, and the values will be used as the name of the tree that results from the query - this allows the user to run multiple queries on the same tree, saving the output to a different tree each time.
59-
* `expressions`, `cut`, `filter_name`, `aliases`: have the same meaning as for [`TTree.arrays()`](https://uproot.readthedocs.io/en/latest/uproot.behaviors.TTree.TTree.html#arrays) in `uproot`, except that functions aren't permitted (but *glob*s and _regular expressions_, which are special kinds of strings, are).
59+
* `expressions`, `cut`, `filter_name`, `aliases`: have the same meaning as for [`TTree.arrays()`](https://uproot.readthedocs.io/en/latest/uproot.behaviors.TTree.TTree.html#arrays)/[`RNTuple.arrays()`](https://uproot.readthedocs.io/en/stable/uproot.models.RNTuple.Model_ROOT_3a3a_RNTuple.html#arrays) in `uproot`, except that functions aren't permitted (but *glob*s and _regular expressions_, which are special kinds of strings, are).
6060

6161
Other keys will be ignored.
6262

servicex/databinder_models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,11 @@ class OutputFormatEnum(str, Enum):
198198
a ROOT TTree https://root.cern.ch/doc/master/classTTree.html
199199
"""
200200

201+
root_rntuple = "root-rntuple"
202+
"""
203+
Save the output as an RNtuple https://root.cern/doc/master/classROOT_1_1RNTuple.html
204+
"""
205+
201206
def to_ResultFormat(self) -> ResultFormat:
202207
"""This method is used to convert the OutputFormatEnum enum to the ResultFormat enum,
203208
which is what is actually used for the TransformRequest. This allows us to use
@@ -207,6 +212,8 @@ def to_ResultFormat(self) -> ResultFormat:
207212
return ResultFormat.parquet
208213
elif self == self.root_ttree:
209214
return ResultFormat.root_ttree
215+
elif self == self.root_rntuple:
216+
return ResultFormat.root_rntuple
210217
else: # pragma: no cover
211218
raise RuntimeError(f"Bad OutputFormatEnum {self}")
212219

servicex/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class ResultFormat(str, Enum):
7979

8080
parquet = "parquet"
8181
root_ttree = "root-file"
82+
root_rntuple = "root-rntuple"
8283

8384

8485
class Status(str, Enum):

tests/test_databinder.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ def test_output_format():
9797
spec = basic_spec()
9898
spec["General"] = {"OutputFormat": "root-ttree"}
9999
ServiceXSpec.model_validate(spec)
100+
spec["General"] = {"OutputFormat": "root-rntuple"}
101+
ServiceXSpec.model_validate(spec)
100102
spec["General"] = {"OutputFormat": "parquet"}
101103
ServiceXSpec.model_validate(spec)
102104
spec["General"] = {"OutputFormat": OutputFormat.root_ttree}
103105
ServiceXSpec.model_validate(spec)
106+
spec["General"] = {"OutputFormat": OutputFormat.root_rntuple}
107+
ServiceXSpec.model_validate(spec)
104108
spec["General"] = {"OutputFormat": OutputFormat.parquet}
105109
ServiceXSpec.model_validate(spec)
106110
with pytest.raises(ValidationError):
@@ -846,6 +850,35 @@ def test_uproot_raw_query_parquet(transformed_result, codegen_list, with_event_l
846850
deliver(spec, config_path="tests/example_config.yaml")
847851

848852

853+
def test_uproot_raw_query_rntuple(transformed_result, codegen_list, with_event_loop):
854+
from servicex import deliver
855+
from servicex.query import UprootRaw # type: ignore
856+
857+
spec = ServiceXSpec.model_validate(
858+
{
859+
"General": {"OutputFormat": "root-rntuple"},
860+
"Sample": [
861+
{
862+
"Name": "sampleA",
863+
"RucioDID": "user.ivukotic:user.ivukotic.single_top_tW__nominal",
864+
"Query": UprootRaw([{"treename": "nominal"}]),
865+
}
866+
],
867+
}
868+
)
869+
with (
870+
patch(
871+
"servicex.dataset_group.DatasetGroup.as_files",
872+
return_value=[transformed_result],
873+
),
874+
patch(
875+
"servicex.servicex_client.ServiceXClient.get_code_generators",
876+
return_value=codegen_list,
877+
),
878+
):
879+
deliver(spec, config_path="tests/example_config.yaml")
880+
881+
849882
def test_generic_query(codegen_list):
850883
from servicex.servicex_client import ServiceXClient
851884

0 commit comments

Comments
 (0)