f9columnar 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {f9columnar-0.3.0 → f9columnar-0.3.2}/PKG-INFO +1 -1
  2. f9columnar-0.3.2/f9columnar/hdf5_writer.py +326 -0
  3. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/dataloader_helpers.py +6 -1
  4. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/dataset_scaling.py +1 -1
  5. f9columnar-0.3.0/f9columnar/ml/hdf5_writer_processor.py → f9columnar-0.3.2/f9columnar/ml/hdf5_parallel_writer.py +5 -2
  6. f9columnar-0.3.0/f9columnar/ml/hdf5_writer_postprocessor.py → f9columnar-0.3.2/f9columnar/ml/hdf5_writer.py +3 -0
  7. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/root_dataloader.py +45 -10
  8. {f9columnar-0.3.0 → f9columnar-0.3.2}/pyproject.toml +1 -1
  9. {f9columnar-0.3.0 → f9columnar-0.3.2}/LICENSE +0 -0
  10. {f9columnar-0.3.0 → f9columnar-0.3.2}/README.md +0 -0
  11. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/__init__.py +0 -0
  12. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/arrays.py +0 -0
  13. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/PMGxsecDB_mc16.txt +0 -0
  14. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/PMGxsecDB_mc21.txt +0 -0
  15. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/campaigns.json +0 -0
  16. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/luminosity.json +0 -0
  17. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/periods.json +0 -0
  18. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/data/truth_classification.json +0 -0
  19. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/dataset_builder.py +0 -0
  20. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/hdf5_dataloader.py +0 -0
  21. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/histograms.py +0 -0
  22. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/__init__.py +0 -0
  23. /f9columnar-0.3.0/f9columnar/ml/hdf5_ml_dataloader.py → /f9columnar-0.3.2/f9columnar/ml/hdf5_dataloader.py +0 -0
  24. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/imbalanced_sampler.py +0 -0
  25. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/ml/scalers.py +0 -0
  26. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/processors.py +0 -0
  27. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/processors_collection.py +0 -0
  28. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/run.py +0 -0
  29. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/__init__.py +0 -0
  30. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_driver.py +0 -0
  31. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_handler.py +0 -0
  32. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_merger.py +0 -0
  33. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_run.py +0 -0
  34. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/submit/act_run.sh +0 -0
  35. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/__init__.py +0 -0
  36. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/ak_helpers.py +0 -0
  37. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/config_utils.py +0 -0
  38. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/helpers.py +0 -0
  39. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/loggers.py +0 -0
  40. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/regex_helpers.py +0 -0
  41. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/rucio_db.py +0 -0
  42. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/rucio_utils.py +0 -0
  43. {f9columnar-0.3.0 → f9columnar-0.3.2}/f9columnar/utils/xsec_db.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: f9columnar
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: Columnar analysis utils.
5
5
  License: MIT
6
6
  Author: Jan Gavranovic
