legend-pydataobj 1.13.0__tar.gz → 1.14.1__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.
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/PKG-INFO +1 -1
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/PKG-INFO +1 -1
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/SOURCES.txt +1 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/_version.py +2 -2
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/radware.py +3 -3
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/varlen.py +2 -2
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/ndarray.py +5 -5
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/array.py +1 -1
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/composite.py +162 -149
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/core.py +33 -24
- legend_pydataobj-1.14.1/src/lgdo/lh5/exceptions.py +55 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/iterator.py +18 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/store.py +14 -8
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/tools.py +7 -6
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/utils.py +17 -9
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/array.py +5 -2
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/encoded.py +6 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/scalar.py +3 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/table.py +8 -4
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/vectorofvectors.py +3 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/test_radware_sigcompress.py +3 -3
- legend_pydataobj-1.14.1/tests/lh5/test_exceptions.py +260 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_iterator.py +20 -2
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_write.py +1 -122
- legend_pydataobj-1.14.1/tests/lh5/test_pathlib.py +40 -0
- legend_pydataobj-1.13.0/src/lgdo/lh5/exceptions.py +0 -40
- legend_pydataobj-1.13.0/tests/lh5/test_exceptions.py +0 -17
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/LICENSE +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/README.md +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/pyproject.toml +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/setup.cfg +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/dependency_links.txt +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/entry_points.txt +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/not-zip-safe +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/requires.txt +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/legend_pydataobj.egg-info/top_level.txt +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/cli.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/base.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/generic.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/compression/utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lgdo_utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/array.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/composite.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/encoded.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/scalar.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/vector_of_vectors.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/scalar.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/vector_of_vectors.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/concat.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/datatype.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/settings.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/logging.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/__init__.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/arrayofequalsizedarrays.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/fixedsizearray.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/histogram.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/lgdo.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/struct.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/vovutils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/types/waveformtable.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/units.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/conftest.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/sigcompress/LDQTA_r117_20200110T105115Z_cal_geds_raw-0.dat +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/sigcompress/special-wf-clipped.dat +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/test_compression.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/test_str2wfcodec.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/compression/test_uleb128_zigzag_diff.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/conftest.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/conftest.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_concat.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_core.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_datatype.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_store.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_tools.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/lh5/test_lh5_utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/test_cli.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/test_lgdo_utils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_array.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_arrayofequalsizedarrays.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_encoded.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_fixedsizearray.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_histogram.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_representations.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_scalar.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_struct.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_table.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_table_eval.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_vectorofvectors.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_vovutils.py +0 -0
- {legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/tests/types/test_waveformtable.py +0 -0
@@ -95,13 +95,13 @@ def encode(
|
|
95
95
|
if isinstance(sig_in, np.ndarray):
|
96
96
|
s = sig_in.shape
|
97
97
|
if len(sig_in) == 0:
|
98
|
-
return np.empty(s[:-1]
|
98
|
+
return np.empty((*s[:-1], 0), dtype=ubyte), np.empty(0, dtype=uint32)
|
99
99
|
|
100
100
|
if sig_out is None:
|
101
101
|
# the encoded signal is an array of bytes
|
102
102
|
# -> twice as long as a uint16
|
103
103
|
# pre-allocate ubyte (uint8) array, expand last dimension
|
104
|
-
sig_out = np.empty(s[:-1]
|
104
|
+
sig_out = np.empty((*s[:-1], s[-1] * 2), dtype=ubyte)
|
105
105
|
|
106
106
|
if sig_out.dtype != ubyte:
|
107
107
|
msg = "sig_out must be of type ubyte"
|
@@ -226,7 +226,7 @@ def decode(
|
|
226
226
|
# allocate output array with lasd dim as large as the longest
|
227
227
|
# uncompressed wf
|
228
228
|
maxs = np.max(_get_hton_u16(sig_in[0], 0))
|
229
|
-
sig_out = np.empty(s[:-1]
|
229
|
+
sig_out = np.empty((*s[:-1], maxs), dtype=int32)
|
230
230
|
|
231
231
|
# siglen has one dimension less (the last)
|
232
232
|
siglen = np.empty(s[:-1], dtype=uint32)
|
@@ -74,14 +74,14 @@ def encode(
|
|
74
74
|
if isinstance(sig_in, np.ndarray):
|
75
75
|
s = sig_in.shape
|
76
76
|
if len(sig_in) == 0:
|
77
|
-
return np.empty(s[:-1]
|
77
|
+
return np.empty((*s[:-1], 0), dtype=ubyte), np.empty(0, dtype=uint32)
|
78
78
|
|
79
79
|
if sig_out is None:
|
80
80
|
# the encoded signal is an array of bytes
|
81
81
|
# pre-allocate ubyte (uint8) array with a generous (but safe) size
|
82
82
|
max_b = int(np.ceil(np.iinfo(sig_in.dtype).bits / 16) * 5)
|
83
83
|
# expand last dimension
|
84
|
-
sig_out = np.empty(s[:-1]
|
84
|
+
sig_out = np.empty((*s[:-1], s[-1] * max_b), dtype=ubyte)
|
85
85
|
|
86
86
|
if sig_out.dtype != ubyte:
|
87
87
|
msg = "sig_out must be of type ubyte"
|
{legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/read/ndarray.py
RENAMED
@@ -57,7 +57,7 @@ def _h5_read_ndarray(
|
|
57
57
|
(start_row,) + (0,) * (h5d.rank - 1),
|
58
58
|
(1,) * h5d.rank,
|
59
59
|
None,
|
60
|
-
(n_rows_to_read,
|
60
|
+
(n_rows_to_read, *fspace.shape[1:]),
|
61
61
|
)
|
62
62
|
elif use_h5idx:
|
63
63
|
# Note that h5s will automatically merge adjacent elements into a range
|
@@ -67,7 +67,7 @@ def _h5_read_ndarray(
|
|
67
67
|
(i,) + (0,) * (h5d.rank - 1),
|
68
68
|
(1,) * h5d.rank,
|
69
69
|
None,
|
70
|
-
(1,
|
70
|
+
(1, *fspace.shape[1:]),
|
71
71
|
h5py.h5s.SELECT_OR,
|
72
72
|
)
|
73
73
|
|
@@ -84,7 +84,7 @@ def _h5_read_ndarray(
|
|
84
84
|
(obj_buf_start,) + (0,) * (h5d.rank - 1),
|
85
85
|
(1,) * h5d.rank,
|
86
86
|
None,
|
87
|
-
(n_rows_to_read,
|
87
|
+
(n_rows_to_read, *fspace.shape[1:]),
|
88
88
|
)
|
89
89
|
h5d.read(mspace, fspace, obj_buf.nda)
|
90
90
|
else:
|
@@ -93,10 +93,10 @@ def _h5_read_ndarray(
|
|
93
93
|
obj_buf.nda[dest_sel, ...] = tmp[idx, ...]
|
94
94
|
nda = obj_buf.nda
|
95
95
|
elif n_rows == 0:
|
96
|
-
tmp_shape = (0,
|
96
|
+
tmp_shape = (0, *h5d.shape[1:])
|
97
97
|
nda = np.empty(tmp_shape, h5d.dtype)
|
98
98
|
else:
|
99
|
-
mspace = h5py.h5s.create_simple((n_rows_to_read,
|
99
|
+
mspace = h5py.h5s.create_simple((n_rows_to_read, *fspace.shape[1:]))
|
100
100
|
nda = np.empty(mspace.shape, h5d.dtype)
|
101
101
|
if idx is None or use_h5idx:
|
102
102
|
h5d.read(mspace, fspace, nda)
|
{legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/array.py
RENAMED
@@ -40,7 +40,7 @@ def _h5_write_array(
|
|
40
40
|
# this is needed in order to have a resizable (in the first
|
41
41
|
# axis) data set, i.e. rows can be appended later
|
42
42
|
# NOTE: this automatically turns chunking on!
|
43
|
-
maxshape = (None,
|
43
|
+
maxshape = (None, *nda.shape[1:])
|
44
44
|
h5py_kwargs.setdefault("maxshape", maxshape)
|
45
45
|
|
46
46
|
if wo_mode == "o" and name in group:
|
{legend_pydataobj-1.13.0 → legend_pydataobj-1.14.1}/src/lgdo/lh5/_serializers/write/composite.py
RENAMED
@@ -52,140 +52,166 @@ def _h5_write_lgdo(
|
|
52
52
|
# In hdf5, 'a' is really "modify" -- in addition to appending, you can
|
53
53
|
# change any object in the file. So we use file:append for
|
54
54
|
# write_object:overwrite.
|
55
|
+
opened_here = False
|
55
56
|
if not isinstance(lh5_file, h5py.File):
|
56
57
|
mode = "w" if wo_mode == "of" or not Path(lh5_file).exists() else "a"
|
57
|
-
lh5_file = h5py.File(lh5_file, mode=mode, **file_kwargs)
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
)
|
64
|
-
|
65
|
-
group = utils.get_h5_group(group, lh5_file)
|
59
|
+
try:
|
60
|
+
fh = h5py.File(lh5_file, mode=mode, **file_kwargs)
|
61
|
+
except OSError as oe:
|
62
|
+
raise LH5EncodeError(str(oe), lh5_file, None) from oe
|
66
63
|
|
67
|
-
|
68
|
-
if name in group or (
|
69
|
-
("datatype" in group.attrs or group == "/")
|
70
|
-
and (len(name) <= 2 or "/" not in name[1:-1])
|
71
|
-
):
|
72
|
-
pass
|
73
|
-
# group is in file but not struct or need to create nesting
|
64
|
+
opened_here = True
|
74
65
|
else:
|
75
|
-
|
76
|
-
# if name is nested, iterate up from parent
|
77
|
-
# otherwise we just need to iterate the group
|
78
|
-
if len(name) > 2 and "/" in name[1:-1]:
|
79
|
-
group = utils.get_h5_group(
|
80
|
-
name[:-1].rsplit("/", 1)[0],
|
81
|
-
group,
|
82
|
-
)
|
83
|
-
curr_name = (
|
84
|
-
name.rsplit("/", 1)[1]
|
85
|
-
if name[-1] != "/"
|
86
|
-
else name[:-1].rsplit("/", 1)[1]
|
87
|
-
)
|
88
|
-
else:
|
89
|
-
curr_name = name
|
90
|
-
# initialize the object to be written
|
91
|
-
obj = types.Struct({curr_name.replace("/", ""): obj})
|
66
|
+
fh = lh5_file
|
92
67
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
if len(group) > 1:
|
100
|
-
break
|
101
|
-
curr_name = group.name
|
102
|
-
group = group.parent
|
103
|
-
if group.name != "/":
|
104
|
-
obj = types.Struct({curr_name[len(group.name) + 1 :]: obj})
|
105
|
-
else:
|
106
|
-
obj = types.Struct({curr_name[1:]: obj})
|
107
|
-
# if the group has more than one child, we need to append else we can overwrite
|
108
|
-
wo_mode = "ac" if len(group) > 1 else "o"
|
109
|
-
|
110
|
-
# set the new name
|
111
|
-
if group.name == "/":
|
112
|
-
name = "/"
|
113
|
-
elif group.parent.name == "/":
|
114
|
-
name = group.name[1:]
|
115
|
-
else:
|
116
|
-
name = group.name[len(group.parent.name) + 1 :]
|
117
|
-
# get the new group
|
118
|
-
group = utils.get_h5_group(group.parent if group.name != "/" else "/", lh5_file)
|
68
|
+
try:
|
69
|
+
log.debug(
|
70
|
+
f"writing {obj!r}[{start_row}:{n_rows}] as "
|
71
|
+
f"{fh.filename}:{group}/{name}[{write_start}:], "
|
72
|
+
f"mode = {wo_mode}, h5py_kwargs = {h5py_kwargs}"
|
73
|
+
)
|
119
74
|
|
120
|
-
|
121
|
-
msg = f"can't overwrite '{name}' in wo_mode 'write_safe'"
|
122
|
-
raise LH5EncodeError(msg, lh5_file, group, name)
|
75
|
+
group = utils.get_h5_group(group, fh)
|
123
76
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
and wo_mode not in ["w", "o", "of"]
|
129
|
-
and name in group
|
77
|
+
# name already in file
|
78
|
+
if name in group or (
|
79
|
+
("datatype" in group.attrs or group == "/")
|
80
|
+
and (len(name) <= 2 or "/" not in name[1:-1])
|
130
81
|
):
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
82
|
+
pass
|
83
|
+
# group is in file but not struct or need to create nesting
|
84
|
+
else:
|
85
|
+
# check if name is nested
|
86
|
+
# if name is nested, iterate up from parent
|
87
|
+
# otherwise we just need to iterate the group
|
88
|
+
if len(name) > 2 and "/" in name[1:-1]:
|
89
|
+
group = utils.get_h5_group(
|
90
|
+
name[:-1].rsplit("/", 1)[0],
|
91
|
+
group,
|
92
|
+
)
|
93
|
+
curr_name = (
|
94
|
+
name.rsplit("/", 1)[1]
|
95
|
+
if name[-1] != "/"
|
96
|
+
else name[:-1].rsplit("/", 1)[1]
|
97
|
+
)
|
98
|
+
else:
|
99
|
+
curr_name = name
|
100
|
+
# initialize the object to be written
|
101
|
+
obj = types.Struct({curr_name.replace("/", ""): obj})
|
102
|
+
|
103
|
+
# if base group already has a child we just append
|
104
|
+
if len(group) >= 1:
|
105
|
+
wo_mode = "ac"
|
106
|
+
else:
|
107
|
+
# iterate up the group hierarchy until we reach the root or a group with more than one child
|
108
|
+
while group.name != "/":
|
109
|
+
if len(group) > 1:
|
110
|
+
break
|
111
|
+
curr_name = group.name
|
112
|
+
group = group.parent
|
113
|
+
if group.name != "/":
|
114
|
+
obj = types.Struct({curr_name[len(group.name) + 1 :]: obj})
|
115
|
+
else:
|
116
|
+
obj = types.Struct({curr_name[1:]: obj})
|
117
|
+
# if the group has more than one child, we need to append else we can overwrite
|
118
|
+
wo_mode = "ac" if len(group) > 1 else "o"
|
119
|
+
|
120
|
+
# set the new name
|
121
|
+
if group.name == "/":
|
122
|
+
name = "/"
|
123
|
+
elif group.parent.name == "/":
|
124
|
+
name = group.name[1:]
|
125
|
+
else:
|
126
|
+
name = group.name[len(group.parent.name) + 1 :]
|
127
|
+
# get the new group
|
128
|
+
group = utils.get_h5_group(group.parent if group.name != "/" else "/", fh)
|
129
|
+
|
130
|
+
if wo_mode == "w" and name in group:
|
131
|
+
msg = f"can't overwrite '{name}' in wo_mode 'write_safe'"
|
132
|
+
raise LH5EncodeError(msg, fh, group, name)
|
133
|
+
|
134
|
+
# struct, table, waveform table or histogram.
|
135
|
+
if isinstance(obj, types.Struct):
|
136
|
+
if (
|
137
|
+
isinstance(obj, types.Histogram)
|
138
|
+
and wo_mode not in ["w", "o", "of"]
|
139
|
+
and name in group
|
140
|
+
):
|
141
|
+
msg = f"can't append-write to histogram in wo_mode '{wo_mode}'"
|
142
|
+
raise LH5EncodeError(msg, fh, group, name)
|
143
|
+
if isinstance(obj, types.Histogram) and write_start != 0:
|
144
|
+
msg = f"can't write histogram in wo_mode '{wo_mode}' with write_start != 0"
|
145
|
+
raise LH5EncodeError(msg, fh, group, name)
|
146
|
+
|
147
|
+
return _h5_write_struct(
|
148
|
+
obj,
|
149
|
+
name,
|
150
|
+
fh,
|
151
|
+
group=group,
|
152
|
+
start_row=start_row,
|
153
|
+
n_rows=n_rows, # if isinstance(obj, types.Table | types.Histogram) else None,
|
154
|
+
wo_mode=wo_mode,
|
155
|
+
write_start=write_start,
|
156
|
+
**h5py_kwargs,
|
157
|
+
)
|
152
158
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
):
|
157
|
-
group = utils.get_h5_group(
|
158
|
-
name, group, grp_attrs=obj.attrs, overwrite=(wo_mode == "o")
|
159
|
-
)
|
159
|
+
# scalars
|
160
|
+
if isinstance(obj, types.Scalar):
|
161
|
+
return _h5_write_scalar(obj, name, fh, group, wo_mode)
|
160
162
|
|
161
|
-
#
|
162
|
-
|
163
|
+
# vector of encoded vectors
|
164
|
+
if isinstance(
|
165
|
+
obj, (types.VectorOfEncodedVectors, types.ArrayOfEncodedEqualSizedArrays)
|
166
|
+
):
|
167
|
+
group = utils.get_h5_group(
|
168
|
+
name, group, grp_attrs=obj.attrs, overwrite=(wo_mode == "o")
|
169
|
+
)
|
163
170
|
|
164
|
-
|
165
|
-
obj.encoded_data
|
166
|
-
"encoded_data",
|
167
|
-
lh5_file,
|
168
|
-
group=group,
|
169
|
-
start_row=start_row,
|
170
|
-
n_rows=n_rows,
|
171
|
-
wo_mode=wo_mode,
|
172
|
-
write_start=write_start,
|
173
|
-
**h5py_kwargs,
|
174
|
-
)
|
171
|
+
# ask not to further compress flattened_data, it is already compressed!
|
172
|
+
obj.encoded_data.flattened_data.attrs["compression"] = None
|
175
173
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
lh5_file,
|
174
|
+
_h5_write_vector_of_vectors(
|
175
|
+
obj.encoded_data,
|
176
|
+
"encoded_data",
|
177
|
+
fh,
|
181
178
|
group=group,
|
179
|
+
start_row=start_row,
|
180
|
+
n_rows=n_rows,
|
182
181
|
wo_mode=wo_mode,
|
182
|
+
write_start=write_start,
|
183
|
+
**h5py_kwargs,
|
183
184
|
)
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
185
|
+
|
186
|
+
if isinstance(obj.decoded_size, types.Scalar):
|
187
|
+
_h5_write_scalar(
|
188
|
+
obj.decoded_size,
|
189
|
+
"decoded_size",
|
190
|
+
fh,
|
191
|
+
group=group,
|
192
|
+
wo_mode=wo_mode,
|
193
|
+
)
|
194
|
+
else:
|
195
|
+
_h5_write_array(
|
196
|
+
obj.decoded_size,
|
197
|
+
"decoded_size",
|
198
|
+
fh,
|
199
|
+
group=group,
|
200
|
+
start_row=start_row,
|
201
|
+
n_rows=n_rows,
|
202
|
+
wo_mode=wo_mode,
|
203
|
+
write_start=write_start,
|
204
|
+
**h5py_kwargs,
|
205
|
+
)
|
206
|
+
|
207
|
+
return None
|
208
|
+
|
209
|
+
# vector of vectors
|
210
|
+
if isinstance(obj, types.VectorOfVectors):
|
211
|
+
return _h5_write_vector_of_vectors(
|
212
|
+
obj,
|
213
|
+
name,
|
214
|
+
fh,
|
189
215
|
group=group,
|
190
216
|
start_row=start_row,
|
191
217
|
n_rows=n_rows,
|
@@ -194,38 +220,25 @@ def _h5_write_lgdo(
|
|
194
220
|
**h5py_kwargs,
|
195
221
|
)
|
196
222
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
**h5py_kwargs,
|
211
|
-
)
|
212
|
-
|
213
|
-
# if we get this far, must be one of the Array types
|
214
|
-
if isinstance(obj, types.Array):
|
215
|
-
return _h5_write_array(
|
216
|
-
obj,
|
217
|
-
name,
|
218
|
-
lh5_file,
|
219
|
-
group=group,
|
220
|
-
start_row=start_row,
|
221
|
-
n_rows=n_rows,
|
222
|
-
wo_mode=wo_mode,
|
223
|
-
write_start=write_start,
|
224
|
-
**h5py_kwargs,
|
225
|
-
)
|
223
|
+
# if we get this far, must be one of the Array types
|
224
|
+
if isinstance(obj, types.Array):
|
225
|
+
return _h5_write_array(
|
226
|
+
obj,
|
227
|
+
name,
|
228
|
+
fh,
|
229
|
+
group=group,
|
230
|
+
start_row=start_row,
|
231
|
+
n_rows=n_rows,
|
232
|
+
wo_mode=wo_mode,
|
233
|
+
write_start=write_start,
|
234
|
+
**h5py_kwargs,
|
235
|
+
)
|
226
236
|
|
227
|
-
|
228
|
-
|
237
|
+
msg = f"do not know how to write '{name}' of type '{type(obj).__name__}'"
|
238
|
+
raise LH5EncodeError(msg, fh, group, name)
|
239
|
+
finally:
|
240
|
+
if opened_here:
|
241
|
+
fh.close()
|
229
242
|
|
230
243
|
|
231
244
|
def _h5_write_struct(
|
@@ -14,12 +14,13 @@ from numpy.typing import ArrayLike
|
|
14
14
|
|
15
15
|
from .. import types
|
16
16
|
from . import _serializers
|
17
|
+
from .exceptions import LH5DecodeError
|
17
18
|
from .utils import read_n_rows
|
18
19
|
|
19
20
|
|
20
21
|
def read(
|
21
22
|
name: str,
|
22
|
-
lh5_file: str | h5py.File | Sequence[str | h5py.File],
|
23
|
+
lh5_file: str | Path | h5py.File | Sequence[str | Path | h5py.File],
|
23
24
|
start_row: int = 0,
|
24
25
|
n_rows: int = sys.maxsize,
|
25
26
|
idx: ArrayLike = None,
|
@@ -110,15 +111,20 @@ def read(
|
|
110
111
|
object
|
111
112
|
the read-out object
|
112
113
|
"""
|
114
|
+
close_after = False
|
113
115
|
if isinstance(lh5_file, h5py.File):
|
114
116
|
lh5_obj = lh5_file[name]
|
115
|
-
elif isinstance(lh5_file, str):
|
116
|
-
|
117
|
+
elif isinstance(lh5_file, (str, Path)):
|
118
|
+
try:
|
119
|
+
lh5_file = h5py.File(str(Path(lh5_file)), mode="r", locking=locking)
|
120
|
+
except (OSError, FileExistsError) as oe:
|
121
|
+
raise LH5DecodeError(str(oe), lh5_file, None) from oe
|
122
|
+
|
123
|
+
close_after = True
|
117
124
|
try:
|
118
125
|
lh5_obj = lh5_file[name]
|
119
126
|
except KeyError as ke:
|
120
|
-
|
121
|
-
raise KeyError(err) from ke
|
127
|
+
raise LH5DecodeError(str(ke), lh5_file, name) from ke
|
122
128
|
else:
|
123
129
|
if obj_buf is not None:
|
124
130
|
obj_buf.resize(obj_buf_start)
|
@@ -173,29 +179,32 @@ def read(
|
|
173
179
|
if isinstance(idx, np.ndarray) and idx.dtype == np.dtype("?"):
|
174
180
|
idx = np.where(idx)[0]
|
175
181
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
182
|
+
try:
|
183
|
+
obj, n_rows_read = _serializers._h5_read_lgdo(
|
184
|
+
lh5_obj.id,
|
185
|
+
lh5_obj.file.filename,
|
186
|
+
lh5_obj.name,
|
187
|
+
start_row=start_row,
|
188
|
+
n_rows=n_rows,
|
189
|
+
idx=idx,
|
190
|
+
use_h5idx=use_h5idx,
|
191
|
+
field_mask=field_mask,
|
192
|
+
obj_buf=obj_buf,
|
193
|
+
obj_buf_start=obj_buf_start,
|
194
|
+
decompress=decompress,
|
195
|
+
)
|
196
|
+
with suppress(AttributeError):
|
197
|
+
obj.resize(obj_buf_start + n_rows_read)
|
198
|
+
return obj
|
199
|
+
finally:
|
200
|
+
if close_after:
|
201
|
+
lh5_file.close()
|
193
202
|
|
194
203
|
|
195
204
|
def write(
|
196
205
|
obj: types.LGDO,
|
197
206
|
name: str,
|
198
|
-
lh5_file: str | h5py.File,
|
207
|
+
lh5_file: str | Path | h5py.File,
|
199
208
|
group: str | h5py.Group = "/",
|
200
209
|
start_row: int = 0,
|
201
210
|
n_rows: int | None = None,
|
@@ -318,7 +327,7 @@ def write(
|
|
318
327
|
|
319
328
|
def read_as(
|
320
329
|
name: str,
|
321
|
-
lh5_file: str | h5py.File | Sequence[str | h5py.File],
|
330
|
+
lh5_file: str | Path | h5py.File | Sequence[str | Path | h5py.File],
|
322
331
|
library: str,
|
323
332
|
**kwargs,
|
324
333
|
) -> Any:
|
@@ -0,0 +1,55 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import h5py
|
4
|
+
|
5
|
+
|
6
|
+
class LH5DecodeError(Exception):
|
7
|
+
def __init__(
|
8
|
+
self, message: str, file: str | h5py.File, oname: str | None = None
|
9
|
+
) -> None:
|
10
|
+
super().__init__(message)
|
11
|
+
|
12
|
+
self.file = file.filename if isinstance(file, h5py.File) else file
|
13
|
+
self.obj = oname
|
14
|
+
|
15
|
+
def __str__(self) -> str:
|
16
|
+
if self.obj is None:
|
17
|
+
msg = f"while opening file {self.file} for decoding: "
|
18
|
+
else:
|
19
|
+
msg = f"while decoding object '{self.obj}' in file {self.file}: "
|
20
|
+
|
21
|
+
return msg + super().__str__()
|
22
|
+
|
23
|
+
def __reduce__(self) -> tuple: # for pickling.
|
24
|
+
return self.__class__, (*self.args, self.file, self.obj)
|
25
|
+
|
26
|
+
|
27
|
+
class LH5EncodeError(Exception):
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
message: str,
|
31
|
+
file: str | h5py.File,
|
32
|
+
group: str | h5py.Group | None = None,
|
33
|
+
name: str | None = None,
|
34
|
+
) -> None:
|
35
|
+
super().__init__(message)
|
36
|
+
|
37
|
+
self.file = file.filename if isinstance(file, h5py.File) else file
|
38
|
+
self.group = (
|
39
|
+
(group.name if isinstance(file, h5py.File) else group).rstrip("/")
|
40
|
+
if group is not None
|
41
|
+
else None
|
42
|
+
)
|
43
|
+
self.name = name.lstrip("/") if name is not None else None
|
44
|
+
|
45
|
+
def __str__(self) -> str:
|
46
|
+
if self.name is None:
|
47
|
+
msg = f"while opening file {self.file} for encoding: "
|
48
|
+
else:
|
49
|
+
msg = (
|
50
|
+
f"while encoding object {self.group}/{self.name} to file {self.file}: "
|
51
|
+
)
|
52
|
+
return msg + super().__str__()
|
53
|
+
|
54
|
+
def __reduce__(self) -> tuple: # for pickling.
|
55
|
+
return self.__class__, (*self.args, self.file, self.group, self.name)
|