legend-pydataobj 1.12.0a2__tar.gz → 1.12.0a4__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 (94) hide show
  1. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/PKG-INFO +1 -1
  2. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/pyproject.toml +2 -2
  3. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/PKG-INFO +1 -1
  4. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/_version.py +2 -2
  5. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/write/composite.py +2 -2
  6. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/core.py +5 -1
  7. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/store.py +7 -7
  8. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/utils.py +6 -4
  9. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/vectorofvectors.py +60 -18
  10. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/test_radware_sigcompress.py +2 -2
  11. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/conftest.py +3 -3
  12. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_utils.py +9 -1
  13. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_write.py +21 -21
  14. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_vectorofvectors.py +44 -0
  15. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/LICENSE +0 -0
  16. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/README.md +0 -0
  17. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/setup.cfg +0 -0
  18. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/SOURCES.txt +0 -0
  19. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/dependency_links.txt +0 -0
  20. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/entry_points.txt +0 -0
  21. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/not-zip-safe +0 -0
  22. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/requires.txt +0 -0
  23. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/legend_pydataobj.egg-info/top_level.txt +0 -0
  24. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/__init__.py +0 -0
  25. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/cli.py +0 -0
  26. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/__init__.py +0 -0
  27. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/base.py +0 -0
  28. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/generic.py +0 -0
  29. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/radware.py +0 -0
  30. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/utils.py +0 -0
  31. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/compression/varlen.py +0 -0
  32. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lgdo_utils.py +0 -0
  33. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/__init__.py +0 -0
  34. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/__init__.py +0 -0
  35. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/__init__.py +0 -0
  36. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/array.py +0 -0
  37. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/composite.py +0 -0
  38. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/encoded.py +0 -0
  39. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/ndarray.py +0 -0
  40. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/scalar.py +0 -0
  41. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/utils.py +0 -0
  42. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/read/vector_of_vectors.py +0 -0
  43. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/write/__init__.py +0 -0
  44. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/write/array.py +0 -0
  45. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/write/scalar.py +0 -0
  46. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/_serializers/write/vector_of_vectors.py +0 -0
  47. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/concat.py +0 -0
  48. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/datatype.py +0 -0
  49. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/exceptions.py +0 -0
  50. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/iterator.py +0 -0
  51. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/lh5/tools.py +0 -0
  52. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/logging.py +0 -0
  53. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/__init__.py +0 -0
  54. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/array.py +0 -0
  55. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/arrayofequalsizedarrays.py +0 -0
  56. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/encoded.py +0 -0
  57. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/fixedsizearray.py +0 -0
  58. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/histogram.py +0 -0
  59. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/lgdo.py +0 -0
  60. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/scalar.py +0 -0
  61. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/struct.py +0 -0
  62. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/table.py +0 -0
  63. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/vovutils.py +0 -0
  64. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/types/waveformtable.py +0 -0
  65. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/units.py +0 -0
  66. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/src/lgdo/utils.py +0 -0
  67. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/conftest.py +0 -0
  68. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/sigcompress/LDQTA_r117_20200110T105115Z_cal_geds_raw-0.dat +0 -0
  69. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/sigcompress/special-wf-clipped.dat +0 -0
  70. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/test_compression.py +0 -0
  71. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/test_str2wfcodec.py +0 -0
  72. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/compression/test_uleb128_zigzag_diff.py +0 -0
  73. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/conftest.py +0 -0
  74. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_concat.py +0 -0
  75. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_core.py +0 -0
  76. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_exceptions.py +0 -0
  77. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_datatype.py +0 -0
  78. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_iterator.py +0 -0
  79. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_store.py +0 -0
  80. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/lh5/test_lh5_tools.py +0 -0
  81. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/test_cli.py +0 -0
  82. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/test_lgdo_utils.py +0 -0
  83. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_array.py +0 -0
  84. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_arrayofequalsizedarrays.py +0 -0
  85. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_encoded.py +0 -0
  86. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_fixedsizearray.py +0 -0
  87. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_histogram.py +0 -0
  88. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_representations.py +0 -0
  89. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_scalar.py +0 -0
  90. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_struct.py +0 -0
  91. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_table.py +0 -0
  92. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_table_eval.py +0 -0
  93. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/tests/types/test_vovutils.py +0 -0
  94. {legend_pydataobj-1.12.0a2 → legend_pydataobj-1.12.0a4}/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.12.0a2