@@ -0,0 +1,326 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import logging
5
+ from abc import abstractmethod
6
+ from typing import Any
7
+
8
+ import awkward as ak
9
+ import h5py
10
+ import numpy as np
11
+
12
+ from f9columnar.processors import Postprocessor, Processor
13
+
14
+
15
+ class BaseArraysHdf5Writer(Postprocessor):
16
+ def __init__(self, file_path: str, dataset_names: str | list[str] | None = None, name: str = "HDF5Writer") -> None:
17
+ """Class for HDF5 data writer postprocessors that write awkward arrays to HDF5 file.
18
+
19
+ Parameters
20
+ ----------
21
+ file_path : str
22
+ Path to the created HDF5 file.
23
+ dataset_names : str | list[str] | None, optional
24
+ Names of the datasets to be created. Can be dir/subdir/.../dataset_name.
25
+ name : str, optional
26
+ Name of the processor.
27
+
28
+ Other Parameters
29
+ ----------------
30
+ shape, chunks, maxshape, dtype, compression, compression_opts
31
+ See [1].
32
+
33
+ References
34
+ ----------
35
+ [1] - https://docs.h5py.org/en/stable/high/group.html#h5py.Group.create_dataset
36
+ [2] - https://docs.h5py.org/en/stable/high/dataset.html
37
+ [3] - https://pythonforthelab.com/blog/how-to-use-hdf5-files-in-python/
38
+
39
+ """
40
+ super().__init__(name)
41
+ self.file_path = file_path
42
+
43
+ if type(dataset_names) is str:
44
+ self.dataset_names = [dataset_names]
45
+ elif type(dataset_names) is list:
46
+ self.dataset_names = dataset_names
47
+ else:
48
+ self.dataset_names = []
49
+
50
+ self._current_idx = 0
51
+ self._current_shape: int | None = None
52
+
53
+ def create_datasets(
54
+ self,
55
+ mode: str = "w",
56
+ dataset_names: list[str] | None = None,
57
+ shape: tuple[int, int] | tuple[int, int, int] | None = None,
58
+ chunks: bool = False,
59
+ maxshape: tuple[int | None, int] | tuple[int | None, int, int] | None = None,
60
+ dtype: str = "float32",
61
+ compression: str = "lzf",
62
+ compression_opts: int | None = None,
63
+ ) -> None:
64
+ if mode not in ["w", "a"]:
65
+ raise ValueError("Mode must be 'w' or 'a'!")
66
+
67
+ if maxshape is not None and shape is None:
68
+ raise ValueError("Shape must be provided if maxshape is provided!")
69
+
70
+ if maxshape is not None or compression:
71
+ logging.info("Auto-chunking is enabled by default, if you use compression or maxshape.")
72
+ chunks = True
73
+
74
+ if dataset_names is None:
75
+ dataset_names = self.dataset_names
76
+
77
+ if len(dataset_names) == 0:
78
+ raise ValueError("No dataset names provided!")
79
+
80
+ with h5py.File(self.file_path, mode) as f:
81
+ for dataset_name in dataset_names:
82
+ dataset_name_split = dataset_name.split("/")
83
+
84
+ f_obj = f
85
+ for i, group in enumerate(dataset_name_split):
86
+ if i == len(dataset_name_split) - 1:
87
+ f_obj.create_dataset(
88
+ group,
89
+ shape=shape,
90
+ chunks=chunks,
91
+ maxshape=maxshape,
92
+ dtype=dtype,
93
+ compression=compression,
94
+ compression_opts=compression_opts,
95
+ )
96
+ elif i == 0:
97
+ if group not in f_obj:
98
+ g = f.create_group(group)
99
+ f_obj = g
100
+ else:
101
+ f_obj = f_obj[group]
102
+ else:
103
+ g = g.create_group(group)
104
+ f_obj = g
105
+
106
+ def add_data(
107
+ self,
108
+ data: np.ndarray,
109
+ dataset_name: str,
110
+ idx: int | tuple[int, int],
111
+ resize: tuple | None = None,
112
+ ) -> None:
113
+ if type(idx) is tuple and len(idx) > 2:
114
+ raise ValueError("Only support 2D data!")
115
+
116
+ with h5py.File(self.file_path, "a") as f:
117
+ dataset = f[dataset_name]
118
+
119
+ if resize:
120
+ dataset.resize(resize)
121
+
122
+ if type(idx) is int:
123
+ dataset[idx] = data
124
+ elif type(idx) is tuple:
125
+ dataset[idx[0] : idx[1]] = data
126
+ else:
127
+ raise TypeError("idx must be a tuple or an integer!")
128
+
129
+ def add_metadata(self, metadata_dct: dict[str, Any], group_name: str | None = None) -> None:
130
+ with h5py.File(self.file_path, "a") as f:
131
+ if group_name is not None:
132
+ group = f[group_name]
133
+ else:
134
+ group = f
135
+
136
+ group.create_dataset("metadata", data=json.dumps(metadata_dct))
137
+
138
+ def get_metadata(self, group_name: str | None = None) -> dict[str, Any]:
139
+ if group_name is None:
140
+ group_name = "metadata"
141
+ else:
142
+ group_name = f"{group_name}/metadata"
143
+
144
+ with h5py.File(self.file_path, "r") as f:
145
+ metadata = json.loads(f[group_name][()])
146
+
147
+ return metadata
148
+
149
+ def get_keys(self) -> list[str]:
150
+ with h5py.File(self.file_path, "r") as f:
151
+ keys = list(f.keys())
152
+
153
+ return keys
154
+
155
+ def get_handle(self, mode: str = "r") -> h5py.File:
156
+ return h5py.File(self.file_path, mode)
157
+
158
+ def write_arrays(
159
+ self,
160
+ arrays: ak.Array,
161
+ dataset_name: str,
162
+ column_names: list[str],
163
+ chunk_shape: int = 1000,
164
+ ) -> None:
165
+ if self._current_shape is None:
166
+ self._current_shape = chunk_shape
167
+
168
+ save_arrays = []
169
+
170
+ for column_name in column_names:
171
+ if column_name not in arrays.fields:
172
+ raise RuntimeError(f"Column {column_name} not found in arrays!")
173
+
174
+ column = ak.to_numpy(arrays[column_name])
175
+ column = column[:, None]
176
+ save_arrays.append(column)
177
+
178
+ save_arrays = np.concatenate(save_arrays, axis=1)
179
+
180
+ array_chunks = len(save_arrays) // chunk_shape + 1
181
+ chunk_save_arrays = np.array_split(save_arrays, array_chunks)
182
+
183
+ for chunk_array in chunk_save_arrays:
184
+ n_chunk = len(chunk_array)
185
+ start_idx, stop_idx = self._current_idx, self._current_idx + n_chunk
186
+
187
+ self._current_idx = stop_idx
188
+
189
+ if self._current_idx > self._current_shape:
190
+ resize = (stop_idx, chunk_array.shape[1])
191
+ self._current_shape = stop_idx
192
+ else:
193
+ resize = None
194
+
195
+ self.add_data(chunk_array, dataset_name, idx=(start_idx, stop_idx), resize=resize)
196
+
197
+ @abstractmethod
198
+ def run(self, processors: dict[str, Processor], *args: Any, **kwargs: Any):
199
+ pass
200
+
201
+
202
+ class DatasetHdf5Writer(BaseArraysHdf5Writer):
203
+ def __init__(
204
+ self,
205
+ file_path: str,
206
+ dataset_name: str,
207
+ column_names: list[str],
208
+ save_node: str = "output",
209
+ chunk_shape: int = 1000,
210
+ name: str = "datasetHDF5Writer",
211
+ **hdf5_kwargs: Any,
212
+ ) -> None:
213
+ super().__init__(file_path, dataset_names=dataset_name, name=name)
214
+ self.chunk_shape = chunk_shape
215
+ self.column_names = column_names
216
+ self.save_node = save_node
217
+
218
+ self.create_datasets(
219
+ shape=(chunk_shape, len(column_names)),
220
+ maxshape=(None, len(column_names)),
221
+ **hdf5_kwargs,
222
+ )
223
+ self.add_metadata({"columns": self.column_names})
224
+
225
+ def run(self, processors: dict[str, Processor]) -> dict[str, dict[str, Processor]]:
226
+ arrays_processor = processors[self.save_node]
227
+
228
+ if hasattr(arrays_processor, "arrays"):
229
+ arrays = arrays_processor.arrays
230
+ else:
231
+ raise AttributeError("Arrays attribute not found in the processor!")
232
+
233
+ if len(arrays) == 0:
234
+ return {"processors": processors}
235
+
236
+ self.write_arrays(arrays, self.dataset_names[0], self.column_names, self.chunk_shape)
237
+
238
+ return {"processors": processors}
239
+
240
+
241
+ class NtupleHdf5Writer(BaseArraysHdf5Writer):
242
+ def __init__(
243
+ self,
244
+ file_path: str,
245
+ mc_column_names: list[str],
246
+ data_column_names: list[str] | None = None,
247
+ save_node: str = "output",
248
+ chunk_shape: int = 1000,
249
+ write_mc: bool = True,
250
+ write_data: bool = True,
251
+ name: str = "datasetHDF5Writer",
252
+ dataset_names: list[str] | None = None,
253
+ **hdf5_kwargs: Any,
254
+ ) -> None:
255
+ if dataset_names is None:
256
+ dataset_names = ["mc", "data"]
257
+
258
+ if len(dataset_names) != 2:
259
+ raise ValueError("Dataset names must be a list of two strings!")
260
+
261
+ super().__init__(file_path, dataset_names=dataset_names, name=name)
262
+ self.save_node = save_node
263
+ self.chunk_shape = chunk_shape
264
+
265
+ if write_data is False and write_mc is False:
266
+ raise ValueError("Both write_data and write_mc cannot be False!")
267
+
268
+ self.write_data, self.write_mc = write_data, write_mc
269
+
270
+ self.mc_column_names = mc_column_names
271
+
272
+ if data_column_names is None:
273
+ logging.info("Data column names not provided, using MC column names.")
274
+ self.data_column_names = mc_column_names
275
+ else:
276
+ self.data_column_names = data_column_names
277
+
278
+ metadata = {}
279
+ mc_group, data_group = self.dataset_names[0], self.dataset_names[1]
280
+
281
+ if write_mc:
282
+ self.create_datasets(
283
+ dataset_names=[mc_group],
284
+ shape=(self.chunk_shape, len(self.mc_column_names)),
285
+ maxshape=(None, len(self.mc_column_names)),
286
+ **hdf5_kwargs,
287
+ )
288
+ metadata[f"{mc_group}_columns"] = self.mc_column_names
289
+
290
+ if write_data:
291
+ self.create_datasets(
292
+ mode="a" if self.write_mc else "w",
293
+ dataset_names=[data_group],
294
+ shape=(self.chunk_shape, len(self.data_column_names)),
295
+ maxshape=(None, len(self.data_column_names)),
296
+ **hdf5_kwargs,
297
+ )
298
+ metadata[f"{data_group}_columns"] = self.data_column_names
299
+
300
+ self.add_metadata(metadata)
301
+
302
+ self._current_mc_idx, self._current_data_idx = 0, 0
303
+ self._current_mc_shape, self._current_data_shape = None, None
304
+
305
+ def run(self, processors: dict[str, Processor]) -> dict[str, dict[str, Processor]]:
306
+ arrays_processor = processors[self.save_node]
307
+
308
+ if hasattr(arrays_processor, "arrays"):
309
+ arrays = arrays_processor.arrays
310
+ else:
311
+ raise AttributeError("Arrays attribute not found in the processor!")
312
+
313
+ if len(arrays) == 0:
314
+ return {"processors": processors}
315
+
316
+ if self.is_data and self.write_data:
317
+ self._current_idx, self._current_shape = self._current_mc_idx, self._current_mc_shape
318
+ self.write_arrays(arrays, self.dataset_names[1], self.data_column_names, self.chunk_shape)
319
+ self._current_mc_idx, self._current_mc_shape = self._current_idx, self._current_shape
320
+
321
+ if not self.is_data and self.write_mc:
322
+ self._current_idx, self._current_shape = self._current_data_idx, self._current_data_shape
323
+ self.write_arrays(arrays, self.dataset_names[0], self.mc_column_names, self.chunk_shape)
324
+ self._current_data_idx, self._current_data_shape = self._current_idx, self._current_shape
325
+
326
+ return {"processors": processors}
@@ -377,6 +377,11 @@ def get_column_selection(hdf5_files: str | list[str], column_names: list[str]) -
377
377
  selection = ColumnSelection()
