legend-pydataobj 1.14.0__tar.gz → 1.14.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 (98) hide show
  1. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/PKG-INFO +1 -1
  2. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/PKG-INFO +1 -1
  3. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/_version.py +2 -2
  4. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/write/composite.py +162 -149
  5. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/core.py +29 -20
  6. legend_pydataobj-1.14.2/src/lgdo/lh5/exceptions.py +55 -0
  7. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/store.py +5 -1
  8. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/tools.py +5 -1
  9. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/utils.py +8 -2
  10. legend_pydataobj-1.14.2/tests/lh5/test_exceptions.py +273 -0
  11. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_write.py +1 -122
  12. legend_pydataobj-1.14.0/src/lgdo/lh5/exceptions.py +0 -40
  13. legend_pydataobj-1.14.0/tests/lh5/test_exceptions.py +0 -17
  14. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/LICENSE +0 -0
  15. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/README.md +0 -0
  16. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/pyproject.toml +0 -0
  17. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/setup.cfg +0 -0
  18. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/SOURCES.txt +0 -0
  19. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/dependency_links.txt +0 -0
  20. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/entry_points.txt +0 -0
  21. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/not-zip-safe +0 -0
  22. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/requires.txt +0 -0
  23. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/legend_pydataobj.egg-info/top_level.txt +0 -0
  24. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/__init__.py +0 -0
  25. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/cli.py +0 -0
  26. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/__init__.py +0 -0
  27. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/base.py +0 -0
  28. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/generic.py +0 -0
  29. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/radware.py +0 -0
  30. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/utils.py +0 -0
  31. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/compression/varlen.py +0 -0
  32. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lgdo_utils.py +0 -0
  33. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/__init__.py +0 -0
  34. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/__init__.py +0 -0
  35. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/__init__.py +0 -0
  36. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/array.py +0 -0
  37. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/composite.py +0 -0
  38. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/encoded.py +0 -0
  39. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/ndarray.py +0 -0
  40. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/scalar.py +0 -0
  41. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/utils.py +0 -0
  42. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/read/vector_of_vectors.py +0 -0
  43. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/write/__init__.py +0 -0
  44. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/write/array.py +0 -0
  45. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/write/scalar.py +0 -0
  46. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/_serializers/write/vector_of_vectors.py +0 -0
  47. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/concat.py +0 -0
  48. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/datatype.py +0 -0
  49. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/iterator.py +0 -0
  50. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/lh5/settings.py +0 -0
  51. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/logging.py +0 -0
  52. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/__init__.py +0 -0
  53. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/array.py +0 -0
  54. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/arrayofequalsizedarrays.py +0 -0
  55. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/encoded.py +0 -0
  56. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/fixedsizearray.py +0 -0
  57. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/histogram.py +0 -0
  58. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/lgdo.py +0 -0
  59. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/scalar.py +0 -0
  60. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/struct.py +0 -0
  61. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/table.py +0 -0
  62. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/vectorofvectors.py +0 -0
  63. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/vovutils.py +0 -0
  64. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/types/waveformtable.py +0 -0
  65. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/units.py +0 -0
  66. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/src/lgdo/utils.py +0 -0
  67. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/conftest.py +0 -0
  68. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/sigcompress/LDQTA_r117_20200110T105115Z_cal_geds_raw-0.dat +0 -0
  69. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/sigcompress/special-wf-clipped.dat +0 -0
  70. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/test_compression.py +0 -0
  71. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/test_radware_sigcompress.py +0 -0
  72. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/test_str2wfcodec.py +0 -0
  73. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/compression/test_uleb128_zigzag_diff.py +0 -0
  74. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/conftest.py +0 -0
  75. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/conftest.py +0 -0
  76. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_concat.py +0 -0
  77. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_core.py +0 -0
  78. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_datatype.py +0 -0
  79. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_iterator.py +0 -0
  80. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_store.py +0 -0
  81. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_tools.py +0 -0
  82. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_lh5_utils.py +0 -0
  83. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/lh5/test_pathlib.py +0 -0
  84. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/test_cli.py +0 -0
  85. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/test_lgdo_utils.py +0 -0
  86. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_array.py +0 -0
  87. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_arrayofequalsizedarrays.py +0 -0
  88. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_encoded.py +0 -0
  89. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_fixedsizearray.py +0 -0
  90. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_histogram.py +0 -0
  91. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_representations.py +0 -0
  92. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_scalar.py +0 -0
  93. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_struct.py +0 -0
  94. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_table.py +0 -0
  95. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_table_eval.py +0 -0
  96. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_vectorofvectors.py +0 -0
  97. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_vovutils.py +0 -0
  98. {legend_pydataobj-1.14.0 → legend_pydataobj-1.14.2}/tests/types/test_waveformtable.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: legend_pydataobj
