blissdata 0.3.3__tar.gz → 0.3.4__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.
- {blissdata-0.3.3 → blissdata-0.3.4}/PKG-INFO +14 -2
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/__init__.py +1 -1
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/beacon/_base.py +3 -1
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/lima.py +25 -5
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/remote_node.py +1 -11
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/bliss.py +2 -5
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/hdf5.py +68 -15
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/caching.py +22 -28
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/settings.py +2 -2
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/h5api/scanner.py +2 -2
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata.egg-info/PKG-INFO +14 -2
- {blissdata-0.3.3 → blissdata-0.3.4}/LICENSE +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/README.md +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/beacon/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/beacon/config.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/beacon/data.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/beacon/files.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/client.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/common/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/common/utils.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/channel.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/node.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/scan.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/events/walk.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/expiration.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/lima_image.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/node.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/channel.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/dataset.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/dataset_collection.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/lima.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/node_ref_channel.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/proposal.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/scan.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/nodes/scan_group.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/data/scan.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/abstract.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/dynamic_hdf5.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/file_arguments.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/static_hdf5.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/hdf5_retry.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/lima.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/h5api/utils/types.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/connection.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/manager.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/proxy.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/redis/scripting.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/streaming.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/streaming_events.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/beacon/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/beacon/test_config.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/beacon/test_data.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/beacon/test_files.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/conftest.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/h5api/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/h5api/test_dynamic_files.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/h5api/test_static_files.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/redis/__init__.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata/tests/redis/manager.py +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata.egg-info/SOURCES.txt +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata.egg-info/dependency_links.txt +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata.egg-info/requires.txt +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/blissdata.egg-info/top_level.txt +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/pyproject.toml +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/setup.cfg +0 -0
- {blissdata-0.3.3 → blissdata-0.3.4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: blissdata
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Bliss data streaming client
|
|
5
5
|
Home-page: https://gitlab.esrf.fr/bliss/bliss/-/tree/master/blissdata
|
|
6
6
|
Author: BCU (ESRF)
|
|
@@ -10,11 +10,23 @@ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGP
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Requires-Python: <3.10,>=3.7
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: gevent>=20.9.0
|
|
15
|
+
Requires-Dist: h5py>=2.9
|
|
16
|
+
Requires-Dist: numpy>=1.13
|
|
17
|
+
Requires-Dist: silx>=1.1.0
|
|
13
18
|
Provides-Extra: tango
|
|
19
|
+
Requires-Dist: pytango>=9.3.1; extra == "tango"
|
|
14
20
|
Provides-Extra: test
|
|
21
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
22
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
15
23
|
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
26
|
+
Requires-Dist: black==22.3; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8>=4; extra == "dev"
|
|
16
28
|
Provides-Extra: beacon
|
|
17
|
-
|
|
29
|
+
Requires-Dist: ruamel.yaml; extra == "beacon"
|
|
18
30
|
|
|
19
31
|
# blissdata
|
|
20
32
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Base client to communicate with Beacon."""
|
|
2
2
|
|
|
3
|
+
import platform
|
|
3
4
|
import socket
|
|
4
5
|
import struct
|
|
5
6
|
import threading
|
|
@@ -28,7 +29,8 @@ class BeaconClient:
|
|
|
28
29
|
else:
|
|
29
30
|
self._address = host, port
|
|
30
31
|
connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
31
|
-
|
|
32
|
+
if platform.system() != "Windows":
|
|
33
|
+
connection.setsockopt(socket.SOL_IP, socket.IP_TOS, 0x10)
|
|
32
34
|
connection.connect(self._address)
|
|
33
35
|
connection.settimeout(timeout)
|
|
34
36
|
self._connection = connection
|
|
@@ -244,9 +244,24 @@ class LimaImageStatusEvent(streaming_events.StreamEvent):
|
|
|
244
244
|
images_per_acquisition = info["saving_frame_per_acquisition"]
|
|
245
245
|
|
|
246
246
|
first_file_index_in_scan = info["saving_next_number"]
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
if "saving_managed_mode" not in info:
|
|
248
|
+
raise RuntimeError(
|
|
249
|
+
"Lima info does not have 'saving_managed_mode'. Upgrade Bliss to solve it."
|
|
250
|
+
)
|
|
251
|
+
if info["saving_managed_mode"] == "HARDWARE":
|
|
252
|
+
# Assume Dectris hardware saving
|
|
253
|
+
subdir_format = (
|
|
254
|
+
info["saving_prefix"]
|
|
255
|
+
+ "_data_"
|
|
256
|
+
+ info["saving_index_format"]
|
|
257
|
+
+ info["saving_suffix"]
|
|
258
|
+
)
|
|
259
|
+
else:
|
|
260
|
+
subdir_format = (
|
|
261
|
+
info["saving_prefix"]
|
|
262
|
+
+ info["saving_index_format"]
|
|
263
|
+
+ info["saving_suffix"]
|
|
264
|
+
)
|
|
250
265
|
path_format = os.path.join(info["saving_directory"], subdir_format)
|
|
251
266
|
file_format = info["saving_format"]
|
|
252
267
|
|
|
@@ -260,9 +275,13 @@ class LimaImageStatusEvent(streaming_events.StreamEvent):
|
|
|
260
275
|
)
|
|
261
276
|
if file_index_in_scan is None:
|
|
262
277
|
break
|
|
263
|
-
file_path = path_format % file_index_in_scan
|
|
264
278
|
if file_format.lower().startswith("hdf5"):
|
|
265
|
-
if info["
|
|
279
|
+
if info["saving_managed_mode"] == "HARDWARE":
|
|
280
|
+
# Assume Dectris hardware saving
|
|
281
|
+
path_in_file = "/entry/data/data"
|
|
282
|
+
# Dectris starts counting from 1 instead of 0 like lima does
|
|
283
|
+
file_index_in_scan += 1
|
|
284
|
+
elif info["lima_version"] == "<1.9.1":
|
|
266
285
|
# 'old' lima
|
|
267
286
|
path_in_file = (
|
|
268
287
|
"/entry_0000/instrument/"
|
|
@@ -277,6 +296,7 @@ class LimaImageStatusEvent(streaming_events.StreamEvent):
|
|
|
277
296
|
)
|
|
278
297
|
else:
|
|
279
298
|
path_in_file = ""
|
|
299
|
+
file_path = path_format % file_index_in_scan
|
|
280
300
|
yield file_path, path_in_file, image_index_in_file, file_format
|
|
281
301
|
|
|
282
302
|
@staticmethod
|
|
@@ -199,16 +199,6 @@ class RemoteNodeWalker:
|
|
|
199
199
|
node.node_type,
|
|
200
200
|
node.name,
|
|
201
201
|
node.db_name,
|
|
202
|
-
|
|
202
|
+
node.info.get_all(),
|
|
203
203
|
redis_url,
|
|
204
204
|
)
|
|
205
|
-
|
|
206
|
-
@staticmethod
|
|
207
|
-
def pack_info(info):
|
|
208
|
-
info_dict = info.get_all()
|
|
209
|
-
try:
|
|
210
|
-
# ScanState objects brings Bliss dependencies with them, replace with name
|
|
211
|
-
info_dict["state"] = info["state"].name
|
|
212
|
-
except KeyError:
|
|
213
|
-
pass
|
|
214
|
-
return info_dict
|
|
@@ -102,7 +102,7 @@ class BlissDynamicHDF5Handler(hdf5.DynamicHDF5Handler):
|
|
|
102
102
|
if h5item.name == hdf5.SEP:
|
|
103
103
|
return False
|
|
104
104
|
scan = [s for s in h5item.name.split(hdf5.SEP) if s][0]
|
|
105
|
-
nxentry = self.file_obj
|
|
105
|
+
nxentry = self.file_obj[scan]
|
|
106
106
|
except AttributeError:
|
|
107
107
|
raise RetryError("file is closed")
|
|
108
108
|
if "end_time" in nxentry:
|
|
@@ -119,10 +119,7 @@ class BlissDynamicHDF5Handler(hdf5.DynamicHDF5Handler):
|
|
|
119
119
|
nxentry = self.file_obj[scan]
|
|
120
120
|
except AttributeError:
|
|
121
121
|
raise RetryError("file is closed")
|
|
122
|
-
|
|
123
|
-
# Last dataset written to the file
|
|
124
|
-
return True
|
|
125
|
-
return self._get_writer_status(nxentry) in ("SUCCEEDED", "FAILED")
|
|
122
|
+
return "end_time" in nxentry # Last dataset written to the file
|
|
126
123
|
|
|
127
124
|
def _get_writer_status(self, nxentry: h5py.Dataset) -> Optional[str]:
|
|
128
125
|
nxnote = nxentry.get("writer", None)
|
|
@@ -10,7 +10,7 @@ from . import types
|
|
|
10
10
|
from . import lima
|
|
11
11
|
from .hdf5_retry import retry_file_access
|
|
12
12
|
from .hdf5_retry import ignore_retry_timeout
|
|
13
|
-
from .hdf5_retry import RetryError, SoftRetryError
|
|
13
|
+
from .hdf5_retry import RetryTimeoutError, RetryError, SoftRetryError
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
HDF5Item = Union[h5py.Dataset, h5py.Group, h5py.File, lima.LimaDataset, lima.LimaGroup]
|
|
@@ -71,13 +71,19 @@ class DynamicHDF5Handler:
|
|
|
71
71
|
return self._file_obj
|
|
72
72
|
|
|
73
73
|
def get_item(self, name: str) -> HDF5Item:
|
|
74
|
-
|
|
74
|
+
try:
|
|
75
|
+
return self._retry_get_item(name)
|
|
76
|
+
except RetryTimeoutError:
|
|
77
|
+
raise KeyError(name)
|
|
75
78
|
|
|
76
79
|
def slice_dataset(self, name: str, idx: types.DataIndexType) -> types.DataType:
|
|
77
80
|
return self._retry_slice_dataset(name, idx)
|
|
78
81
|
|
|
79
82
|
def get_attr(self, name: str, key: str) -> Any:
|
|
80
|
-
|
|
83
|
+
try:
|
|
84
|
+
return self._retry_get_attr(name, key)
|
|
85
|
+
except RetryTimeoutError:
|
|
86
|
+
raise AttributeError(name)
|
|
81
87
|
|
|
82
88
|
@ignore_retry_timeout
|
|
83
89
|
def iter_attrs(self, name: str) -> Iterator[str]:
|
|
@@ -138,7 +144,24 @@ class DynamicHDF5Handler:
|
|
|
138
144
|
item = self._native_items.get(name)
|
|
139
145
|
if item is not None:
|
|
140
146
|
return item
|
|
141
|
-
|
|
147
|
+
try:
|
|
148
|
+
item = self.file_obj[name]
|
|
149
|
+
except KeyError:
|
|
150
|
+
parent_name, _, item_name = name.rpartition(SEP)
|
|
151
|
+
if not parent_name:
|
|
152
|
+
parent_name = SEP
|
|
153
|
+
if parent_name == name:
|
|
154
|
+
raise
|
|
155
|
+
parent_item = self._get_item(parent_name)
|
|
156
|
+
if not self._is_finished(parent_item):
|
|
157
|
+
raise # item could still be created
|
|
158
|
+
try:
|
|
159
|
+
item = parent_item[item_name] # try one more time
|
|
160
|
+
except KeyError as e:
|
|
161
|
+
if not _key_does_not_exist(e):
|
|
162
|
+
raise
|
|
163
|
+
# item will never be created
|
|
164
|
+
raise RetryTimeoutError(str(e)) from e
|
|
142
165
|
self._native_items[name] = item
|
|
143
166
|
return item
|
|
144
167
|
|
|
@@ -152,16 +175,28 @@ class DynamicHDF5Handler:
|
|
|
152
175
|
|
|
153
176
|
def _get_attr(self, name: str, key: str) -> Any:
|
|
154
177
|
item = self._get_item(name)
|
|
155
|
-
|
|
178
|
+
try:
|
|
179
|
+
return item.attrs[key]
|
|
180
|
+
except KeyError:
|
|
181
|
+
if not self._is_finished(item):
|
|
182
|
+
raise # attribute could still be created
|
|
183
|
+
try:
|
|
184
|
+
return item.attrs[key] # try one more time
|
|
185
|
+
except KeyError as e:
|
|
186
|
+
if not _key_does_not_exist(e):
|
|
187
|
+
raise
|
|
188
|
+
# attribute will never be created
|
|
189
|
+
raise RetryTimeoutError(str(e)) from e
|
|
156
190
|
|
|
157
191
|
def _iter_attrs(self, name: str, start_index: int = 0) -> Iterator[str]:
|
|
158
192
|
item = self._get_item(name)
|
|
193
|
+
is_complete = self._is_initialized(item)
|
|
159
194
|
if start_index == 0:
|
|
160
195
|
yield from item.attrs
|
|
161
196
|
else:
|
|
162
197
|
yield from list(item.attrs)[start_index:]
|
|
163
|
-
if not
|
|
164
|
-
raise RetryError("
|
|
198
|
+
if not is_complete:
|
|
199
|
+
raise RetryError("attributes could still be added")
|
|
165
200
|
|
|
166
201
|
def _len_attrs(self, name: str) -> int:
|
|
167
202
|
item = self._get_item(name)
|
|
@@ -173,19 +208,19 @@ class DynamicHDF5Handler:
|
|
|
173
208
|
item = self._get_item(name)
|
|
174
209
|
self._check_dataset_before_read(item)
|
|
175
210
|
if self.is_group(item):
|
|
176
|
-
|
|
211
|
+
is_complete = self._is_initialized(item)
|
|
177
212
|
for key in self._iter_group(item, start_index):
|
|
178
|
-
|
|
213
|
+
is_complete = False
|
|
179
214
|
yield key
|
|
180
|
-
if not
|
|
181
|
-
raise RetryError("
|
|
215
|
+
if not is_complete:
|
|
216
|
+
raise RetryError("children could still be added to the group")
|
|
182
217
|
else:
|
|
183
|
-
|
|
218
|
+
is_complete = self._is_finished(item)
|
|
184
219
|
for data in self._iter_dataset(item, start_index):
|
|
185
|
-
|
|
220
|
+
is_complete = False
|
|
186
221
|
yield data
|
|
187
|
-
if not
|
|
188
|
-
raise RetryError("
|
|
222
|
+
if not is_complete:
|
|
223
|
+
raise RetryError("dataset could still grow")
|
|
189
224
|
|
|
190
225
|
@staticmethod
|
|
191
226
|
def is_group(h5item: HDF5Item):
|
|
@@ -225,3 +260,21 @@ class DynamicHDF5Handler:
|
|
|
225
260
|
|
|
226
261
|
def _is_finished(self, h5item: HDF5Item) -> bool:
|
|
227
262
|
return True
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _key_does_not_exist(exc: KeyError) -> bool:
|
|
266
|
+
"""
|
|
267
|
+
A real KeyError (meaning that the key does not exist) gives the following error message:
|
|
268
|
+
|
|
269
|
+
.. code
|
|
270
|
+
|
|
271
|
+
KeyError: "Unable to synchronously open object (object 'end_time' doesn't exist)"
|
|
272
|
+
|
|
273
|
+
An example of a KeyError caused by another reason
|
|
274
|
+
|
|
275
|
+
.. code
|
|
276
|
+
|
|
277
|
+
KeyError: 'Unable to synchronously open object (addr overflow, addr = 64392369, size = 96, eoa = 64365353)'
|
|
278
|
+
|
|
279
|
+
"""
|
|
280
|
+
return "doesn't exist" in str(exc)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Client-side Redis cache with an invalidation connection.
|
|
2
2
|
"""
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import socket
|
|
5
5
|
import gevent
|
|
6
6
|
import gevent.event
|
|
7
7
|
import gevent.select
|
|
@@ -39,7 +39,7 @@ class CachingConnectionGreenlet(gevent.Greenlet):
|
|
|
39
39
|
self._started_event = started_event
|
|
40
40
|
self._tracking_redirect_id = None
|
|
41
41
|
self.connection = None
|
|
42
|
-
self.
|
|
42
|
+
self._rp, self._wp = None, None
|
|
43
43
|
super().__init__()
|
|
44
44
|
|
|
45
45
|
def stop(self):
|
|
@@ -48,11 +48,11 @@ class CachingConnectionGreenlet(gevent.Greenlet):
|
|
|
48
48
|
|
|
49
49
|
Calling `kill` might not return the pubsub connection to the pool.
|
|
50
50
|
"""
|
|
51
|
-
self._send_fd(self.
|
|
51
|
+
self._send_fd(self._wp, b"X")
|
|
52
52
|
|
|
53
53
|
def _run(self):
|
|
54
54
|
with ExitStack() as stack:
|
|
55
|
-
ctx = self.
|
|
55
|
+
ctx = self._setup_wp()
|
|
56
56
|
rp, stop_callback = stack.enter_context(ctx)
|
|
57
57
|
|
|
58
58
|
ctx = self._setup_invalidation_connection(stop_callback)
|
|
@@ -65,44 +65,38 @@ class CachingConnectionGreenlet(gevent.Greenlet):
|
|
|
65
65
|
self._started_event.set()
|
|
66
66
|
self._invalidation_loop(pubsub, rp)
|
|
67
67
|
|
|
68
|
-
@
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def stop_callback(*args, **kw):
|
|
68
|
+
@staticmethod
|
|
69
|
+
def _close_fd(fd):
|
|
70
|
+
if fd is not None:
|
|
73
71
|
try:
|
|
74
|
-
|
|
72
|
+
fd.close()
|
|
75
73
|
except OSError:
|
|
76
74
|
# already closed
|
|
77
75
|
pass
|
|
78
76
|
|
|
79
|
-
try:
|
|
80
|
-
self._close_pipe = wp
|
|
81
|
-
yield rp, stop_callback
|
|
82
|
-
finally:
|
|
83
|
-
self._close_pipe = None
|
|
84
|
-
self._close_fd(wp)
|
|
85
|
-
self._close_fd(rp)
|
|
86
|
-
|
|
87
77
|
@staticmethod
|
|
88
|
-
def
|
|
78
|
+
def _send_fd(fd, msg):
|
|
89
79
|
if fd is None:
|
|
90
80
|
return
|
|
91
81
|
try:
|
|
92
|
-
|
|
82
|
+
fd.send(msg)
|
|
93
83
|
except OSError:
|
|
94
84
|
# already closed
|
|
95
85
|
pass
|
|
96
86
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
def _close_wp(self):
|
|
88
|
+
return self._close_fd(self._wp)
|
|
89
|
+
|
|
90
|
+
@contextmanager
|
|
91
|
+
def _setup_wp(self):
|
|
92
|
+
self._rp, self._wp = socket.socketpair()
|
|
93
|
+
|
|
101
94
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
yield self._rp, self._close_wp
|
|
96
|
+
finally:
|
|
97
|
+
self._close_fd(self._rp)
|
|
98
|
+
self._close_fd(self._wp)
|
|
99
|
+
self._rp, self._wp = None, None
|
|
106
100
|
|
|
107
101
|
@contextmanager
|
|
108
102
|
def _setup_invalidation_connection(self, stop_callback):
|
|
@@ -712,7 +712,7 @@ local set_size = redis.call("ZCARD", setkey)
|
|
|
712
712
|
if set_max_score > set_size then
|
|
713
713
|
-- we need to reassign scores as some was deleted
|
|
714
714
|
local new_order = 1
|
|
715
|
-
table = redis.call("ZRANGE", setkey, 0, -1)
|
|
715
|
+
local table = redis.call("ZRANGE", setkey, 0, -1)
|
|
716
716
|
for k, attr in pairs(table)
|
|
717
717
|
do
|
|
718
718
|
--redis.call("ZADD", setkey, new_order, attr)
|
|
@@ -764,7 +764,7 @@ class OrderedHashSetting(BaseHashSetting):
|
|
|
764
764
|
if self.connection.exists(self.name) and not self.connection.exists(
|
|
765
765
|
self._name_order
|
|
766
766
|
):
|
|
767
|
-
if self.connection.type(self.name) == b"hash":
|
|
767
|
+
if self.connection.type(self.name) == b"hash": # noqa E721
|
|
768
768
|
# we can provide a default order (alphabetical), to ensure an ordered hash
|
|
769
769
|
# can be built on top of an existing hash ; this is to preserve
|
|
770
770
|
# settings coherency in case of type "upgrade" (like when Lima ROIs
|
|
@@ -268,7 +268,7 @@ def writer_context(filename: str, scan_number: int) -> Iterator[h5py.Group]:
|
|
|
268
268
|
|
|
269
269
|
try:
|
|
270
270
|
entry.attrs["NX_class"] = "NXentry"
|
|
271
|
-
entry
|
|
271
|
+
entry["start_time"] = timestamp()
|
|
272
272
|
writer = entry.create_group("writer")
|
|
273
273
|
writer.attrs["NX_class"] = "NXnote"
|
|
274
274
|
writer["status"] = "STARTING"
|
|
@@ -279,7 +279,7 @@ def writer_context(filename: str, scan_number: int) -> Iterator[h5py.Group]:
|
|
|
279
279
|
else:
|
|
280
280
|
writer["status"][()] = "SUCCEEDED"
|
|
281
281
|
finally:
|
|
282
|
-
entry
|
|
282
|
+
entry["end_time"] = timestamp()
|
|
283
283
|
|
|
284
284
|
|
|
285
285
|
@contextmanager
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: blissdata
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Bliss data streaming client
|
|
5
5
|
Home-page: https://gitlab.esrf.fr/bliss/bliss/-/tree/master/blissdata
|
|
6
6
|
Author: BCU (ESRF)
|
|
@@ -10,11 +10,23 @@ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGP
|
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Requires-Python: <3.10,>=3.7
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: gevent>=20.9.0
|
|
15
|
+
Requires-Dist: h5py>=2.9
|
|
16
|
+
Requires-Dist: numpy>=1.13
|
|
17
|
+
Requires-Dist: silx>=1.1.0
|
|
13
18
|
Provides-Extra: tango
|
|
19
|
+
Requires-Dist: pytango>=9.3.1; extra == "tango"
|
|
14
20
|
Provides-Extra: test
|
|
21
|
+
Requires-Dist: pytest>=7; extra == "test"
|
|
22
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
15
23
|
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
26
|
+
Requires-Dist: black==22.3; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8>=4; extra == "dev"
|
|
16
28
|
Provides-Extra: beacon
|
|
17
|
-
|
|
29
|
+
Requires-Dist: ruamel.yaml; extra == "beacon"
|
|
18
30
|
|
|
19
31
|
# blissdata
|
|
20
32
|
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|