378
378
 
379
379
  for dataset_name in used_columns_dct.keys():
380
+ if dataset_name in pad_values:
381
+ pad_value = float(pad_values[dataset_name])
382
+ else:
383
+ pad_value = None
384
+
380
385
  selection[dataset_name] = DatasetColumn(
381
386
  dataset_name,
382
387
  all_columns_dct[dataset_name],
@@ -387,7 +392,7 @@ def get_column_selection(hdf5_files: str | list[str], column_names: list[str]) -
387
392
  numer_columns_idx_dct[dataset_name],
388
393
  categ_columns_idx_dct[dataset_name],
389
394
  shapes_dct[dataset_name],
390
- pad_values,
395
+ pad_value,
391
396
  labels,
392
397
  )
393
398
 
@@ -8,7 +8,7 @@ import numpy as np
8
8
  from torch.utils.data import DataLoader
9
9
 
10
10
  from f9columnar.ml.dataloader_helpers import ColumnSelection, padding_mask
11
- from f9columnar.ml.hdf5_ml_dataloader import WeightedDatasetBatch, get_ml_hdf5_dataloader
11
+ from f9columnar.ml.hdf5_dataloader import WeightedDatasetBatch, get_ml_hdf5_dataloader
12
12
  from f9columnar.ml.scalers import CategoricalFeatureScaler, FeatureScaler, NumericalFeatureScaler
