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.
- ewoksdata-1.0.0/PKG-INFO +67 -0
- ewoksdata-1.0.0/pyproject.toml +65 -0
- ewoksdata-1.0.0/setup.cfg +4 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/bliss.py +1 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/__init__.py +1 -6
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/config.py +1 -2
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/dataset_writer.py +93 -62
- ewoksdata-1.0.0/src/ewoksdata/tests/__init__.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/conftest.py +1 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/data/bliss_scans.py +26 -2
- ewoksdata-1.0.0/src/ewoksdata/tests/test_dataset_writer.py +186 -0
- ewoksdata-1.0.0/src/ewoksdata.egg-info/PKG-INFO +67 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/SOURCES.txt +0 -2
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/requires.txt +6 -13
- ewoksdata-0.6.0/PKG-INFO +0 -50
- ewoksdata-0.6.0/pyproject.toml +0 -5
- ewoksdata-0.6.0/setup.cfg +0 -69
- ewoksdata-0.6.0/setup.py +0 -4
- ewoksdata-0.6.0/src/ewoksdata/__init__.py +0 -1
- ewoksdata-0.6.0/src/ewoksdata/tests/test_dataset_writer.py +0 -89
- ewoksdata-0.6.0/src/ewoksdata.egg-info/PKG-INFO +0 -50
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/LICENSE.md +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/README.md +0 -0
- {ewoksdata-0.6.0/src/ewoksdata/data → ewoksdata-1.0.0/src/ewoksdata}/__init__.py +0 -0
- {ewoksdata-0.6.0/src/ewoksdata/tests → ewoksdata-1.0.0/src/ewoksdata/data}/__init__.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav0.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav1.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/blissdata/blissdatav2.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/contextiterator.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/__init__.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/hdf5/types.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/nexus.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/url.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/data/utils.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/data/__init__.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_contextiterator.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_bliss.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_hdf5.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata/tests/test_data_nexus.py +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/dependency_links.txt +0 -0
- {ewoksdata-0.6.0 → ewoksdata-1.0.0}/src/ewoksdata.egg-info/top_level.txt +0 -0
ewoksdata-1.0.0/PKG-INFO
ADDED
|
@@ -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/*']
|
|
@@ -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
|
|
|
@@ -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.
|
|
91
|
-
|
|
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.
|
|
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
|
-
|
|
148
|
+
chunk_size = len(self._buffer)
|
|
149
|
+
|
|
143
150
|
if self._flush_time_expired():
|
|
144
|
-
|
|
151
|
+
flush_size = chunk_size
|
|
145
152
|
elif align and self._chunked:
|
|
146
|
-
n =
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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.
|
|
157
|
-
|
|
158
|
-
if self._chunked and
|
|
159
|
-
self._dataset.resize(
|
|
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
|
-
#
|
|
162
|
-
self.
|
|
163
|
-
self.
|
|
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.
|
|
210
|
-
self.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
268
|
-
|
|
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
|
-
|
|
291
|
+
flush_sizes = chunk_sizes
|
|
271
292
|
elif align and self._chunked:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
281
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
nalloc_new = numpy.array([
|
|
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
|
-
#
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
)
|
|
304
|
-
|
|
305
|
-
|
|
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,
|
|
337
|
+
for buffer, i_dim0, istart_dim1, i_flush_size_dim1 in zip(
|
|
309
338
|
buffers,
|
|
310
|
-
range(i0_chunk0, i0_chunk0 +
|
|
339
|
+
range(i0_chunk0, i0_chunk0 + chunk_size_dim0),
|
|
311
340
|
istart0_dim1,
|
|
312
|
-
|
|
341
|
+
flush_sizes_dim1,
|
|
313
342
|
):
|
|
314
|
-
self._dataset[
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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,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
|
|
@@ -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
|
-
|
|
17
|
-
|
|
18
|
-
black>=22
|
|
11
|
+
ewoksdata[test]
|
|
12
|
+
black>=25
|
|
19
13
|
flake8>=4
|
|
20
14
|
|
|
21
15
|
[doc]
|
|
22
|
-
|
|
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
|
-
|
|
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
|
ewoksdata-0.6.0/pyproject.toml
DELETED
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 +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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|