ewoksdata 0.6.0__tar.gz → 1.0.0__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 (41) hide show
  1. ewoksdata-1.0.0/PKG-INFO +67 -0
  2. ewoksdata-1.0.0/pyproject.toml +65 -0
  3. ewoksdata-1.0.0/setup.cfg +4 -0
  4. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/bliss.py +1 -0
  5. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/__init__.py +1 -6
  6. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/config.py +1 -2
  7. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/dataset_writer.py +93 -62
  8. ewoksdata-1.0.0/src/ewoksdata/tests/__init__.py +0 -0
  9. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/conftest.py +1 -0
  10. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/data/bliss_scans.py +26 -2
  11. ewoksdata-1.0.0/src/ewoksdata/tests/test_dataset_writer.py +186 -0
  12. ewoksdata-1.0.0/src/ewoksdata.egg-info/PKG-INFO +67 -0
  13. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/SOURCES.txt +0 -2
  14. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/requires.txt +6 -13
  15. ewoksdata-0.6.0/PKG-INFO +0 -50
  16. ewoksdata-0.6.0/pyproject.toml +0 -5
  17. ewoksdata-0.6.0/setup.cfg +0 -69
  18. ewoksdata-0.6.0/setup.py +0 -4
  19. ewoksdata-0.6.0/src/ewoksdata/__init__.py +0 -1
  20. ewoksdata-0.6.0/src/ewoksdata/tests/test_dataset_writer.py +0 -89
  21. ewoksdata-0.6.0/src/ewoksdata.egg-info/PKG-INFO +0 -50
  22. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/LICENSE.md +0 -0
  23. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/README.md +0 -0
  24. {ewoksdata-0.6.0/src/ewoksdata/data → ewoksdata-1.0.0/src/ewoksdata}/__init__.py +0 -0
  25. {ewoksdata-0.6.0/src/ewoksdata/tests → ewoksdata-1.0.0/src/ewoksdata/data}/__init__.py +0 -0
  26. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav0.py +0 -0
  27. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav1.py +0 -0
  28. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav2.py +0 -0
  29. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/contextiterator.py +0 -0
  30. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/__init__.py +0 -0
  31. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/types.py +0 -0
  32. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/nexus.py +0 -0
  33. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/url.py +0 -0
  34. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/utils.py +0 -0
  35. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/data/__init__.py +0 -0
  36. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_contextiterator.py +0 -0
  37. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_bliss.py +0 -0
  38. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_hdf5.py +0 -0
  39. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_nexus.py +0 -0
  40. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/dependency_links.txt +0 -0
  41. {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/top_level.txt +0 -0
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.2
2
+ Name: ewoksdata
3
+ Version: 1.0.0
4
+ Summary: Ewoks tasks for data access
5
+ Author-email: ESRF <dau-pydev@esrf.fr>
6
+ License: # MIT License
7
+
8
+ **Copyright (c) 2021 European Synchrotron Radiation Facility**
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
11
+ this software and associated documentation files (the "Software"), to deal in
12
+ the Software without restriction, including without limitation the rights to
13
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14
+ the Software, and to permit persons to whom the Software is furnished to do so,
15
+ subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+ Project-URL: Homepage, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
28
+ Project-URL: Documentation, https://ewoksdata.readthedocs.io
29
+ Project-URL: Repository, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
30
+ Project-URL: Issues, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues
31
+ Project-URL: Changelog, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/-/blob/main/CHANGELOG.md
32
+ Classifier: Intended Audience :: Science/Research
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Requires-Python: >=3.8
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE.md
38
+ Requires-Dist: h5py>=2.8
39
+ Requires-Dist: silx>=1.1.0
40
+ Requires-Dist: hdf5plugin
41
+ Requires-Dist: blissdata>=0.3.4
42
+ Requires-Dist: redis
43
+ Requires-Dist: redis!=5.3.0b1,!=5.3.0b3
44
+ Requires-Dist: packaging
45
+ Requires-Dist: beartype!=0.20.0rc0
46
+ Provides-Extra: online
47
+ Requires-Dist: blissdata[tango]; extra == "online"
48
+ Provides-Extra: test
49
+ Requires-Dist: ewoksdata[online]; extra == "test"
50
+ Requires-Dist: pytest>=7; extra == "test"
51
+ Provides-Extra: dev
52
+ Requires-Dist: ewoksdata[test]; extra == "dev"
53
+ Requires-Dist: black>=25; extra == "dev"
54
+ Requires-Dist: flake8>=4; extra == "dev"
55
+ Provides-Extra: doc
56
+ Requires-Dist: ewoksdata[test]; extra == "doc"
57
+ Requires-Dist: sphinx>=4.5; extra == "doc"
58
+ Requires-Dist: sphinx-autodoc-typehints>=1.16; extra == "doc"
59
+ Requires-Dist: pydata-sphinx-theme<0.15; extra == "doc"
60
+
61
+ # ewoksdata
62
+
63
+ Data access utilities for [ewoks](https://ewoks.readthedocs.io/) workflows.
64
+
65
+ ## Documentation
66
+
67
+ https://ewoksdata.readthedocs.io
@@ -0,0 +1,65 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=46.4"
4
+ ]
5
+ build-backend = "setuptools.build_meta"
6
+
7
+ [project]
8
+ name = "ewoksdata"
9
+ version = "1.0.0"
10
+ authors = [{name = "ESRF", email = "dau-pydev@esrf.fr"}]
11
+ description = "Ewoks tasks for data access"
12
+ readme = {file = "README.md", content-type = "text/markdown"}
13
+ license = {file = "LICENSE.md"}
14
+ classifiers = [
15
+ "Intended Audience :: Science/Research",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Programming Language :: Python :: 3",
18
+ ]
19
+ requires-python = ">=3.8"
20
+ dependencies = [
21
+ "h5py >=2.8",
22
+ "silx >=1.1.0",
23
+ "hdf5plugin",
24
+ "blissdata >=0.3.4",
25
+ "redis", # blissdata<1
26
+ "redis !=5.3.0b1,!=5.3.0b3",
27
+ "packaging",
28
+ "beartype !=0.20.0rc0" # https://github.com/beartype/beartype/issues/483
29
+ ]
30
+
31
+ [project.urls]
32
+ Homepage = "https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/"
33
+ Documentation = "https://ewoksdata.readthedocs.io"
34
+ Repository = "https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/"
35
+ Issues = "https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues"
36
+ Changelog = "https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/-/blob/main/CHANGELOG.md"
37
+
38
+ [project.optional-dependencies]
39
+ online = [
40
+ "blissdata[tango]",
41
+ ]
42
+ test = [
43
+ "ewoksdata[online]",
44
+ "pytest >=7",
45
+ ]
46
+ dev = [
47
+ "ewoksdata[test]",
48
+ "black >=25",
49
+ "flake8 >=4",
50
+ ]
51
+ doc = [
52
+ "ewoksdata[test]",
53
+ "sphinx >=4.5",
54
+ "sphinx-autodoc-typehints >=1.16",
55
+ "pydata-sphinx-theme < 0.15",
56
+ ]
57
+
58
+ [tool.setuptools]
59
+ package-dir = { "" = "src" }
60
+
61
+ [tool.setuptools.packages.find]
62
+ where = ["src"]
63
+
64
+ [tool.coverage.run]
65
+ omit = ['*/tests/*']
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -12,6 +12,7 @@ from silx.utils import retry as retrymod
12
12
  from silx.io.utils import get_data as silx_get_data
13
13
 
14
14
  from .blissdata import iter_bliss_scan_data_from_memory # noqa F401
15
+ from .blissdata import iter_bliss_scan_data_from_memory_slice # noqa F401
15
16
  from .blissdata import last_lima_image # noqa F401
16
17
  from .blissdata import dynamic_hdf5
17
18
 
@@ -1,9 +1,4 @@
1
- import sys
2
-
3
- if sys.version_info >= (3, 8):
4
- from importlib.metadata import version
5
- else:
6
- from importlib_metadata import version
1
+ from importlib.metadata import version
7
2
  from packaging.specifiers import SpecifierSet
8
3
 
9
4
 
@@ -1,5 +1,4 @@
1
- """HDF5 configuration of optimal data storage (IO speed, compression, ...)
2
- """
1
+ """HDF5 configuration of optimal data storage (IO speed, compression, ...)"""
3
2
 
4
3
  from typing import Optional
5
4
  from numbers import Integral
@@ -17,6 +17,7 @@ class _DatasetWriterBase:
17
17
  attrs: Optional[dict] = None,
18
18
  flush_period: Optional[float] = None,
19
19
  ) -> None:
20
+ self._file = parent.file
20
21
  self._parent = parent
21
22
  self._name = name
22
23
  self._attrs = attrs
@@ -53,6 +54,10 @@ class _DatasetWriterBase:
53
54
  return False
54
55
  return (time.time() - self._last_flush) >= self._flush_period
55
56
 
57
+ def _flush_hdf5(self) -> None:
58
+ """Explicit HDF5 flush for non-locking readers."""
59
+ self._file.flush()
60
+
56
61
 
57
62
  class DatasetWriter(_DatasetWriterBase):
58
63
  """Append arrays of the same shape to a new HDF5 dataset in a sequential manner.
@@ -84,11 +89,12 @@ class DatasetWriter(_DatasetWriterBase):
84
89
  ) -> None:
85
90
  super().__init__(parent, name, attrs=attrs, flush_period=flush_period)
86
91
  self._npoints = npoints
87
- self._buffer: List[ArrayLike] = list()
88
- self._npoints_added: int = 0
89
92
  self._chunked: bool = False
90
- self._nchunk: int = 0
91
- self._nflushed: int = 0
93
+ self._npoints_added: int = 0
94
+
95
+ self._buffer: List[ArrayLike] = list()
96
+ self._chunk_size: int = 0
97
+ self._flushed_size: int = 0
92
98
 
93
99
  def _create_dataset(self, first_data_point: numpy.ndarray) -> h5py.Dataset:
94
100
  scan_shape = (self._npoints,)
@@ -111,7 +117,7 @@ class DatasetWriter(_DatasetWriterBase):
111
117
  options["maxshape"] = max_shape
112
118
  if options["chunks"]:
113
119
  self._chunked = True
114
- self._nchunk = options["chunks"][0]
120
+ self._chunk_size = options["chunks"][0]
115
121
  dset = self._parent.create_dataset(self._name, **options)
116
122
  if self._attrs:
117
123
  dset.attrs.update(self._attrs)
@@ -139,30 +145,35 @@ class DatasetWriter(_DatasetWriterBase):
139
145
 
140
146
  def flush_buffer(self, align: bool = False) -> bool:
141
147
  # Determine how many points to flush
142
- nbuffer = len(self._buffer)
148
+ chunk_size = len(self._buffer)
149
+
143
150
  if self._flush_time_expired():
144
- nflush = nbuffer
151
+ flush_size = chunk_size
145
152
  elif align and self._chunked:
146
- n = nbuffer + (self._nflushed % self._nchunk)
147
- nflush = n // self._nchunk * self._nchunk
148
- nflush = min(nflush, nbuffer)
153
+ n = chunk_size + (self._flushed_size % self._chunk_size)
154
+ flush_size = n // self._chunk_size * self._chunk_size
155
+ flush_size = min(flush_size, chunk_size)
149
156
  else:
150
- nflush = nbuffer
151
- if nflush == 0:
157
+ flush_size = chunk_size
158
+
159
+ if flush_size == 0:
152
160
  return False
153
161
 
154
162
  # Enlarge the dataset when needed
155
163
  nalloc = self._dataset.shape[0]
156
- istart = self._nflushed
157
- nflushed = istart + nflush
158
- if self._chunked and nflushed > nalloc:
159
- self._dataset.resize(nflushed, axis=0)
164
+ istart = self._flushed_size
165
+ flushed_size = istart + flush_size
166
+ if self._chunked and flushed_size > nalloc:
167
+ self._dataset.resize(flushed_size, axis=0)
168
+
169
+ # Copy data from buffer to HDF5
170
+ self._dataset[istart : istart + flush_size] = self._buffer[:flush_size]
160
171
 
161
- # Move data from memory to HDF5
162
- self._dataset[istart : istart + nflush] = self._buffer[:nflush]
163
- self._buffer = self._buffer[nflush:]
164
- self._nflushed = nflushed
172
+ # Remove copied data from buffer
173
+ self._buffer = self._buffer[flush_size:]
174
+ self._flushed_size = flushed_size
165
175
 
176
+ self._flush_hdf5()
166
177
  self._last_flush = time.time()
167
178
  return True
168
179
 
@@ -204,11 +215,12 @@ class StackDatasetWriter(_DatasetWriterBase):
204
215
  ) -> None:
205
216
  super().__init__(parent, name, attrs=attrs, flush_period=flush_period)
206
217
  self._npoints = npoints
218
+ self._chunked: bool = False
207
219
  self._nstack = nstack
220
+
208
221
  self._buffers: List[List[ArrayLike]] = list()
209
- self._chunked: bool = False
210
- self._nchunk: ArrayLike = numpy.zeros(2, dtype=int)
211
- self._nflushed: ArrayLike = numpy.array(list(), dtype=int)
222
+ self._chunk_size: ArrayLike = numpy.zeros(2, dtype=int)
223
+ self._flushed_size_dim1: ArrayLike = numpy.array(list(), dtype=int)
212
224
 
213
225
  def _create_dataset(
214
226
  self, first_data_point: numpy.ndarray, stack_index: int
@@ -233,7 +245,7 @@ class StackDatasetWriter(_DatasetWriterBase):
233
245
  options["maxshape"] = max_shape
234
246
  if options["chunks"]:
235
247
  self._chunked = True
236
- self._nchunk = numpy.array(options["chunks"][:2], dtype=int)
248
+ self._chunk_size = numpy.array(options["chunks"][:2], dtype=int)
237
249
  dset = self._parent.create_dataset(self._name, **options)
238
250
  if self._attrs:
239
251
  dset.attrs.update(self._attrs)
@@ -243,7 +255,7 @@ class StackDatasetWriter(_DatasetWriterBase):
243
255
  # Add stack buffers when needed
244
256
  for _ in range(max(stack_index - len(self._buffers) + 1, 0)):
245
257
  self._buffers.append(list())
246
- self._nflushed = numpy.append(self._nflushed, 0)
258
+ self._flushed_size_dim1 = numpy.append(self._flushed_size_dim1, 0)
247
259
  return self._buffers[stack_index]
248
260
 
249
261
  def add_point(self, data: ArrayLike, stack_index: int) -> bool:
@@ -264,60 +276,79 @@ class StackDatasetWriter(_DatasetWriterBase):
264
276
 
265
277
  def flush_buffer(self, align: bool = False) -> bool:
266
278
  # Determine how many points to flush for each buffer in the stack
267
- nbuffer = numpy.array([len(buffer) for buffer in self._buffers])
268
- nchunk_dim0, nchunk_dim1 = self._nchunk[:2]
279
+ chunk_sizes = numpy.array([len(buffer) for buffer in self._buffers])
280
+ flushed_size_dim1 = self._flushed_size_dim1
281
+ size_dim0 = len(chunk_sizes)
282
+ assert size_dim0 == len(
283
+ flushed_size_dim1
284
+ ), "Number of buffers and number of flushed dim1 points must be the same"
285
+
286
+ chunk_size_dim0, chunk_size_dim1 = self._chunk_size[:2]
287
+ if chunk_size_dim0 == 0:
288
+ chunk_size_dim0 = size_dim0
289
+
269
290
  if self._flush_time_expired():
270
- nflush = nbuffer
291
+ flush_sizes = chunk_sizes
271
292
  elif align and self._chunked:
272
- n = nbuffer + (self._nflushed % nchunk_dim1)
273
- nflush = n // nchunk_dim1 * nchunk_dim1
274
- nflush = numpy.minimum(nflush, nbuffer)
275
- for i0_chunk0 in range(0, len(nbuffer), nchunk_dim0):
276
- nflush[i0_chunk0 : i0_chunk0 + nchunk_dim0] = min(
277
- nflush[i0_chunk0 : i0_chunk0 + nchunk_dim0]
278
- )
293
+ size_dim0 = size_dim0 // chunk_size_dim0 * chunk_size_dim0
294
+ chunk_sizes = chunk_sizes[:size_dim0]
295
+ flushed_size_dim1 = flushed_size_dim1[:size_dim0]
296
+ if size_dim0:
297
+ n1 = chunk_sizes + (flushed_size_dim1 % chunk_size_dim1)
298
+ flush_sizes = n1 // chunk_size_dim1 * chunk_size_dim1
299
+ flush_sizes = numpy.minimum(flush_sizes, chunk_sizes)
300
+ for i0_chunk0 in range(0, size_dim0, chunk_size_dim0):
301
+ flush_sizes[i0_chunk0 : i0_chunk0 + chunk_size_dim0] = min(
302
+ flush_sizes[i0_chunk0 : i0_chunk0 + chunk_size_dim0]
303
+ )
304
+ else:
305
+ flush_sizes = list()
279
306
  else:
280
- nflush = nbuffer
281
- if not any(nflush):
307
+ flush_sizes = chunk_sizes
308
+
309
+ if not any(flush_sizes):
282
310
  return False
283
311
 
284
312
  # Enlarge the dataset when needed
285
313
  nalloc = self._dataset.shape[:2]
286
- istart = self._nflushed
287
- nflushed = istart + nflush
288
- nalloc_new = numpy.array([len(nbuffer), max(nflushed)])
314
+ istart_dim1 = flushed_size_dim1
315
+ flushed_size_dim1 = istart_dim1 + flush_sizes
316
+ nalloc_new = numpy.array([size_dim0, max(flushed_size_dim1)])
289
317
  if self._chunked and any(nalloc_new > nalloc):
290
318
  for axis, n in enumerate(nalloc_new):
291
319
  self._dataset.resize(n, axis=axis)
292
320
 
293
- # Move data from memory to HDF5
294
- if nchunk_dim0 == 0:
295
- nchunk_dim0 = len(nbuffer)
296
- for i0_chunk0 in range(0, len(nbuffer), nchunk_dim0):
297
- idx_dim0 = slice(i0_chunk0, i0_chunk0 + nchunk_dim0)
298
- nflush_dim1 = nflush[idx_dim0]
299
- istart0_dim1 = istart[idx_dim0]
321
+ # Copy data from buffer to HDF5
322
+ for i0_chunk0 in range(0, size_dim0, chunk_size_dim0):
323
+ idx_dim0 = slice(i0_chunk0, i0_chunk0 + chunk_size_dim0)
300
324
  buffers = self._buffers[idx_dim0]
301
- if all(nflush_dim1 == nflush_dim1[0]) and all(
302
- istart0_dim1 == istart0_dim1[0]
303
- ):
304
- data = [buffer[: nflush_dim1[0]] for buffer in buffers]
305
- idx_dim1 = slice(istart0_dim1[0], istart0_dim1[0] + nflush_dim1[0])
325
+
326
+ flush_sizes_dim1 = flush_sizes[idx_dim0]
327
+ non_ragged_buffers = len(set(flush_sizes_dim1)) == 1
328
+
329
+ istart0_dim1 = istart_dim1[idx_dim0]
330
+ non_ragged_destination = len(set(istart0_dim1)) == 1
331
+
332
+ if non_ragged_destination and non_ragged_buffers:
333
+ data = [buffer[: flush_sizes_dim1[0]] for buffer in buffers]
334
+ idx_dim1 = slice(istart0_dim1[0], istart0_dim1[0] + flush_sizes_dim1[0])
306
335
  self._dataset[idx_dim0, idx_dim1] = data
307
336
  else:
308
- for buffer, i_dim0, istart_dim1, n_dim1 in zip(
337
+ for buffer, i_dim0, istart_dim1, i_flush_size_dim1 in zip(
309
338
  buffers,
310
- range(i0_chunk0, i0_chunk0 + nchunk_dim0),
339
+ range(i0_chunk0, i0_chunk0 + chunk_size_dim0),
311
340
  istart0_dim1,
312
- nflush_dim1,
341
+ flush_sizes_dim1,
313
342
  ):
314
- self._dataset[i_dim0, istart_dim1 : istart_dim1 + n_dim1, ...] = (
315
- buffer[:n_dim1]
316
- )
317
- self._buffers = [
318
- buffer[n_dim1:] for buffer, n_dim1 in zip(self._buffers, nflush)
319
- ]
320
- self._nflushed = nflushed
343
+ self._dataset[
344
+ i_dim0, istart_dim1 : istart_dim1 + i_flush_size_dim1, ...
345
+ ] = buffer[:i_flush_size_dim1]
346
+
347
+ # Remove copied data from buffer
348
+ for i0 in range(size_dim0):
349
+ self._buffers[i0] = self._buffers[i0][flush_sizes[i0] :]
350
+ self._flushed_size_dim1[i0] = flushed_size_dim1[i0]
321
351
 
352
+ self._flush_hdf5()
322
353
  self._last_flush = time.time()
323
354
  return True
File without changes
@@ -1,5 +1,6 @@
1
1
  import numpy
2
2
  import pytest
3
+
3
4
  from . import data
4
5
 
5
6
 
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from datetime import datetime
3
3
  from pathlib import Path
4
- from typing import Tuple
4
+ from typing import Optional, Tuple
5
5
  import numpy
6
6
  import h5py
7
7
 
@@ -19,6 +19,8 @@ def save_bliss_scan(
19
19
  sequence: str = "add",
20
20
  lima_names: Tuple[str, ...] = ("p3",),
21
21
  counter_names: Tuple[str, ...] = ("diode1", "diode2"),
22
+ positioner_names: Tuple[str, ...] = ("diffty", "diffrz"),
23
+ title: Optional[str] = None,
22
24
  ) -> Path:
23
25
  dataset_filename = tmpdir / "sample_dataset.h5"
24
26
  lima_dirname = tmpdir / f"scan{scannr:04d}"
@@ -28,12 +30,18 @@ def save_bliss_scan(
28
30
  root.attrs["creator"] = "bliss"
29
31
  scan = root.create_group(f"{scannr}.{subscannr}")
30
32
  scan.attrs["NX_class"] = "NXentry"
33
+ if title is not None:
34
+ scan["title"] = title
31
35
 
32
36
  instrument = scan.create_group("instrument")
33
37
  instrument.attrs["NX_class"] = "NXinstrument"
34
38
  measurement = scan.create_group("measurement")
35
39
  measurement.attrs["NX_class"] = "NXcollection"
36
40
 
41
+ if positioner_names:
42
+ positioners = instrument.create_group("positioners")
43
+ positioners.attrs["NX_class"] = "NXcollection"
44
+
37
45
  for name in counter_names:
38
46
  _save_counter(scan, name, npoints)
39
47
  for name in lima_names:
@@ -47,6 +55,8 @@ def save_bliss_scan(
47
55
  scannr,
48
56
  sequence,
49
57
  )
58
+ for name in positioner_names:
59
+ _save_positioner(scan, name, npoints)
50
60
 
51
61
  scan["end_time"] = datetime.now().astimezone().isoformat()
52
62
  return dataset_filename
@@ -100,7 +110,7 @@ def _save_lima(
100
110
  sshape = (i1 - i0,) + lima_shape[1:]
101
111
  vsource = h5py.VirtualSource(spath, sdset, shape=sshape, dtype=lima_dtype)
102
112
 
103
- layout[i0:i1] = vsource
113
+ layout[i0:i1] = vsource[:]
104
114
  detector = _add_detector(scan, name)
105
115
  detector.create_virtual_dataset("data", layout, fillvalue=numpy.nan)
106
116
 
@@ -110,3 +120,17 @@ def _add_detector(scan: h5py.Group, name: str) -> h5py.Group:
110
120
  grp.attrs["NX_class"] = "NXdetector"
111
121
  scan["measurement"][name] = h5py.SoftLink(f"{grp.name}/data")
112
122
  return grp
123
+
124
+
125
+ def _save_positioner(scan: h5py.Group, name: str, npoints: int) -> None:
126
+ positioner = _add_positioner(scan, name)
127
+ positioner["value"] = numpy.arange(npoints)
128
+
129
+
130
+ def _add_positioner(scan: h5py.Group, name: str) -> h5py.Group:
131
+ instrument = scan["instrument"]
132
+ grp = instrument.create_group(name)
133
+ grp.attrs["NX_class"] = "Nxpositioner"
134
+ scan["measurement"][name] = h5py.SoftLink(f"{grp.name}/value")
135
+ instrument["positioners"][name] = h5py.SoftLink(f"{grp.name}/value")
136
+ return grp
@@ -0,0 +1,186 @@
1
+ import time
2
+ import itertools
3
+ import multiprocessing
4
+
5
+ import h5py
6
+ import numpy
7
+ import pytest
8
+ from silx.io import h5py_utils
9
+
10
+
11
+ from ..data.hdf5 import dataset_writer
12
+
13
+
14
+ @pytest.mark.parametrize("npoints", (1, 3, 1000))
15
+ @pytest.mark.parametrize("flush_period", (None, 0.1))
16
+ @pytest.mark.parametrize("known_npoints", (True, False))
17
+ def test_dataset_writer(tmpdir, npoints, flush_period, known_npoints):
18
+ expected = list()
19
+ filename = str(tmpdir / "test.h5")
20
+ if flush_period is None:
21
+ sleep_time = None
22
+ else:
23
+ sleep_time = flush_period + 0.1
24
+ isleep = npoints // 3
25
+
26
+ kwargs = {"flush_period": flush_period}
27
+ if known_npoints:
28
+ kwargs["npoints"] = npoints
29
+
30
+ with h5py.File(filename, mode="w") as f:
31
+ with dataset_writer.DatasetWriter(f, "data", **kwargs) as writer:
32
+ for ipoint in range(npoints):
33
+ data = numpy.random.random((10, 20))
34
+ writer.add_point(data)
35
+ expected.append(data)
36
+ if sleep_time and ipoint == isleep:
37
+ time.sleep(sleep_time)
38
+
39
+ with h5py.File(filename, mode="r") as f:
40
+ data = f["data"][()]
41
+ numpy.testing.assert_allclose(data, expected)
42
+
43
+
44
+ @pytest.mark.parametrize("nstack", (1, 4))
45
+ @pytest.mark.parametrize("npoints", (1, 3, 1000))
46
+ @pytest.mark.parametrize("flush_period", (None, 0.1))
47
+ @pytest.mark.parametrize("known_npoints", (True, False))
48
+ @pytest.mark.parametrize("known_nstack", (True, False))
49
+ @pytest.mark.parametrize("append_stacks_in_parallel", (True, False))
50
+ def test_stack_dataset_writer(
51
+ tmpdir,
52
+ nstack,
53
+ npoints,
54
+ flush_period,
55
+ known_npoints,
56
+ known_nstack,
57
+ append_stacks_in_parallel,
58
+ ):
59
+ expected = [list() for _ in range(nstack)]
60
+ filename = str(tmpdir / "test.h5")
61
+ if flush_period is None:
62
+ sleep_time = None
63
+ else:
64
+ sleep_time = flush_period + 0.1
65
+ isleep = (nstack * npoints) // 3
66
+
67
+ kwargs = {"flush_period": flush_period}
68
+ if known_npoints:
69
+ kwargs["npoints"] = npoints
70
+ if known_nstack:
71
+ kwargs["nstack"] = nstack
72
+
73
+ if append_stacks_in_parallel:
74
+ itpoints = itertools.product(range(npoints), range(nstack))
75
+ else:
76
+ itpoints = itertools.product(range(nstack), range(npoints))
77
+
78
+ with h5py.File(filename, mode="w") as f:
79
+ with dataset_writer.StackDatasetWriter(f, "data", **kwargs) as writer:
80
+ for tpl in itpoints:
81
+ if append_stacks_in_parallel:
82
+ ipoint, istack = tpl
83
+ else:
84
+ istack, ipoint = tpl
85
+ data = numpy.random.random((10, 20))
86
+ writer.add_point(data, istack)
87
+ expected[istack].append(data)
88
+ if sleep_time and (ipoint * nstack + istack) == isleep:
89
+ time.sleep(sleep_time)
90
+
91
+ with h5py.File(filename, mode="r") as f:
92
+ data = f["data"][()]
93
+ numpy.testing.assert_allclose(data, expected)
94
+
95
+
96
+ def test_concurrent_reader(tmpdir):
97
+ npoints = 50
98
+ hdf5_filename = str(tmpdir / "test.h5")
99
+ read_timestamps = str(tmpdir / "read_timestamps.log")
100
+ write_timestamps = str(tmpdir / "write_timestamps.log")
101
+ dataset_name = "data"
102
+
103
+ # Run read loop in a sub-process
104
+ start_event = multiprocessing.Event()
105
+ reader_process = multiprocessing.Process(
106
+ target=_read_hdf5_file,
107
+ args=(hdf5_filename, dataset_name, npoints, read_timestamps, start_event),
108
+ )
109
+ reader_process.start()
110
+
111
+ assert start_event.wait(timeout=10)
112
+
113
+ # Run write loop
114
+ try:
115
+ _write_hdf5_file(hdf5_filename, dataset_name, npoints, write_timestamps)
116
+ except Exception:
117
+ reader_process.terminate()
118
+ raise
119
+
120
+ # Wait for read loop to finish
121
+ try:
122
+ reader_process.join(timeout=10)
123
+ if reader_process.exitcode is None:
124
+ raise TimeoutError("Reader process did not terminate within the timeout.")
125
+ elif reader_process.exitcode != 0:
126
+ raise RuntimeError(
127
+ f"Reader process terminated with exit code {reader_process.exitcode}."
128
+ )
129
+ except Exception:
130
+ reader_process.terminate()
131
+ raise
132
+
133
+ # Check that reading and writing happened concurrently
134
+ with open(read_timestamps, "r") as eventfile:
135
+ read_events = [int(line.strip()) for line in eventfile.readlines()]
136
+ with open(write_timestamps, "r") as eventfile:
137
+ write_events = [int(line.strip()) for line in eventfile.readlines()]
138
+
139
+ assert len(read_events) == npoints
140
+ assert len(write_events) == npoints
141
+
142
+ all_events = sorted(read_events + write_events)
143
+ assert (
144
+ read_events != all_events[: len(read_events)]
145
+ ), "reads and writes are not interleaved"
146
+
147
+
148
+ class _DatasetWriter(dataset_writer.DatasetWriter):
149
+ """Testing concurrent reading and writing always ends up
150
+ being flaky. So we introduce a sleep after flushing
151
+ to give the reader plenty of time to fetch new data.
152
+ """
153
+
154
+ def _flush_hdf5(self) -> None:
155
+ print("flush")
156
+ super()._flush_hdf5()
157
+ time.sleep(0.2)
158
+
159
+
160
+ def _write_hdf5_file(hdf5_filename, dataset_name, npoints, event_filename):
161
+ data = numpy.zeros((500, 500), dtype=numpy.int64)
162
+ with open(event_filename, "a") as eventfile:
163
+ with h5py.File(hdf5_filename, mode="w") as h5file:
164
+ with _DatasetWriter(h5file, dataset_name) as writer:
165
+ for i in range(npoints):
166
+ writer.add_point(data)
167
+ eventfile.write(f"{time.perf_counter_ns()}\n")
168
+ print(f"write {i}")
169
+
170
+
171
+ def _read_hdf5_file(hdf5_filename, dataset_name, npoints, event_filename, start_event):
172
+ i = 0
173
+ with open(event_filename, "a") as eventfile:
174
+ start_event.set()
175
+ while i < npoints:
176
+ for _ in _iter_data(hdf5_filename, dataset_name):
177
+ eventfile.write(f"{time.perf_counter_ns()}\n")
178
+ print(f"read {i}")
179
+ i += 1
180
+
181
+
182
+ @h5py_utils.retry()
183
+ def _iter_data(hdf5_filename, dataset_name, start_index=0):
184
+ with h5py_utils.File(hdf5_filename) as h5file:
185
+ for _ in h5file[dataset_name][start_index:], start_index:
186
+ yield None
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.2
2
+ Name: ewoksdata
3
+ Version: 1.0.0
4
+ Summary: Ewoks tasks for data access
5
+ Author-email: ESRF <dau-pydev@esrf.fr>
6
+ License: # MIT License
7
+
8
+ **Copyright (c) 2021 European Synchrotron Radiation Facility**
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
11
+ this software and associated documentation files (the "Software"), to deal in
12
+ the Software without restriction, including without limitation the rights to
13
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14
+ the Software, and to permit persons to whom the Software is furnished to do so,
15
+ subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
23
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
24
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
27
+ Project-URL: Homepage, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
28
+ Project-URL: Documentation, https://ewoksdata.readthedocs.io
29
+ Project-URL: Repository, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
30
+ Project-URL: Issues, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues
31
+ Project-URL: Changelog, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/-/blob/main/CHANGELOG.md
32
+ Classifier: Intended Audience :: Science/Research
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Programming Language :: Python :: 3
35
+ Requires-Python: >=3.8
36
+ Description-Content-Type: text/markdown
37
+ License-File: LICENSE.md
38
+ Requires-Dist: h5py>=2.8
39
+ Requires-Dist: silx>=1.1.0
40
+ Requires-Dist: hdf5plugin
41
+ Requires-Dist: blissdata>=0.3.4
42
+ Requires-Dist: redis
43
+ Requires-Dist: redis!=5.3.0b1,!=5.3.0b3
44
+ Requires-Dist: packaging
45
+ Requires-Dist: beartype!=0.20.0rc0
46
+ Provides-Extra: online
47
+ Requires-Dist: blissdata[tango]; extra == "online"
48
+ Provides-Extra: test
49
+ Requires-Dist: ewoksdata[online]; extra == "test"
50
+ Requires-Dist: pytest>=7; extra == "test"
51
+ Provides-Extra: dev
52
+ Requires-Dist: ewoksdata[test]; extra == "dev"
53
+ Requires-Dist: black>=25; extra == "dev"
54
+ Requires-Dist: flake8>=4; extra == "dev"
55
+ Provides-Extra: doc
56
+ Requires-Dist: ewoksdata[test]; extra == "doc"
57
+ Requires-Dist: sphinx>=4.5; extra == "doc"
58
+ Requires-Dist: sphinx-autodoc-typehints>=1.16; extra == "doc"
59
+ Requires-Dist: pydata-sphinx-theme<0.15; extra == "doc"
60
+
61
+ # ewoksdata
62
+
63
+ Data access utilities for [ewoks](https://ewoks.readthedocs.io/) workflows.
64
+
65
+ ## Documentation
66
+
67
+ https://ewoksdata.readthedocs.io
@@ -1,8 +1,6 @@
1
1
  LICENSE.md
2
2
  README.md
3
3
  pyproject.toml
4
- setup.cfg
5
- setup.py
6
4
  src/ewoksdata/__init__.py
7
5
  src/ewoksdata.egg-info/PKG-INFO
8
6
  src/ewoksdata.egg-info/SOURCES.txt
@@ -3,24 +3,17 @@ silx>=1.1.0
3
3
  hdf5plugin
4
4
  blissdata>=0.3.4
5
5
  redis
6
+ redis!=5.3.0b1,!=5.3.0b3
6
7
  packaging
7
-
8
- [:python_version < "3.8"]
9
- blissdata<1.0.1
10
- importlib_metadata
11
-
12
- [:python_version >= "3.8"]
13
- blissdata
8
+ beartype!=0.20.0rc0
14
9
 
15
10
  [dev]
16
- blissdata[tango]
17
- pytest>=7
18
- black>=22
11
+ ewoksdata[test]
12
+ black>=25
19
13
  flake8>=4
20
14
 
21
15
  [doc]
22
- blissdata[tango]
23
- pytest>=7
16
+ ewoksdata[test]
24
17
  sphinx>=4.5
25
18
  sphinx-autodoc-typehints>=1.16
26
19
  pydata-sphinx-theme<0.15
@@ -29,5 +22,5 @@ pydata-sphinx-theme<0.15
29
22
  blissdata[tango]
30
23
 
31
24
  [test]
32
- blissdata[tango]
25
+ ewoksdata[online]
33
26
  pytest>=7
ewoksdata-0.6.0/PKG-INFO DELETED
@@ -1,50 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: ewoksdata
3
- Version: 0.6.0
4
- Summary: Ewoks tasks for data access
5
- Home-page: https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
6
- Author: ESRF
7
- Author-email: wout.de_nolf@esrf.fr
8
- License: MIT
9
- Project-URL: Source, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
10
- Project-URL: Documentation, https://ewoksdata.readthedocs.io
11
- Project-URL: Tracker, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues/
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Requires-Python: >=3.7
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE.md
18
- Requires-Dist: h5py>=2.8
19
- Requires-Dist: silx>=1.1.0
20
- Requires-Dist: hdf5plugin
21
- Requires-Dist: blissdata>=0.3.4
22
- Requires-Dist: blissdata<1.0.1; python_version < "3.8"
23
- Requires-Dist: blissdata; python_version >= "3.8"
24
- Requires-Dist: redis
25
- Requires-Dist: packaging
26
- Requires-Dist: importlib_metadata; python_version < "3.8"
27
- Provides-Extra: online
28
- Requires-Dist: blissdata[tango]; extra == "online"
29
- Provides-Extra: test
30
- Requires-Dist: blissdata[tango]; extra == "test"
31
- Requires-Dist: pytest>=7; extra == "test"
32
- Provides-Extra: dev
33
- Requires-Dist: blissdata[tango]; extra == "dev"
34
- Requires-Dist: pytest>=7; extra == "dev"
35
- Requires-Dist: black>=22; extra == "dev"
36
- Requires-Dist: flake8>=4; extra == "dev"
37
- Provides-Extra: doc
38
- Requires-Dist: blissdata[tango]; extra == "doc"
39
- Requires-Dist: pytest>=7; extra == "doc"
40
- Requires-Dist: sphinx>=4.5; extra == "doc"
41
- Requires-Dist: sphinx-autodoc-typehints>=1.16; extra == "doc"
42
- Requires-Dist: pydata-sphinx-theme<0.15; extra == "doc"
43
-
44
- # ewoksdata
45
-
46
- Data access utilities for [ewoks](https://ewoks.readthedocs.io/) workflows.
47
-
48
- ## Documentation
49
-
50
- https://ewoksdata.readthedocs.io
@@ -1,5 +0,0 @@
1
- [build-system]
2
- requires = [
3
- "setuptools>=46.4"
4
- ]
5
- build-backend = "setuptools.build_meta"
ewoksdata-0.6.0/setup.cfg DELETED
@@ -1,69 +0,0 @@
1
- [metadata]
2
- name = ewoksdata
3
- version = attr: ewoksdata.__version__
4
- author = ESRF
5
- author_email = wout.de_nolf@esrf.fr
6
- description = Ewoks tasks for data access
7
- long_description = file: README.md
8
- long_description_content_type = text/markdown
9
- license = MIT
10
- url = https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
11
- project_urls =
12
- Source = https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
13
- Documentation = https://ewoksdata.readthedocs.io
14
- Tracker = https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues/
15
- classifiers =
16
- Intended Audience :: Science/Research
17
- License :: OSI Approved :: MIT License
18
- Programming Language :: Python :: 3
19
-
20
- [options]
21
- package_dir =
22
- =src
23
- packages = find:
24
- python_requires = >=3.7
25
- install_requires =
26
- h5py >=2.8
27
- silx >=1.1.0
28
- hdf5plugin
29
- blissdata >=0.3.4
30
- blissdata <1.0.1; python_version < "3.8"
31
- blissdata; python_version >= "3.8"
32
- redis # blissdata<1
33
- packaging
34
- importlib_metadata; python_version < "3.8"
35
-
36
- [options.packages.find]
37
- where = src
38
-
39
- [options.extras_require]
40
- online =
41
- blissdata[tango]
42
- test =
43
- %(online)s
44
- pytest >=7
45
- dev =
46
- %(test)s
47
- black >=22
48
- flake8 >=4
49
- doc =
50
- %(test)s
51
- sphinx >=4.5
52
- sphinx-autodoc-typehints >=1.16
53
- pydata-sphinx-theme < 0.15
54
-
55
- [flake8]
56
- ignore = E501, E203, W503
57
- max-line-length = 88
58
- exclude =
59
- .eggs
60
-
61
- [coverage:run]
62
- omit =
63
- setup.py
64
- */tests/*
65
-
66
- [egg_info]
67
- tag_build =
68
- tag_date = 0
69
-
ewoksdata-0.6.0/setup.py DELETED
@@ -1,4 +0,0 @@
1
- import setuptools
2
-
3
- if __name__ == "__main__":
4
- setuptools.setup()
@@ -1 +0,0 @@
1
- __version__ = "0.6.0"
@@ -1,89 +0,0 @@
1
- import time
2
- import itertools
3
-
4
- import h5py
5
- import numpy
6
- import pytest
7
- from ..data.hdf5 import dataset_writer
8
-
9
-
10
- @pytest.mark.parametrize("npoints", (1, 3, 1000))
11
- @pytest.mark.parametrize("flush_period", (None, 0.1))
12
- @pytest.mark.parametrize("known_npoints", (True, False))
13
- def test_dataset_writer(tmpdir, npoints, flush_period, known_npoints):
14
- expected = list()
15
- filename = str(tmpdir / "test.h5")
16
- if flush_period is None:
17
- sleep_time = None
18
- else:
19
- sleep_time = flush_period + 0.1
20
- isleep = npoints // 3
21
-
22
- kwargs = {"flush_period": flush_period}
23
- if known_npoints:
24
- kwargs["npoints"] = npoints
25
-
26
- with h5py.File(filename, mode="w") as f:
27
- with dataset_writer.DatasetWriter(f, "data", **kwargs) as writer:
28
- for ipoint in range(npoints):
29
- data = numpy.random.random((10, 20))
30
- writer.add_point(data)
31
- expected.append(data)
32
- if sleep_time and ipoint == isleep:
33
- time.sleep(sleep_time)
34
-
35
- with h5py.File(filename, mode="r") as f:
36
- data = f["data"][()]
37
- numpy.testing.assert_allclose(data, expected)
38
-
39
-
40
- @pytest.mark.parametrize("nstack", (1, 4))
41
- @pytest.mark.parametrize("npoints", (1, 3, 1000))
42
- @pytest.mark.parametrize("flush_period", (None, 0.1))
43
- @pytest.mark.parametrize("known_npoints", (True, False))
44
- @pytest.mark.parametrize("known_nstack", (True, False))
45
- @pytest.mark.parametrize("append_stacks_in_parallel", (True, False))
46
- def test_stack_dataset_writer(
47
- tmpdir,
48
- nstack,
49
- npoints,
50
- flush_period,
51
- known_npoints,
52
- known_nstack,
53
- append_stacks_in_parallel,
54
- ):
55
- expected = [list() for _ in range(nstack)]
56
- filename = str(tmpdir / "test.h5")
57
- if flush_period is None:
58
- sleep_time = None
59
- else:
60
- sleep_time = flush_period + 0.1
61
- isleep = (nstack * npoints) // 3
62
-
63
- kwargs = {"flush_period": flush_period}
64
- if known_npoints:
65
- kwargs["npoints"] = npoints
66
- if known_nstack:
67
- kwargs["nstack"] = nstack
68
-
69
- if append_stacks_in_parallel:
70
- itpoints = itertools.product(range(npoints), range(nstack))
71
- else:
72
- itpoints = itertools.product(range(nstack), range(npoints))
73
-
74
- with h5py.File(filename, mode="w") as f:
75
- with dataset_writer.StackDatasetWriter(f, "data", **kwargs) as writer:
76
- for tpl in itpoints:
77
- if append_stacks_in_parallel:
78
- ipoint, istack = tpl
79
- else:
80
- istack, ipoint = tpl
81
- data = numpy.random.random((10, 20))
82
- writer.add_point(data, istack)
83
- expected[istack].append(data)
84
- if sleep_time and (ipoint * nstack + istack) == isleep:
85
- time.sleep(sleep_time)
86
-
87
- with h5py.File(filename, mode="r") as f:
88
- data = f["data"][()]
89
- numpy.testing.assert_allclose(data, expected)
@@ -1,50 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: ewoksdata
3
- Version: 0.6.0
4
- Summary: Ewoks tasks for data access
5
- Home-page: https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
6
- Author: ESRF
7
- Author-email: wout.de_nolf@esrf.fr
8
- License: MIT
9
- Project-URL: Source, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/
10
- Project-URL: Documentation, https://ewoksdata.readthedocs.io
11
- Project-URL: Tracker, https://gitlab.esrf.fr/workflow/ewoksapps/ewoksdata/issues/
12
- Classifier: Intended Audience :: Science/Research
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Programming Language :: Python :: 3
15
- Requires-Python: >=3.7
16
- Description-Content-Type: text/markdown
17
- License-File: LICENSE.md
18
- Requires-Dist: h5py>=2.8
19
- Requires-Dist: silx>=1.1.0
20
- Requires-Dist: hdf5plugin
21
- Requires-Dist: blissdata>=0.3.4
22
- Requires-Dist: blissdata<1.0.1; python_version < "3.8"
23
- Requires-Dist: blissdata; python_version >= "3.8"
24
- Requires-Dist: redis
25
- Requires-Dist: packaging
26
- Requires-Dist: importlib_metadata; python_version < "3.8"
27
- Provides-Extra: online
28
- Requires-Dist: blissdata[tango]; extra == "online"
29
- Provides-Extra: test
30
- Requires-Dist: blissdata[tango]; extra == "test"
31
- Requires-Dist: pytest>=7; extra == "test"
32
- Provides-Extra: dev
33
- Requires-Dist: blissdata[tango]; extra == "dev"
34
- Requires-Dist: pytest>=7; extra == "dev"
35
- Requires-Dist: black>=22; extra == "dev"
36
- Requires-Dist: flake8>=4; extra == "dev"
37
- Provides-Extra: doc
38
- Requires-Dist: blissdata[tango]; extra == "doc"
39
- Requires-Dist: pytest>=7; extra == "doc"
40
- Requires-Dist: sphinx>=4.5; extra == "doc"
41
- Requires-Dist: sphinx-autodoc-typehints>=1.16; extra == "doc"
42
- Requires-Dist: pydata-sphinx-theme<0.15; extra == "doc"
43
-
44
- # ewoksdata
45
-
46
- Data access utilities for [ewoks](https://ewoks.readthedocs.io/) workflows.
47
-
48
- ## Documentation
49
-
50
- https://ewoksdata.readthedocs.io
File without changes
File without changes