13
13
  from f9columnar.utils.loggers import get_batch_progress
14
14
 
@@ -8,7 +8,7 @@ import awkward as ak
8
8
  import h5py
9
9
  import numpy as np
10
10
 
11
- from f9columnar.ml.hdf5_writer_postprocessor import ArraysHdf5Writer
11
+ from f9columnar.ml.hdf5_writer import ArraysHdf5Writer
12
12
  from f9columnar.processors import Processor
13
13
 
14
14
 
@@ -561,7 +561,10 @@ class Hdf5WriterProcessor(Processor):
561
561
 
562
562
  writer.add_data(chunk_arrays_dct, current_dataset_name, idx=(start_idx, stop_idx), resize=resize)
563
563
 
564
- def run(self, arrays: dict[str, Any]) -> dict[str, Any]:
564
+ def run(self, arrays: ak.Array) -> dict[str, ak.Array]:
565
+ if len(arrays) == 0:
566
+ return {"arrays": arrays}
567
+
565
568
  worker_id = self.reports["worker_id"] # type: ignore[index]
566
569
  self._setup_piles_lst(worker_id)
567
570
 
@@ -668,6 +668,9 @@ class Hdf5WriterPostprocessor(Postprocessor):
668
668
  else:
669
669
  raise AttributeError("Arrays attribute not found in the processor!")