3
- Version: 1.14.0
3
+ Version: 1.14.2
4
4
  Summary: LEGEND Python Data Objects
5
5
  Author: The LEGEND Collaboration
6
6
  Maintainer: The LEGEND Collaboration
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: legend_pydataobj
3
- Version: 1.14.0
3
+ Version: 1.14.2
4
4
  Summary: LEGEND Python Data Objects
5
5
  Author: The LEGEND Collaboration
6
6
  Maintainer: The LEGEND Collaboration
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '1.14.0'
21
- __version_tuple__ = version_tuple = (1, 14, 0)
20
+ __version__ = version = '1.14.2'
21
+ __version_tuple__ = version_tuple = (1, 14, 2)
@@ -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
- log.debug(
60
- f"writing {obj!r}[{start_row}:{n_rows}] as "
61
- f"{lh5_file.filename}:{group}/{name}[{write_start}:], "
62
- f"mode = {wo_mode}, h5py_kwargs = {h5py_kwargs}"
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(oe, lh5_file) from oe
66
63
 
67
- # name already in file
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
- # check if name is nested
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
- # if base group already has a child we just append
94
- if len(group) >= 1:
95
- wo_mode = "ac"
96
- else:
97
- # iterate up the group hierarchy until we reach the root or a group with more than one child
98
- while group.name != "/":
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
- if wo_mode == "w" and name in group:
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
- # struct, table, waveform table or histogram.
125
- if isinstance(obj, types.Struct):
126
- if (
127
- isinstance(obj, types.Histogram)
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
- msg = f"can't append-write to histogram in wo_mode '{wo_mode}'"
132
- raise LH5EncodeError(msg, lh5_file, group, name)
133
- if isinstance(obj, types.Histogram) and write_start != 0:
134
- msg = f"can't write histogram in wo_mode '{wo_mode}' with write_start != 0"
135
- raise LH5EncodeError(msg, lh5_file, group, name)
136
-
137
- return _h5_write_struct(
138
- obj,
139
- name,
140
- lh5_file,
141
- group=group,
142
- start_row=start_row,
143
- n_rows=n_rows, # if isinstance(obj, types.Table | types.Histogram) else None,
144
- wo_mode=wo_mode,
145
- write_start=write_start,
146
- **h5py_kwargs,
147
- )
148
-
149
- # scalars
150
- if isinstance(obj, types.Scalar):
151
- return _h5_write_scalar(obj, name, lh5_file, group, wo_mode)
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
- # vector of encoded vectors
154
- if isinstance(
155
- obj, (types.VectorOfEncodedVectors, types.ArrayOfEncodedEqualSizedArrays)
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
- # ask not to further compress flattened_data, it is already compressed!
162
- obj.encoded_data.flattened_data.attrs["compression"] = None
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
- _h5_write_vector_of_vectors(
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
- if isinstance(obj.decoded_size, types.Scalar):
177
- _h5_write_scalar(
178
- obj.decoded_size,
179
- "decoded_size",
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
- else:
185
- _h5_write_array(
186
- obj.decoded_size,
187
- "decoded_size",
188
- lh5_file,
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
- return None
198
-
199
- # vector of vectors
200
- if isinstance(obj, types.VectorOfVectors):
201
- return _h5_write_vector_of_vectors(
202
- obj,
203
- name,
204
- lh5_file,
205
- group=group,
206
- start_row=start_row,
207
- n_rows=n_rows,
208
- wo_mode=wo_mode,
209
- write_start=write_start,
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
- msg = f"do not know how to write '{name}' of type '{type(obj).__name__}'"
228
- raise LH5EncodeError(msg, lh5_file, group, name)
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,6 +14,7 @@ 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
 
@@ -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
117
  elif isinstance(lh5_file, (str, Path)):
116
- lh5_file = h5py.File(str(Path(lh5_file)), mode="r", locking=locking)
118
+ try:
119
+ lh5_file = h5py.File(str(Path(lh5_file)), mode="r", locking=locking)
120
+ except (OSError, FileExistsError) as oe:
121
+ raise LH5DecodeError(oe, lh5_file) from oe
122
+
123
+ close_after = True
117
124
  try:
118
125
  lh5_obj = lh5_file[name]
119
126
  except KeyError as ke:
120
- err = f"Object {name} not found in file {lh5_file.filename}"
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,23 +179,26 @@ def read(
173
179
  if isinstance(idx, np.ndarray) and idx.dtype == np.dtype("?"):
174
180
  idx = np.where(idx)[0]
175
181
 
176
- obj, n_rows_read = _serializers._h5_read_lgdo(
177
- lh5_obj.id,
178
- lh5_obj.file.filename,
179
- lh5_obj.name,
180
- start_row=start_row,
181
- n_rows=n_rows,
182
- idx=idx,
183
- use_h5idx=use_h5idx,
184
- field_mask=field_mask,
185
- obj_buf=obj_buf,
186
- obj_buf_start=obj_buf_start,
187
- decompress=decompress,
188
- )
189
- with suppress(AttributeError):
190
- obj.resize(obj_buf_start + n_rows_read)
191
-
192
- return obj
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(
@@ -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)
@@ -19,6 +19,7 @@ from numpy.typing import ArrayLike
19
19
  from .. import types
20
20
  from . import _serializers, utils
21
21
  from .core import read
22
+ from .exceptions import LH5DecodeError
22
23
 
23
24
  log = logging.getLogger(__name__)
24
25
 
@@ -125,7 +126,10 @@ class LH5Store:
125
126
  "fs_page_size": page_buffer,
126
127
  }
127
128
  )
128
- h5f = h5py.File(full_path, mode, **file_kwargs)
129
+ try:
130
+ h5f = h5py.File(full_path, mode, **file_kwargs)
131
+ except (OSError, FileExistsError) as oe:
132
+ raise LH5DecodeError(oe, full_path) from oe
129
133
 
130
134
  if self.keep_open:
131
135
  if isinstance(self.keep_open, int) and len(self.files) >= self.keep_open:
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  import h5py
9
9
 
10
10
  from . import utils
11
+ from .exceptions import LH5DecodeError
11
12
  from .store import LH5Store
12
13
 
13
14
  log = logging.getLogger(__name__)
@@ -123,7 +124,10 @@ def show(
123
124
 
124
125
  # open file
125
126
  if isinstance(lh5_file, (str, Path)):
126
- lh5_file = h5py.File(utils.expand_path(Path(lh5_file)), "r", locking=False)
127
+ try:
128
+ lh5_file = h5py.File(utils.expand_path(Path(lh5_file)), "r", locking=False)
129
+ except (OSError, FileExistsError) as oe:
130
+ raise LH5DecodeError(oe, lh5_file) from oe
127
131
 
128
132
  # go to group
129
133
  if lh5_group != "/":
@@ -45,7 +45,10 @@ def read_n_rows(name: str, h5f: str | Path | h5py.File) -> int | None:
45
45
  Return ``None`` if `name` is a :class:`.Scalar` or a :class:`.Struct`.
46
46
  """
47
47
  if not isinstance(h5f, h5py.File):
48
- h5f = h5py.File(h5f, "r", locking=False)
48
+ try:
49
+ h5f = h5py.File(h5f, "r", locking=False)
50
+ except (OSError, FileExistsError) as oe:
51
+ raise LH5DecodeError(oe, h5f, None) from oe
49
52
 
50
53
  try:
51
54
  h5o = h5f[name].id
@@ -61,7 +64,10 @@ def read_size_in_bytes(name: str, h5f: str | Path | h5py.File) -> int | None:
61
64
  recursively through members of a Struct or Table
62
65
  """
63
66
  if not isinstance(h5f, h5py.File):
64
- h5f = h5py.File(h5f, "r", locking=False)
67
+ try:
68
+ h5f = h5py.File(h5f, "r", locking=False)
69
+ except (OSError, FileExistsError) as oe:
70
+ raise LH5DecodeError(oe, h5f) from oe
65
71
 
66
72
  try:
67
73
  h5o = h5f[name].id