3
+ Version: 1.12.0a4
4
4
  Summary: LEGEND Python Data Objects
5
5
  Author: The LEGEND Collaboration
6
6
  Maintainer: The LEGEND Collaboration
@@ -122,7 +122,7 @@ extend-select = [
122
122
  "PIE", # flake8-pie
123
123
  "PL", # pylint
124
124
  "PT", # flake8-pytest-style
125
- #"PTH", # flake8-use-pathlib
125
+ "PTH", # flake8-use-pathlib
126
126
  "RET", # flake8-return
127
127
  "RUF", # Ruff-specific
128
128
  "SIM", # flake8-simplify
@@ -167,7 +167,7 @@ minversion = "6.0"
167
167
  addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
168
168
  xfail_strict = true
169
169
  filterwarnings = ["error", 'ignore:\nPyarrow:DeprecationWarning']
170
- log_cli_level = "info"
170
+ log_cli_level = "INFO"
171
171
  testpaths = "tests"
172
172
 
173
173
  [tool.codespell]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: legend_pydataobj
3
- Version: 1.12.0a2
3
+ Version: 1.12.0a4
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.12.0a2'
21
- __version_tuple__ = version_tuple = (1, 12, 0)
20
+ __version__ = version = '1.12.0a4'
21
+ __version_tuple__ = version_tuple = (1, 12, 0, 'a4')
@@ -1,8 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- import os
5
4
  from inspect import signature
5
+ from pathlib import Path
6
6
 
7
7
  import h5py
8
8
 
@@ -53,7 +53,7 @@ def _h5_write_lgdo(
53
53
  # change any object in the file. So we use file:append for
54
54
  # write_object:overwrite.
55
55
  if not isinstance(lh5_file, h5py.File):
56
- mode = "w" if wo_mode == "of" or not os.path.exists(lh5_file) else "a"
56
+ mode = "w" if wo_mode == "of" or not Path(lh5_file).exists() else "a"
57
57
  lh5_file = h5py.File(lh5_file, mode=mode, **file_kwargs)
58
58
 
59
59
  log.debug(
@@ -113,7 +113,11 @@ def read(
113
113
  lh5_obj = lh5_file[name]
114
114
  elif isinstance(lh5_file, str):
115
115
  lh5_file = h5py.File(lh5_file, mode="r", locking=locking)
116
- lh5_obj = lh5_file[name]
116
+ try:
117
+ lh5_obj = lh5_file[name]
118
+ except KeyError as ke:
119
+ err = f"Object {name} not found in file {lh5_file.filename}"
120
+ raise KeyError(err) from ke
117
121
  else:
118
122
  if obj_buf is not None:
119
123
  obj_buf.resize(obj_buf_start)
@@ -6,11 +6,11 @@ HDF5 files.
6
6
  from __future__ import annotations
7
7
 
8
8
  import logging
9
- import os
10
9
  import sys
11
10
  from collections import OrderedDict
12
11
  from collections.abc import Mapping, Sequence
13
12
  from inspect import signature
13
+ from pathlib import Path
14
14
  from typing import Any
15
15
 
16
16
  import h5py
@@ -92,16 +92,16 @@ class LH5Store:
92
92
  return self.files[lh5_file]
93
93
 
94
94
  if self.base_path != "":
95
- full_path = os.path.join(self.base_path, lh5_file)
95
+ full_path = Path(self.base_path) / lh5_file
96
96
  else:
97
- full_path = lh5_file
97
+ full_path = Path(lh5_file)
98
98
 
99
- file_exists = os.path.exists(full_path)
99
+ file_exists = full_path.exists()
100
100
  if mode != "r":
101
- directory = os.path.dirname(full_path)
102
- if directory != "" and not os.path.exists(directory):
101
+ directory = full_path.parent
102
+ if directory != "" and not full_path.parent.exists():
103
103
  log.debug(f"making path {directory}")
104
- os.makedirs(directory)
104
+ directory.mkdir(parents=True, exist_ok=True)
105
105
 
106
106
  if mode == "r" and not file_exists:
107
107
  msg = f"file {full_path} not found"
@@ -7,6 +7,7 @@ import logging
7
7
  import os
8
8
  import string
9
9
  from collections.abc import Mapping, Sequence
10
+ from pathlib import Path
10
11
  from typing import Any
11
12
 
12
13
  import h5py
@@ -153,7 +154,7 @@ def expand_vars(expr: str, substitute: dict[str, str] | None = None) -> str:
153
154
 
154
155
  # use provided mapping
155
156
  # then expand env variables
156
- return os.path.expandvars(string.Template(expr).safe_substitute(substitute))
157
+ return os.path.expandvars(string.Template(str(expr)).safe_substitute(substitute))
157
158
 
158
159
 
159
160
  def expand_path(
@@ -183,14 +184,15 @@ def expand_path(
183
184
  Unique absolute path, or list of all absolute paths
184
185
  """
185
186
  if base_path is not None and base_path != "":
186
- base_path = os.path.expanduser(os.path.expandvars(base_path))
187
- path = os.path.join(base_path, path)
187
+ base_path = Path(os.path.expandvars(base_path)).expanduser()
188
+ path = base_path / path
188
189
 
189
190
  # first expand variables
190
191
  _path = expand_vars(path, substitute)
191
192
 
192
193
  # then expand wildcards
193
- paths = sorted(glob.glob(os.path.expanduser(_path)))
194
+ # pathlib glob works differently so use glob for now
195
+ paths = sorted(glob.glob(str(Path(_path).expanduser()))) # noqa: PTH207
194
196
 
195
197
  if base_path is not None and base_path != "":
196
198
  paths = [os.path.relpath(p, base_path) for p in paths]
@@ -130,20 +130,48 @@ class VectorOfVectors(LGDOCollection):
130
130
 
131
131
  # ak.to_buffer helps in de-serialization
132
132
  # NOTE: ak.to_packed() needed?
133
- form, length, container = ak.to_buffers(ak.to_packed(data))
134
-
135
- # NOTE: node#-data is not even in the dict if the awkward array is empty
136
- # NOTE: if the data arg was a numpy array, to_buffers() preserves
137
- # the original dtype
138
- # FIXME: have to copy the buffers, otherwise self will not own the
139
- # data and self.resize() will fail. Is it possible to avoid this?
140
- flattened_data = np.copy(
141
- container.pop(f"node{data.ndim - 1}-data", np.empty(0, dtype=dtype))
142
- )
133
+ form, _, container = ak.to_buffers(ak.to_packed(data))
134
+
135
+ # check if bytestring
136
+ curr = form
137
+ for _ in range(data.ndim - 1):
138
+ curr = curr.content
139
+ if (
140
+ "__array__" in curr.parameters
141
+ and curr.parameters["__array__"] == "bytestring"
142
+ ):
143
+ diffs = np.diff(container[f"node{data.ndim - 1}-offsets"])
144
+ if (diffs != diffs[0]).all():
145
+ err_msg = "Non uniform string lengths not supported"
146
+ raise NotImplementedError(err_msg)
147
+ flattened_data = np.asarray(
148
+ ak.enforce_type(
149
+ ak.unflatten(
150
+ container.pop(
151
+ f"node{data.ndim}-data", np.empty(0, dtype=dtype)
152
+ ),
153
+ diffs[0],
154
+ ),
155
+ "bytes",
156
+ )
157
+ )
143
158
 
144
- # if user-provided dtype is different than dtype from Awkward, cast
145
- # NOTE: makes a copy only if needed
146
- flattened_data = np.asarray(flattened_data, dtype=dtype)
159
+ # if user-provided dtype is different than dtype from Awkward, cast
160
+ # NOTE: makes a copy only if needed
161
+ flattened_data = np.asarray(flattened_data, dtype=dtype)
162
+ else:
163
+ # NOTE: node#-data is not even in the dict if the awkward array is empty
164
+ # NOTE: if the data arg was a numpy array, to_buffers() preserves
165
+ # the original dtype
166
+ # FIXME: have to copy the buffers, otherwise self will not own the
167
+ # data and self.resize() will fail. Is it possible to avoid this?
168
+ flattened_data = np.copy(
169
+ container.pop(f"node{data.ndim - 1}-data", np.empty(0, dtype=dtype))
170
+ )
171
+
172
+ # if user-provided dtype is different than dtype from Awkward, cast
173
+ # NOTE: makes a copy only if needed
174
+ flattened_data = np.asarray(flattened_data, dtype=dtype)
147
175
 
148
176
  # start from innermost VoV and build nested structure
149
177
  for i in range(data.ndim - 2, -1, -1):
@@ -630,11 +658,25 @@ class VectorOfVectors(LGDOCollection):
630
658
  offsets[1:] = self.cumulative_length.nda
631
659
  offsets[0] = 0
632
660
 
633
- content = (
634
- ak.contents.NumpyArray(self.flattened_data.nda)
635
- if self.ndim == 2
636
- else self.flattened_data.view_as(library, with_units=with_units).layout
637
- )
661
+ if self.ndim != 2:
662
+ content = self.flattened_data.view_as(
663
+ library, with_units=with_units
664
+ ).layout
665
+ # need to handle strings separately
666
+ elif np.issubdtype(self.flattened_data.nda.dtype, np.bytes_):
667
+ byte_arrays = []
668
+ for s in self.flattened_data.nda:
669
+ # Convert each string to array of bytes
670
+ byte_array = np.frombuffer(s, dtype=np.uint8)
671
+ byte_arrays.append(byte_array)
672
+ max_len = max(len(b) for b in byte_arrays)
673
+ raw_arrays = ak.contents.NumpyArray(np.concatenate(byte_arrays))
674
+ array_of_chars = ak.contents.RegularArray(
675
+ raw_arrays, max_len, parameters={"__array__": "bytes"}
676
+ )
677
+ content = ak.enforce_type(array_of_chars, "bytes", highlevel=False)
678
+ else:
679
+ content = ak.contents.NumpyArray(self.flattened_data.nda)
638
680
 
639
681
  layout = ak.contents.ListOffsetArray(
640
682
  offsets=ak.index.Index(offsets),
@@ -22,7 +22,7 @@ def read_sigcompress_c_output(filename: str):
22
22
  enc_wf_c = np.empty(0, dtype=np.uint16)
23
23
  nsig_c = None
24
24
  shift = None
25
- with open(filename) as f:
25
+ with Path(filename).open() as f:
26
26
  nsig_c = int(f.readline()) # first number in the file
27
27
  shift = int(f.readline()) # second number in the file
28
28
  for line in f.readlines(): # then the waveform
@@ -35,7 +35,7 @@ def read_sigcompress_c_output_multi(filename: str):
35
35
  enc_wf_c = []
36
36
  nsig_c = np.empty(0, dtype="uint32")
37
37
  shift = np.empty(0, dtype="int32")
38
- with open(filename) as f:
38
+ with Path(filename).open() as f:
39
39
  for line in f:
40
40
  parts = line.split()
41
41
  nsig_c = np.append(nsig_c, np.uint32(parts[0]))
@@ -1,20 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  import shutil
5
4
  import uuid
6
5
  from getpass import getuser
6
+ from pathlib import Path
7
7
  from tempfile import gettempdir
8
8
 
9
9
  import pytest
10
10
  from legendtestdata import LegendTestData
11
11
 
12
- _tmptestdir = os.path.join(gettempdir(), f"lgdo-tests-{getuser()}-{uuid.uuid4()!s}")
12
+ _tmptestdir = Path(gettempdir()) / f"lgdo-tests-{getuser()}-{uuid.uuid4()!s}"
13
13
 
14
14
 
15
15
  @pytest.fixture(scope="session")
16
16
  def tmptestdir():
17
- os.mkdir(_tmptestdir)
17
+ Path(_tmptestdir).mkdir(parents=True, exist_ok=True)
18
18
  return _tmptestdir
19
19
 
20
20
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+ from pathlib import Path
4
5
 
5
6
  import pytest
6
7
 
@@ -36,7 +37,7 @@ def test_expand_path(lgnd_test_data):
36
37
  "lh5/prod-ref-l200/generated/tier/dsp/cal/p03/r001/l200-p03-r001-cal-20230318T012228Z-tier_dsp.lh5"
37
38
  ),
38
39
  ]
39
- base_dir = os.path.dirname(files[0])
40
+ base_dir = Path(files[0]).parent
40
41
 
41
42
  assert utils.expand_path(f"{base_dir}/*20230318T012144Z*") == files[0]
42
43
 
@@ -50,3 +51,10 @@ def test_expand_path(lgnd_test_data):
50
51
 
51
52
  # Check if it finds a list of files correctly
52
53
  assert sorted(utils.expand_path(f"{base_dir}/*.lh5", list=True)) == sorted(files)
54
+
55
+ # check with base_path specified
56
+ base_path = base_dir.parent
57
+ assert (
58
+ utils.expand_path(f"{base_dir.name}/*20230318T012144Z*", base_path=base_path)
59
+ == Path(files[0]).relative_to(base_path).as_posix()
60
+ )
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import logging
4
- import os
4
+ from pathlib import Path
5
5
 
6
6
  import awkward as ak
7
7
  import h5py
@@ -114,8 +114,8 @@ def test_write_object_overwrite_table_no_deletion(caplog, tmptestdir):
114
114
  caplog.set_level(logging.DEBUG)
115
115
  caplog.clear()
116
116
 
117
- if os.path.exists(f"{tmptestdir}/write_object_overwrite_test.lh5"):
118
- os.remove(f"{tmptestdir}/write_object_overwrite_test.lh5")
117
+ if Path(f"{tmptestdir}/write_object_overwrite_test.lh5").exists():
118
+ Path(f"{tmptestdir}/write_object_overwrite_test.lh5").unlink()
119
119
 
120
120
  tb1 = types.Table(col_dict={"dset1": types.Array(np.zeros(10))})
121
121
  tb2 = types.Table(
@@ -145,8 +145,8 @@ def test_write_object_overwrite_table_with_deletion(caplog, tmptestdir):
145
145
  caplog.set_level(logging.DEBUG)
146
146
  caplog.clear()
147
147
 
148
- if os.path.exists(f"{tmptestdir}/write_object_overwrite_test.lh5"):
149
- os.remove(f"{tmptestdir}/write_object_overwrite_test.lh5")
148
+ if Path(f"{tmptestdir}/write_object_overwrite_test.lh5").exists():
149
+ Path(f"{tmptestdir}/write_object_overwrite_test.lh5").unlink()
150
150
 
151
151
  tb1 = types.Table(col_dict={"dset1": types.Array(np.zeros(10))})
152
152
  tb2 = types.Table(
@@ -170,8 +170,8 @@ def test_write_object_overwrite_table_with_deletion(caplog, tmptestdir):
170
170
  assert "dset1" not in list(lh5file["my_group"].keys())
171
171
 
172
172
  # Make sure the same behavior happens when we nest the table in a group
173
- if os.path.exists(f"{tmptestdir}/write_object_overwrite_test.lh5"):
174
- os.remove(f"{tmptestdir}/write_object_overwrite_test.lh5")
173
+ if Path(f"{tmptestdir}/write_object_overwrite_test.lh5").exists():
174
+ Path(f"{tmptestdir}/write_object_overwrite_test.lh5").unlink()
175
175
 
176
176
  tb1 = types.Table(col_dict={"dset1": types.Array(np.zeros(10))})
177
177
  tb2 = types.Table(
@@ -209,8 +209,8 @@ def test_write_object_overwrite_lgdo(caplog, tmptestdir):
209
209
  caplog.clear()
210
210
 
211
211
  # Start with an types.WaveformTable
212
- if os.path.exists(f"{tmptestdir}/write_object_overwrite_test.lh5"):
213
- os.remove(f"{tmptestdir}/write_object_overwrite_test.lh5")
212
+ if Path(f"{tmptestdir}/write_object_overwrite_test.lh5").exists():
213
+ Path(f"{tmptestdir}/write_object_overwrite_test.lh5").unlink()
214
214
 
215
215
  tb1 = types.WaveformTable(
216
216
  t0=np.zeros(10),
@@ -316,8 +316,8 @@ def test_write_object_overwrite_lgdo(caplog, tmptestdir):
316
316
  # Test that when we try to overwrite an existing column in a table we fail
317
317
  def test_write_object_append_column(tmptestdir):
318
318
  # Try to append an array to a table
319
- if os.path.exists(f"{tmptestdir}/write_object_append_column_test.lh5"):
320
- os.remove(f"{tmptestdir}/write_object_append_column_test.lh5")
319
+ if Path(f"{tmptestdir}/write_object_append_column_test.lh5").exists():
320
+ Path(f"{tmptestdir}/write_object_append_column_test.lh5").unlink()
321
321
 
322
322
  array1 = types.Array(np.zeros(10))
323
323
  tb1 = types.Table(col_dict={"dset1`": types.Array(np.ones(10))})
@@ -332,8 +332,8 @@ def test_write_object_append_column(tmptestdir):
332
332
  ) # Now, try to append a column to an array
333
333
 
334
334
  # Try to append a table that has a same key as the old table
335
- if os.path.exists(f"{tmptestdir}/write_object_append_column_test.lh5"):
336
- os.remove(f"{tmptestdir}/write_object_append_column_test.lh5")
335
+ if Path(f"{tmptestdir}/write_object_append_column_test.lh5").exists():
336
+ Path(f"{tmptestdir}/write_object_append_column_test.lh5").unlink()
337
337
 
338
338
  tb1 = types.Table(
339
339
  col_dict={
@@ -355,8 +355,8 @@ def test_write_object_append_column(tmptestdir):
355
355
  ) # Now, try to append a column with a same field
356
356
 
357
357
  # try appending a column that is larger than one that exists
358
- if os.path.exists(f"{tmptestdir}/write_object_append_column_test.lh5"):
359
- os.remove(f"{tmptestdir}/write_object_append_column_test.lh5")
358
+ if Path(f"{tmptestdir}/write_object_append_column_test.lh5").exists():
359
+ Path(f"{tmptestdir}/write_object_append_column_test.lh5").unlink()
360
360
 
361
361
  tb1 = types.Table(col_dict={"dset1": types.Array(np.zeros(10))})
362
362
  tb2 = types.Table(
@@ -373,8 +373,8 @@ def test_write_object_append_column(tmptestdir):
373
373
  ) # Now, try to append a column with a different field size
374
374
 
375
375
  # Finally successfully append a column
376
- if os.path.exists(f"{tmptestdir}/write_object_append_column_test.lh5"):
377
- os.remove(f"{tmptestdir}/write_object_append_column_test.lh5")
376
+ if Path(f"{tmptestdir}/write_object_append_column_test.lh5").exists():
377
+ Path(f"{tmptestdir}/write_object_append_column_test.lh5").unlink()
378
378
 
379
379
  tb1 = types.Table(col_dict={"dset1": types.Array(np.zeros(10))})
380
380
  tb2 = types.Table(
@@ -410,8 +410,8 @@ def test_write_histogram(caplog, tmptestdir):
410
410
  caplog.clear()
411
411
 
412
412
  # Start with an types.Histogram
413
- if os.path.exists(f"{tmptestdir}/write_histogram_test.lh5"):
414
- os.remove(f"{tmptestdir}/write_histogram_test.lh5")
413
+ if Path(f"{tmptestdir}/write_histogram_test.lh5").exists():
414
+ Path(f"{tmptestdir}/write_histogram_test.lh5").unlink()
415
415
 
416
416
  h1 = types.Histogram(
417
417
  np.array([[1, 1], [1, 1]]), (np.array([0, 1, 2]), np.array([2.1, 2.2, 2.3]))
@@ -484,8 +484,8 @@ def test_write_histogram_variable(caplog, tmptestdir):
484
484
  caplog.clear()
485
485
 
486
486
  # Start with an types.Histogram
487
- if os.path.exists(f"{tmptestdir}/write_histogram_test.lh5"):
488
- os.remove(f"{tmptestdir}/write_histogram_test.lh5")
487
+ if Path(f"{tmptestdir}/write_histogram_test.lh5").exists():
488
+ Path(f"{tmptestdir}/write_histogram_test.lh5").unlink()
489
489
 
490
490
  h1 = types.Histogram(
491
491
  np.array([[1, 1], [1, 1]]), (np.array([0, 1.2, 2]), np.array([2.1, 2.5, 2.3]))
@@ -508,3 +508,47 @@ def test_pickle(testvov):
508
508
 
509
509
  for i in range(len(desired)):
510
510
  assert np.array_equal(desired[i], ex[i])
511
+
512
+
513
+ def test_bytestrings():
514
+ for string in [b"a", b"p01", b"V00000A"]:
515
+ # test bytestring
516
+ v = VectorOfVectors(
517
+ flattened_data=np.full(5, string, dtype=f"S{len(string)}"),
518
+ cumulative_length=np.array([2, 5], dtype="uint32"),
519
+ )
520
+ assert v.flattened_data.dtype == f"S{len(string)}"
521
+ assert v.flattened_data.nda[0] == string
522
+
523
+ # test bytestring view_as
524
+ v = VectorOfVectors(
525
+ flattened_data=np.full(5, string, dtype=f"S{len(string)}"),
526
+ cumulative_length=np.array([2, 5], dtype="uint32"),
527
+ )
528
+ ak_arr = v.view_as("ak", with_units=False)
529
+ assert isinstance(ak_arr, ak.Array)
530
+ assert ak_arr[0][0] == string
531
+
532
+ v = VectorOfVectors(
533
+ flattened_data=np.full(5, string, dtype="S7"),
534
+ cumulative_length=np.array([2, 5], dtype="uint32"),
535
+ )
536
+
537
+ # test bytestring with ak Array
538
+ ak_arr = v.view_as("ak", with_units=False)
539
+ v = VectorOfVectors(ak_arr)
540
+ assert v.flattened_data.dtype == "S7"
541
+ assert v.flattened_data.nda[0] == b"V00000A"
542
+
543
+ # test nested bytestring VoVoV
544
+
545
+ v = VectorOfVectors(
546
+ flattened_data=v,
547
+ cumulative_length=np.array([2], dtype="uint32"),
548
+ )
549
+ assert v.flattened_data.flattened_data.dtype == "S7"
550
+ assert v.flattened_data.flattened_data.nda[0] == b"V00000A"
551
+
552
+ ak_arr = v.view_as("ak", with_units=False)
553
+ assert isinstance(ak_arr, ak.Array)
554
+ assert ak_arr[0][0][0] == b"V00000A"