670
670
 
671
+ if len(arrays) == 0:
672
+ return {"processors": processors}
673
+
671
674
  if self.n_piles is not None:
672
675
  n_add_iters = (len(arrays) + self.chunk_shape - 1) // self.chunk_shape
673
676
  pile_idx_lst = [self._get_pile_idx() for _ in range(n_add_iters)]
@@ -4,6 +4,7 @@ import copy
4
4
  import logging
5
5
  import os
6
6
  from collections.abc import Callable, Iterator
7
+ from concurrent.futures import ProcessPoolExecutor
7
8
  from dataclasses import dataclass, field
8
9
  from typing import Any
9
10
 
@@ -17,7 +18,6 @@ from torch.utils.data import DataLoader, IterableDataset
17
18
 
18
19
  from f9columnar.processors import Processor, ProcessorsGraph
19
20
  from f9columnar.utils.helpers import get_file_size
20
- from f9columnar.utils.loggers import get_progress
21
21
 
22
22
 
23
23
  @dataclass
@@ -66,11 +66,7 @@ class RootFiles:
66
66
  total_file_size: float = 0.0
67
67
  total_num_entries: int = 0
68
68
 
69
- def __post_init__(self) -> None:
70
- progress = get_progress()
71
- progress.start()
72
- bar = progress.add_task("Preparing ROOT files", total=len(self.file_names))
73
-
69
+ def load(self) -> RootFiles:
74
70
  for i, file_name in enumerate(self.file_names):
75
71
  if type(self.key) is list:
76
72
  root_file = RootFile(file_name, self.key[i])
@@ -79,8 +75,6 @@ class RootFiles:
79
75
  else:
80
76
  raise ValueError(f"Key {self.key} is not a valid type.")
81
77
 
82
- progress.update(bar, advance=1)
83
-
84
78
  root_file = root_file.open()
85
79
 
86
80
  self.files_dct[file_name] = root_file
@@ -98,7 +92,7 @@ class RootFiles:
98
92
  self.total_file_size += root_file.file_size
99
93
  self.total_num_entries += num_entries
100
94
 
101
- progress.stop()
95
+ return self
102
96
 
103
97
  def __getitem__(self, file_name: str) -> RootFile:
104
98
  return self.files_dct[file_name]
@@ -131,8 +125,49 @@ class UprootIteratorsDfMaker:
131
125
 
132
126
  logging.info(info_str)
133
127
 
128
+ @staticmethod
129
+ def _run_get_root_files(files_lst: list[str], key: str | list[str], it) -> RootFiles:
130
+ return RootFiles(files_lst, key).load()
131
+
132
+ def _join_root_files(self, root_files: list[RootFiles]) -> RootFiles:
133
+ combined_files, combined_file_size_dct, combined_num_entries_dct = {}, {}, {}
134
+
135
+ total_file_size, total_num_entries = 0.0, 0
136
+
137
+ for root_file in root_files:
138
+ combined_files.update(root_file.files_dct)
139
+ combined_file_size_dct.update(root_file.file_size_dct)
140
+ combined_num_entries_dct.update(root_file.num_entries_dct)
141
+
142
+ total_file_size += root_file.total_file_size
143
+ total_num_entries += root_file.total_num_entries
144
+
145
+ return RootFiles(
146
+ list(combined_files.keys()),
147
+ key=self.key,
148
+ files_dct=combined_files,
149
+ file_size_dct=combined_file_size_dct,
150
+ num_entries_dct=combined_num_entries_dct,
151
+ total_file_size=total_file_size,
152
+ total_num_entries=total_num_entries,
153
+ )
154
+
134
155
  def _split(self) -> list[dict[str, list[int]]]:
135
- root_files = RootFiles(self.files, self.key)
156
+ logging.info("Preparing ROOT files (this may take a while).")
157
+
158
+ jobs_idx_split = np.array_split(np.arange(len(self.files)), self.num_workers)
159
+
160
+ with ProcessPoolExecutor(max_workers=self.num_workers) as executor:
161
+ futures = []
162
+ for it, job_idx in enumerate(jobs_idx_split):
163
+ files_lst = [self.files[i] for i in job_idx]
164
+ futures.append(executor.submit(self._run_get_root_files, files_lst, self.key, it))
165
+
166
+ root_files_results = []
167
+ for future in futures:
168
+ root_files_results.append(future.result())
169
+
170
+ root_files = self._join_root_files(root_files_results)
136
171
 
137
172
  self._log_info(root_files.total_file_size, root_files.total_num_entries)
138
173
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "f9columnar"
3
- version = "0.3.0"
3
+ version = "0.3.2"
4
4
  description = "Columnar analysis utils."
5
5
  authors = ["Jan Gavranovic <jan.gavranovic@cern.ch>"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes