blissdata-lima2 2.0__tar.gz → 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/PKG-INFO +5 -2
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/pyproject.toml +6 -3
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2/stream.py +144 -47
- blissdata_lima2-2.0.2/src/blissdata_lima2/tests/test_lima2_stream.py +458 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/PKG-INFO +5 -2
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/requires.txt +3 -1
- blissdata_lima2-2.0/src/blissdata_lima2/tests/test_lima2_stream.py +0 -178
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/LICENSE.md +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/README.md +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/setup.cfg +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2/__init__.py +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2/tests/__init__.py +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2/tests/conftest.py +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/SOURCES.txt +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/dependency_links.txt +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/entry_points.txt +0 -0
- {blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/top_level.txt +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blissdata-lima2
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Lima2 plugin for blissdata
|
|
5
5
|
Maintainer: BCU (ESRF)
|
|
6
6
|
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://gitlab.esrf.fr/bliss/blissdata-lima2
|
|
7
8
|
Keywords: blissdata,lima2
|
|
8
9
|
Classifier: Intended Audience :: Science/Research
|
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -11,11 +12,13 @@ Requires-Python: >=3.10
|
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
License-File: LICENSE.md
|
|
13
14
|
Requires-Dist: blissdata~=2.3
|
|
14
|
-
Requires-Dist: lima2-client~=4.
|
|
15
|
+
Requires-Dist: lima2-client~=4.1
|
|
15
16
|
Provides-Extra: dev
|
|
16
17
|
Requires-Dist: black; extra == "dev"
|
|
17
18
|
Requires-Dist: flake8; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy; extra == "dev"
|
|
18
20
|
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
19
22
|
Requires-Dist: pytest-redis; extra == "dev"
|
|
20
23
|
Dynamic: license-file
|
|
21
24
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "blissdata-lima2"
|
|
7
|
-
version = "2.0"
|
|
7
|
+
version = "2.0.2"
|
|
8
8
|
description = "Lima2 plugin for blissdata"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -16,10 +16,13 @@ classifiers = [
|
|
|
16
16
|
]
|
|
17
17
|
keywords = ["blissdata", "lima2"]
|
|
18
18
|
requires-python = ">=3.10"
|
|
19
|
-
dependencies = ["blissdata~=2.3", "lima2-client~=4.
|
|
19
|
+
dependencies = ["blissdata~=2.3", "lima2-client~=4.1"]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Repository = "https://gitlab.esrf.fr/bliss/blissdata-lima2"
|
|
20
23
|
|
|
21
24
|
[project.optional-dependencies]
|
|
22
|
-
dev = ["black", "flake8", "pytest", "pytest-redis"]
|
|
25
|
+
dev = ["black", "flake8", "mypy", "pytest", "pytest-cov", "pytest-redis"]
|
|
23
26
|
|
|
24
27
|
[project.entry-points.blissdata]
|
|
25
28
|
lima2 = "blissdata_lima2"
|
|
@@ -15,17 +15,19 @@ from blissdata.exceptions import (
|
|
|
15
15
|
EndOfStream,
|
|
16
16
|
IndexNoMoreThereError,
|
|
17
17
|
IndexNotYetThereError,
|
|
18
|
+
IndexWontBeThereError,
|
|
18
19
|
)
|
|
20
|
+
from blissdata.h5api import dynamic_hdf5
|
|
19
21
|
from blissdata.lima.image_utils import ImageData
|
|
20
22
|
from blissdata.streams import (
|
|
21
23
|
BaseStream,
|
|
22
24
|
BaseView,
|
|
23
25
|
EventRange,
|
|
24
|
-
EventStream,
|
|
25
26
|
StreamDefinition,
|
|
26
27
|
)
|
|
27
28
|
from blissdata.streams.default import Stream
|
|
28
29
|
from blissdata.streams.encoding.numeric import NumericStreamEncoder
|
|
30
|
+
from blissdata.streams.event_stream import EventStream
|
|
29
31
|
from blissdata.streams.lima.stream import LimaDirectAccess
|
|
30
32
|
from lima2.common.devencoded.sparse_frame import SparseFrame
|
|
31
33
|
from numpy.typing import DTypeLike
|
|
@@ -72,24 +74,30 @@ class Lima2View(BaseView):
|
|
|
72
74
|
def __len__(self) -> int:
|
|
73
75
|
return len(self._idx_range)
|
|
74
76
|
|
|
75
|
-
def get_data(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
def get_data(self, start: int | None = None, stop: int | None = None) -> np.ndarray:
|
|
78
|
+
frames = []
|
|
79
|
+
for idx in self._idx_range[start:stop]:
|
|
80
|
+
try:
|
|
81
|
+
frames.append(
|
|
82
|
+
get_frame(
|
|
83
|
+
services=self._services,
|
|
84
|
+
acq_uuid=self._acq_uuid,
|
|
85
|
+
source=self._source,
|
|
86
|
+
frame_idx=idx,
|
|
87
|
+
).array
|
|
85
88
|
)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
except RuntimeError as e:
|
|
90
|
+
# Raise if any frame can't be accessed
|
|
91
|
+
raise IndexNoMoreThereError(
|
|
92
|
+
f"Can't fetch {self._source} {self._idx_range[start:stop]}: {e}"
|
|
93
|
+
) from e
|
|
94
|
+
except ValueError as e:
|
|
95
|
+
# Frame source has no associated memory buffer (raw_frame)
|
|
96
|
+
raise IndexNoMoreThereError(
|
|
97
|
+
f"Can't fetch {self._source}: no associated live data"
|
|
98
|
+
) from e
|
|
99
|
+
|
|
100
|
+
return np.asarray(frames)
|
|
93
101
|
|
|
94
102
|
|
|
95
103
|
class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
@@ -120,6 +128,7 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
120
128
|
self._shape = tuple(event_stream.info["shape"])
|
|
121
129
|
self._acq_uuid = str(event_stream.info["acq_uuid"])
|
|
122
130
|
self._source = str(event_stream.info["source_name"])
|
|
131
|
+
self._master_file: tuple[str, str] | None = event_stream.info["master_file"]
|
|
123
132
|
|
|
124
133
|
self._services = l2s.init(
|
|
125
134
|
hostname=str(event_stream.info["conductor_hostname"]),
|
|
@@ -132,8 +141,14 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
132
141
|
|
|
133
142
|
self._cursor = Stream(event_stream).cursor()
|
|
134
143
|
|
|
144
|
+
self._services.handshake()
|
|
145
|
+
|
|
146
|
+
####################################################################################
|
|
147
|
+
# BaseStream
|
|
148
|
+
####################################################################################
|
|
149
|
+
|
|
135
150
|
@property
|
|
136
|
-
def kind(self):
|
|
151
|
+
def kind(self) -> str:
|
|
137
152
|
return "array"
|
|
138
153
|
|
|
139
154
|
@staticmethod
|
|
@@ -145,7 +160,7 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
145
160
|
acq_uuid: str,
|
|
146
161
|
master_file: tuple[str, str] | None,
|
|
147
162
|
dtype: DTypeLike,
|
|
148
|
-
shape: Sequence,
|
|
163
|
+
shape: Sequence[int],
|
|
149
164
|
) -> StreamDefinition:
|
|
150
165
|
info = {
|
|
151
166
|
"plugin": "lima2",
|
|
@@ -184,34 +199,43 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
184
199
|
self._length = int(last_status)
|
|
185
200
|
return self._length
|
|
186
201
|
|
|
187
|
-
def __getitem__(self, key: int | slice) ->
|
|
188
|
-
|
|
189
|
-
if
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
def __getitem__(self, key: int | slice) -> np.ndarray:
|
|
203
|
+
sealed = self.is_sealed()
|
|
204
|
+
if isinstance(key, int):
|
|
205
|
+
size = len(self)
|
|
206
|
+
if key < 0:
|
|
207
|
+
if not sealed:
|
|
208
|
+
raise IndexNotYetThereError(
|
|
209
|
+
"Can't index from end of stream until it is sealed"
|
|
210
|
+
)
|
|
211
|
+
else:
|
|
212
|
+
key += size
|
|
213
|
+
|
|
214
|
+
if not 0 <= key < size:
|
|
215
|
+
# Fail early if we're out of bounds
|
|
216
|
+
if sealed:
|
|
217
|
+
raise IndexWontBeThereError(
|
|
218
|
+
f"Frame {key} is out of range (0..{size-1})"
|
|
219
|
+
)
|
|
220
|
+
else:
|
|
221
|
+
raise IndexNotYetThereError(
|
|
222
|
+
f"Frame {key} is out of range (0..{size-1})"
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
return self._fetch_frames(start=key, stop=key + 1, step=1)[0]
|
|
226
|
+
|
|
227
|
+
elif isinstance(key, slice):
|
|
228
|
+
if (key.start or 0) < 0 or (key.stop or 0) < 0:
|
|
229
|
+
if not sealed:
|
|
230
|
+
raise IndexNotYetThereError(
|
|
231
|
+
"Can't slice from end of stream until it is sealed"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Resolve the slice in the standard way
|
|
235
|
+
start, stop, step = key.indices(len(self))
|
|
236
|
+
|
|
237
|
+
return self._fetch_frames(start=start, stop=stop, step=step)
|
|
205
238
|
|
|
206
|
-
return [
|
|
207
|
-
get_frame(
|
|
208
|
-
services=self._services,
|
|
209
|
-
acq_uuid=self._acq_uuid,
|
|
210
|
-
source=self._source,
|
|
211
|
-
frame_idx=idx,
|
|
212
|
-
)
|
|
213
|
-
for idx in idx_range[key]
|
|
214
|
-
]
|
|
215
239
|
else:
|
|
216
240
|
raise TypeError(f"{type(key)}")
|
|
217
241
|
|
|
@@ -245,6 +269,10 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
245
269
|
stop=stop_idx,
|
|
246
270
|
)
|
|
247
271
|
|
|
272
|
+
####################################################################################
|
|
273
|
+
# LimaDirectAccess
|
|
274
|
+
####################################################################################
|
|
275
|
+
|
|
248
276
|
def get_last_live_image(self) -> ImageData:
|
|
249
277
|
return get_frame(
|
|
250
278
|
services=self._services,
|
|
@@ -252,3 +280,72 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
|
|
|
252
280
|
source=self._source,
|
|
253
281
|
frame_idx=-1,
|
|
254
282
|
)
|
|
283
|
+
|
|
284
|
+
####################################################################################
|
|
285
|
+
# Private API
|
|
286
|
+
####################################################################################
|
|
287
|
+
|
|
288
|
+
def _fetch_frames(self, start: int, stop: int, step: int) -> np.ndarray:
|
|
289
|
+
"""Get frame data online or offline, depending on the current state."""
|
|
290
|
+
if self.is_sealed():
|
|
291
|
+
if self._master_file is not None:
|
|
292
|
+
# Default to an offline lookup
|
|
293
|
+
filepath, datapath = self._master_file
|
|
294
|
+
return self._fetch_from_disk(
|
|
295
|
+
filepath=filepath,
|
|
296
|
+
datapath=datapath,
|
|
297
|
+
start=start,
|
|
298
|
+
stop=stop,
|
|
299
|
+
step=step,
|
|
300
|
+
)
|
|
301
|
+
else:
|
|
302
|
+
# Try online, in case backends still have the frames we want
|
|
303
|
+
_logger.warning(
|
|
304
|
+
f"Requesting frames {start}:{stop}:{step} after stream is sealed, "
|
|
305
|
+
f"but this frame source ({self._source}) isn't persistent."
|
|
306
|
+
)
|
|
307
|
+
return self._fetch_online(start=start, stop=stop, step=step)
|
|
308
|
+
|
|
309
|
+
else:
|
|
310
|
+
return self._fetch_online(start=start, stop=stop, step=step)
|
|
311
|
+
|
|
312
|
+
def _fetch_online(self, start: int, stop: int, step: int) -> np.ndarray:
|
|
313
|
+
"""Get frame data directly from the Lima2 devices."""
|
|
314
|
+
_logger.info(
|
|
315
|
+
f"Fetching {self._source} {start}:{stop}:{step} from lima2 backend"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
frames = []
|
|
319
|
+
for idx in range(start, stop, step):
|
|
320
|
+
try:
|
|
321
|
+
frames.append(
|
|
322
|
+
get_frame(
|
|
323
|
+
services=self._services,
|
|
324
|
+
acq_uuid=self._acq_uuid,
|
|
325
|
+
source=self._source,
|
|
326
|
+
frame_idx=idx,
|
|
327
|
+
).array
|
|
328
|
+
)
|
|
329
|
+
except RuntimeError as e:
|
|
330
|
+
# Raise if any frame can't be accessed
|
|
331
|
+
raise IndexNoMoreThereError(
|
|
332
|
+
f"Can't fetch {self._source} {range(start, stop, step)}: {e}"
|
|
333
|
+
) from e
|
|
334
|
+
except ValueError as e:
|
|
335
|
+
# Frame source has no associated memory buffer (raw_frame)
|
|
336
|
+
raise IndexNoMoreThereError(
|
|
337
|
+
f"Can't fetch {self._source}: no associated live data"
|
|
338
|
+
) from e
|
|
339
|
+
|
|
340
|
+
return np.asarray(frames)
|
|
341
|
+
|
|
342
|
+
def _fetch_from_disk(
|
|
343
|
+
self, filepath: str, datapath: str, start: int, stop: int, step: int
|
|
344
|
+
) -> np.ndarray:
|
|
345
|
+
"""Get frame data from a file (i.e. "offline")."""
|
|
346
|
+
_logger.info(
|
|
347
|
+
f"Fetching {self._source} {start}:{stop}:{step} from disk via {filepath}"
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
with dynamic_hdf5.File(filepath, retry_timeout=10, retry_period=1) as file:
|
|
351
|
+
return file[datapath][start:stop:step]
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
# This file is part of the bliss project
|
|
4
|
+
#
|
|
5
|
+
# Copyright (c) Beamline Control Unit, ESRF
|
|
6
|
+
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
7
|
+
|
|
8
|
+
"""Unit test suite for Lima2 stream and view (streams/lima2.py)."""
|
|
9
|
+
|
|
10
|
+
from types import SimpleNamespace
|
|
11
|
+
from unittest.mock import MagicMock, Mock, call
|
|
12
|
+
from uuid import uuid1
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
import pytest
|
|
16
|
+
from blissdata.exceptions import (
|
|
17
|
+
EmptyViewException,
|
|
18
|
+
IndexNoMoreThereError,
|
|
19
|
+
IndexNotYetThereError,
|
|
20
|
+
IndexWontBeThereError,
|
|
21
|
+
)
|
|
22
|
+
from blissdata.lima.image_utils import ImageData
|
|
23
|
+
from blissdata.streams import EventRange, EventStream
|
|
24
|
+
from lima2.common.devencoded.sparse_frame import SparseFrame
|
|
25
|
+
|
|
26
|
+
from blissdata_lima2 import Lima2Stream, Lima2View
|
|
27
|
+
from blissdata_lima2.stream import get_frame
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.fixture
|
|
31
|
+
def mock_handshake(monkeypatch):
|
|
32
|
+
def mock_handshake(self):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
monkeypatch.setattr(
|
|
36
|
+
"lima2.client.services.ConductorServices.handshake", mock_handshake
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_lima2_get_frame():
|
|
41
|
+
services = Mock()
|
|
42
|
+
uuid = str(uuid1())
|
|
43
|
+
frm = get_frame(services=services, acq_uuid=uuid, source="cafe", frame_idx=123)
|
|
44
|
+
services.pipeline.get_frame.assert_called_with(
|
|
45
|
+
frame_idx=123, source="cafe", uuid=uuid
|
|
46
|
+
)
|
|
47
|
+
assert type(frm) is ImageData
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_lima2_get_sparse_frame():
|
|
51
|
+
mock_frame = Mock(spec=SparseFrame)
|
|
52
|
+
|
|
53
|
+
def mock_pipeline_get_frame(frame_idx, source, uuid):
|
|
54
|
+
return mock_frame
|
|
55
|
+
|
|
56
|
+
mock_services = SimpleNamespace(
|
|
57
|
+
pipeline=SimpleNamespace(get_frame=mock_pipeline_get_frame)
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
uuid = str(uuid1())
|
|
61
|
+
img_data = get_frame(
|
|
62
|
+
services=mock_services, acq_uuid=uuid, source="cafe", frame_idx=123
|
|
63
|
+
)
|
|
64
|
+
mock_frame.densify.assert_called_once()
|
|
65
|
+
assert type(img_data) is ImageData
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def test_lima2_view(monkeypatch):
|
|
69
|
+
services = Mock()
|
|
70
|
+
uuid = str(uuid1())
|
|
71
|
+
view = Lima2View(
|
|
72
|
+
services=services,
|
|
73
|
+
acq_uuid=uuid,
|
|
74
|
+
source="cafe",
|
|
75
|
+
start=0,
|
|
76
|
+
stop=42,
|
|
77
|
+
)
|
|
78
|
+
assert len(view) == 42
|
|
79
|
+
assert view.index == 0
|
|
80
|
+
|
|
81
|
+
frames = view.get_data()
|
|
82
|
+
assert len(frames) == len(view)
|
|
83
|
+
|
|
84
|
+
services.pipeline.get_frame.assert_has_calls(
|
|
85
|
+
[call(uuid=uuid, source="cafe", frame_idx=i) for i in range(42)]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# RuntimeError
|
|
89
|
+
def mock_get_frame_runtime_error(services, acq_uuid, source, frame_idx):
|
|
90
|
+
raise RuntimeError("frame has left the buffer")
|
|
91
|
+
|
|
92
|
+
monkeypatch.setattr(
|
|
93
|
+
"blissdata_lima2.stream.get_frame", mock_get_frame_runtime_error
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
with pytest.raises(IndexNoMoreThereError):
|
|
97
|
+
frames = view.get_data()
|
|
98
|
+
|
|
99
|
+
# ValueError
|
|
100
|
+
def mock_get_frame_value_error(services, acq_uuid, source, frame_idx):
|
|
101
|
+
raise ValueError("no such frame buffer")
|
|
102
|
+
|
|
103
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame_value_error)
|
|
104
|
+
|
|
105
|
+
with pytest.raises(IndexNoMoreThereError):
|
|
106
|
+
frames = view.get_data()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_lima2_protocol(data_store):
|
|
110
|
+
uuid = str(uuid1())
|
|
111
|
+
|
|
112
|
+
stream_def = Lima2Stream.make_definition(
|
|
113
|
+
name="device:cafe",
|
|
114
|
+
source_name="cafe",
|
|
115
|
+
conductor_hostname="www.lima2.org",
|
|
116
|
+
conductor_port=12345,
|
|
117
|
+
acq_uuid=uuid,
|
|
118
|
+
master_file=None,
|
|
119
|
+
dtype=np.float128, # fat pixels >:)
|
|
120
|
+
shape=(4, 1024, 512),
|
|
121
|
+
)
|
|
122
|
+
model = data_store._stream_model(
|
|
123
|
+
encoding=stream_def.encoder.info(), info=stream_def.info
|
|
124
|
+
)
|
|
125
|
+
model.info["protocol_version"] = 1 # hack the protocol number
|
|
126
|
+
event_stream = EventStream.create(data_store, stream_def.name, model)
|
|
127
|
+
|
|
128
|
+
with pytest.raises(RuntimeError):
|
|
129
|
+
_ = Lima2Stream(event_stream=event_stream)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@pytest.fixture
|
|
133
|
+
def lima2_stream(data_store, mock_handshake):
|
|
134
|
+
uuid = str(uuid1())
|
|
135
|
+
|
|
136
|
+
stream_def = Lima2Stream.make_definition(
|
|
137
|
+
name="device:cafe",
|
|
138
|
+
source_name="cafe",
|
|
139
|
+
conductor_hostname="www.lima2.org",
|
|
140
|
+
conductor_port=12345,
|
|
141
|
+
acq_uuid=uuid,
|
|
142
|
+
master_file=None,
|
|
143
|
+
dtype=np.float128, # fat pixels >:)
|
|
144
|
+
shape=(4, 1024, 512),
|
|
145
|
+
)
|
|
146
|
+
model = data_store._stream_model(
|
|
147
|
+
encoding=stream_def.encoder.info(), info=stream_def.info
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
event_stream = EventStream.create(data_store, stream_def.name, model)
|
|
151
|
+
stream = Lima2Stream(event_stream=event_stream)
|
|
152
|
+
|
|
153
|
+
return (stream_def, event_stream, stream)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_lima2_stream_attributes(lima2_stream):
|
|
157
|
+
stream_def, event_stream, stream = lima2_stream
|
|
158
|
+
|
|
159
|
+
assert stream.plugin == "lima2"
|
|
160
|
+
assert stream.shape == stream_def.info["shape"]
|
|
161
|
+
assert stream.kind == "array"
|
|
162
|
+
assert stream.dtype == stream._dtype
|
|
163
|
+
assert stream._need_last_only(last_only=True)
|
|
164
|
+
assert stream._need_last_only(last_only=False)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_lima2_stream_indexing(lima2_stream, monkeypatch):
|
|
168
|
+
stream_def, event_stream, stream = lima2_stream
|
|
169
|
+
|
|
170
|
+
# Feed the event stream
|
|
171
|
+
event_stream.send(np.uint32(42))
|
|
172
|
+
event_stream.join()
|
|
173
|
+
assert len(stream) == 42
|
|
174
|
+
|
|
175
|
+
event_stream.send(np.uint32(123))
|
|
176
|
+
event_stream.join()
|
|
177
|
+
assert len(stream) == 123
|
|
178
|
+
|
|
179
|
+
mock_get_frame = Mock()
|
|
180
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
181
|
+
|
|
182
|
+
# Indexing
|
|
183
|
+
_ = stream[0]
|
|
184
|
+
mock_get_frame.assert_called_with(
|
|
185
|
+
services=stream._services,
|
|
186
|
+
acq_uuid=stream._acq_uuid,
|
|
187
|
+
source="cafe",
|
|
188
|
+
frame_idx=0,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
with pytest.raises(IndexNotYetThereError):
|
|
192
|
+
_ = stream[-1]
|
|
193
|
+
|
|
194
|
+
with pytest.raises(IndexNotYetThereError):
|
|
195
|
+
_ = stream[123123] # wayyy out of bounds, but we're not sealed yet
|
|
196
|
+
|
|
197
|
+
with monkeypatch.context() as mpc:
|
|
198
|
+
mpc.setattr(stream, "is_sealed", lambda: True)
|
|
199
|
+
|
|
200
|
+
with pytest.raises(IndexWontBeThereError):
|
|
201
|
+
_ = stream[123123] # wayyy out of bounds and we're sealed
|
|
202
|
+
|
|
203
|
+
event_stream.seal()
|
|
204
|
+
event_stream.join()
|
|
205
|
+
|
|
206
|
+
_ = stream[-3]
|
|
207
|
+
assert mock_get_frame.mock_calls[-1] == call(
|
|
208
|
+
services=stream._services,
|
|
209
|
+
acq_uuid=stream._acq_uuid,
|
|
210
|
+
source="cafe",
|
|
211
|
+
frame_idx=123 - 3,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_lima2_stream_slicing(lima2_stream, monkeypatch):
|
|
216
|
+
stream_def, event_stream, stream = lima2_stream
|
|
217
|
+
|
|
218
|
+
# Feed the event stream
|
|
219
|
+
event_stream.send(np.uint32(42))
|
|
220
|
+
event_stream.join()
|
|
221
|
+
assert len(stream) == 42
|
|
222
|
+
|
|
223
|
+
event_stream.send(np.uint32(123))
|
|
224
|
+
event_stream.join()
|
|
225
|
+
assert len(stream) == 123
|
|
226
|
+
|
|
227
|
+
mock_get_frame = Mock()
|
|
228
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
229
|
+
|
|
230
|
+
# Slicing
|
|
231
|
+
_ = stream[:3]
|
|
232
|
+
assert mock_get_frame.mock_calls[-3:] == [
|
|
233
|
+
call(
|
|
234
|
+
services=stream._services,
|
|
235
|
+
acq_uuid=stream._acq_uuid,
|
|
236
|
+
source="cafe",
|
|
237
|
+
frame_idx=0,
|
|
238
|
+
),
|
|
239
|
+
call(
|
|
240
|
+
services=stream._services,
|
|
241
|
+
acq_uuid=stream._acq_uuid,
|
|
242
|
+
source="cafe",
|
|
243
|
+
frame_idx=1,
|
|
244
|
+
),
|
|
245
|
+
call(
|
|
246
|
+
services=stream._services,
|
|
247
|
+
acq_uuid=stream._acq_uuid,
|
|
248
|
+
source="cafe",
|
|
249
|
+
frame_idx=2,
|
|
250
|
+
),
|
|
251
|
+
]
|
|
252
|
+
|
|
253
|
+
with pytest.raises(IndexNotYetThereError):
|
|
254
|
+
_ = stream[-2:]
|
|
255
|
+
|
|
256
|
+
with pytest.raises(IndexNotYetThereError):
|
|
257
|
+
_ = stream[:-2]
|
|
258
|
+
|
|
259
|
+
with pytest.raises(TypeError):
|
|
260
|
+
_ = stream["hi :)"]
|
|
261
|
+
|
|
262
|
+
event_stream.seal()
|
|
263
|
+
event_stream.join()
|
|
264
|
+
|
|
265
|
+
# Now slicing/indexing from end is ok
|
|
266
|
+
_ = stream[-2:]
|
|
267
|
+
assert mock_get_frame.mock_calls[-2:] == [
|
|
268
|
+
call(
|
|
269
|
+
services=stream._services,
|
|
270
|
+
acq_uuid=stream._acq_uuid,
|
|
271
|
+
source="cafe",
|
|
272
|
+
frame_idx=123 - 2,
|
|
273
|
+
),
|
|
274
|
+
call(
|
|
275
|
+
services=stream._services,
|
|
276
|
+
acq_uuid=stream._acq_uuid,
|
|
277
|
+
source="cafe",
|
|
278
|
+
frame_idx=123 - 1,
|
|
279
|
+
),
|
|
280
|
+
]
|
|
281
|
+
|
|
282
|
+
_ = stream[:]
|
|
283
|
+
assert mock_get_frame.mock_calls[-123:] == [
|
|
284
|
+
call(
|
|
285
|
+
services=stream._services,
|
|
286
|
+
acq_uuid=stream._acq_uuid,
|
|
287
|
+
source="cafe",
|
|
288
|
+
frame_idx=i,
|
|
289
|
+
)
|
|
290
|
+
for i in range(123)
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
_ = stream.get_last_live_image()
|
|
294
|
+
mock_get_frame.assert_called_with(
|
|
295
|
+
services=stream._services,
|
|
296
|
+
acq_uuid=stream._acq_uuid,
|
|
297
|
+
source="cafe",
|
|
298
|
+
frame_idx=-1,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def test_lima2_stream_build_view(lima2_stream, monkeypatch):
|
|
303
|
+
stream_def, event_stream, stream = lima2_stream
|
|
304
|
+
|
|
305
|
+
mock_get_frame = Mock()
|
|
306
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
307
|
+
|
|
308
|
+
view = stream._build_view_from_events(
|
|
309
|
+
index=0,
|
|
310
|
+
events=EventRange(
|
|
311
|
+
index=0,
|
|
312
|
+
nb_expired=0,
|
|
313
|
+
data=[np.uint32(5), np.uint32(24), np.uint32(42)],
|
|
314
|
+
end_of_stream=False,
|
|
315
|
+
),
|
|
316
|
+
last_only=False,
|
|
317
|
+
)
|
|
318
|
+
assert view._idx_range == range(0, 42)
|
|
319
|
+
|
|
320
|
+
view = stream._build_view_from_events(
|
|
321
|
+
index=0,
|
|
322
|
+
events=EventRange(
|
|
323
|
+
index=0,
|
|
324
|
+
nb_expired=0,
|
|
325
|
+
data=[np.uint32(5), np.uint32(24), np.uint32(42)],
|
|
326
|
+
end_of_stream=False,
|
|
327
|
+
),
|
|
328
|
+
last_only=True,
|
|
329
|
+
)
|
|
330
|
+
assert view._idx_range == range(41, 42)
|
|
331
|
+
|
|
332
|
+
with pytest.raises(EmptyViewException):
|
|
333
|
+
# index >= data[-1]
|
|
334
|
+
view = stream._build_view_from_events(
|
|
335
|
+
index=42,
|
|
336
|
+
events=EventRange(
|
|
337
|
+
index=0,
|
|
338
|
+
nb_expired=0,
|
|
339
|
+
data=[np.uint32(5), np.uint32(24), np.uint32(42)],
|
|
340
|
+
end_of_stream=False,
|
|
341
|
+
),
|
|
342
|
+
last_only=False,
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def test_lima2_stream_fetch_frames(lima2_stream, monkeypatch):
|
|
347
|
+
stream_def, event_stream, stream = lima2_stream
|
|
348
|
+
|
|
349
|
+
mock_get_frame = Mock()
|
|
350
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
351
|
+
|
|
352
|
+
with monkeypatch.context() as mpc:
|
|
353
|
+
# Stream sealed, has master file
|
|
354
|
+
mock_fetch = Mock()
|
|
355
|
+
mpc.setattr(stream, "_fetch_from_disk", mock_fetch)
|
|
356
|
+
mpc.setattr(stream, "is_sealed", lambda: True)
|
|
357
|
+
mpc.setattr(
|
|
358
|
+
stream,
|
|
359
|
+
"_master_file",
|
|
360
|
+
("/path/to/master.h5", "entry/instrument/detector/dataset"),
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
stream._fetch_frames(start=0, stop=42, step=3)
|
|
364
|
+
|
|
365
|
+
mock_fetch.assert_called_once_with(
|
|
366
|
+
filepath="/path/to/master.h5",
|
|
367
|
+
datapath="entry/instrument/detector/dataset",
|
|
368
|
+
start=0,
|
|
369
|
+
stop=42,
|
|
370
|
+
step=3,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
with monkeypatch.context() as mpc:
|
|
374
|
+
# Stream sealed, no master file
|
|
375
|
+
mock_fetch = Mock()
|
|
376
|
+
mpc.setattr(stream, "_fetch_online", mock_fetch)
|
|
377
|
+
mpc.setattr(stream, "is_sealed", lambda: True)
|
|
378
|
+
mpc.setattr(stream, "_master_file", None)
|
|
379
|
+
|
|
380
|
+
stream._fetch_frames(start=0, stop=42, step=3)
|
|
381
|
+
|
|
382
|
+
mock_fetch.assert_called_once_with(
|
|
383
|
+
start=0,
|
|
384
|
+
stop=42,
|
|
385
|
+
step=3,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
with monkeypatch.context() as mpc:
|
|
389
|
+
# Stream not sealed
|
|
390
|
+
mock_fetch = Mock()
|
|
391
|
+
mpc.setattr(stream, "_fetch_online", mock_fetch)
|
|
392
|
+
mpc.setattr(stream, "is_sealed", lambda: False)
|
|
393
|
+
|
|
394
|
+
stream._fetch_frames(start=0, stop=42, step=3)
|
|
395
|
+
|
|
396
|
+
mock_fetch.assert_called_once_with(
|
|
397
|
+
start=0,
|
|
398
|
+
stop=42,
|
|
399
|
+
step=3,
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def test_lima2_stream_fetch_online(lima2_stream, monkeypatch):
|
|
404
|
+
stream_def, event_stream, stream = lima2_stream
|
|
405
|
+
|
|
406
|
+
mock_get_frame = Mock()
|
|
407
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
408
|
+
|
|
409
|
+
stream._fetch_online(start=0, stop=42, step=3)
|
|
410
|
+
|
|
411
|
+
mock_get_frame.assert_has_calls(
|
|
412
|
+
[
|
|
413
|
+
call(
|
|
414
|
+
services=stream._services,
|
|
415
|
+
acq_uuid=stream._acq_uuid,
|
|
416
|
+
source=stream._source,
|
|
417
|
+
frame_idx=idx,
|
|
418
|
+
)
|
|
419
|
+
for idx in range(0, 42, 3)
|
|
420
|
+
]
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
# RuntimeError
|
|
424
|
+
def mock_get_frame_runtime_error(services, acq_uuid, source, frame_idx):
|
|
425
|
+
raise RuntimeError("oh no :(")
|
|
426
|
+
|
|
427
|
+
monkeypatch.setattr(
|
|
428
|
+
"blissdata_lima2.stream.get_frame", mock_get_frame_runtime_error
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
with pytest.raises(IndexNoMoreThereError):
|
|
432
|
+
_ = stream._fetch_online(start=0, stop=1, step=1)
|
|
433
|
+
|
|
434
|
+
# ValueError
|
|
435
|
+
def mock_get_frame_value_error(services, acq_uuid, source, frame_idx):
|
|
436
|
+
raise ValueError("oh no :(")
|
|
437
|
+
|
|
438
|
+
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame_value_error)
|
|
439
|
+
|
|
440
|
+
with pytest.raises(IndexNoMoreThereError):
|
|
441
|
+
_ = stream._fetch_online(start=0, stop=1, step=1)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def test_lima2_stream_fetch_offline(lima2_stream, monkeypatch):
|
|
445
|
+
stream_def, event_stream, stream = lima2_stream
|
|
446
|
+
|
|
447
|
+
mock_dynamic_hdf5 = MagicMock()
|
|
448
|
+
monkeypatch.setattr("blissdata_lima2.stream.dynamic_hdf5", mock_dynamic_hdf5)
|
|
449
|
+
|
|
450
|
+
stream._fetch_from_disk(
|
|
451
|
+
filepath="/path/to/master.h5",
|
|
452
|
+
datapath="entry/instrument/detector/dataset",
|
|
453
|
+
start=0,
|
|
454
|
+
stop=42,
|
|
455
|
+
step=3,
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
mock_dynamic_hdf5.File.assert_called_once()
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: blissdata-lima2
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: Lima2 plugin for blissdata
|
|
5
5
|
Maintainer: BCU (ESRF)
|
|
6
6
|
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://gitlab.esrf.fr/bliss/blissdata-lima2
|
|
7
8
|
Keywords: blissdata,lima2
|
|
8
9
|
Classifier: Intended Audience :: Science/Research
|
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -11,11 +12,13 @@ Requires-Python: >=3.10
|
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
License-File: LICENSE.md
|
|
13
14
|
Requires-Dist: blissdata~=2.3
|
|
14
|
-
Requires-Dist: lima2-client~=4.
|
|
15
|
+
Requires-Dist: lima2-client~=4.1
|
|
15
16
|
Provides-Extra: dev
|
|
16
17
|
Requires-Dist: black; extra == "dev"
|
|
17
18
|
Requires-Dist: flake8; extra == "dev"
|
|
19
|
+
Requires-Dist: mypy; extra == "dev"
|
|
18
20
|
Requires-Dist: pytest; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
19
22
|
Requires-Dist: pytest-redis; extra == "dev"
|
|
20
23
|
Dynamic: license-file
|
|
21
24
|
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
#
|
|
3
|
-
# This file is part of the bliss project
|
|
4
|
-
#
|
|
5
|
-
# Copyright (c) Beamline Control Unit, ESRF
|
|
6
|
-
# Distributed under the GNU LGPLv3. See LICENSE for more info.
|
|
7
|
-
|
|
8
|
-
"""Unit test suite for Lima2 stream and view (streams/lima2.py)."""
|
|
9
|
-
|
|
10
|
-
from unittest.mock import Mock, call
|
|
11
|
-
from uuid import uuid1
|
|
12
|
-
|
|
13
|
-
import numpy as np
|
|
14
|
-
import pytest
|
|
15
|
-
from blissdata.exceptions import IndexNotYetThereError
|
|
16
|
-
from blissdata.lima.image_utils import ImageData
|
|
17
|
-
from blissdata.streams import EventStream
|
|
18
|
-
|
|
19
|
-
from blissdata_lima2 import Lima2Stream, Lima2View
|
|
20
|
-
from blissdata_lima2.stream import get_frame
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def test_lima2_get_frame():
|
|
24
|
-
services = Mock()
|
|
25
|
-
uuid = str(uuid1())
|
|
26
|
-
frm = get_frame(services=services, acq_uuid=uuid, source="cafe", frame_idx=123)
|
|
27
|
-
services.pipeline.get_frame.assert_called_with(
|
|
28
|
-
frame_idx=123, source="cafe", uuid=uuid
|
|
29
|
-
)
|
|
30
|
-
assert type(frm) is ImageData
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def test_lima2_view():
|
|
34
|
-
services = Mock()
|
|
35
|
-
uuid = str(uuid1())
|
|
36
|
-
view = Lima2View(
|
|
37
|
-
services=services,
|
|
38
|
-
acq_uuid=uuid,
|
|
39
|
-
source="cafe",
|
|
40
|
-
start=0,
|
|
41
|
-
stop=42,
|
|
42
|
-
)
|
|
43
|
-
assert len(view) == 42
|
|
44
|
-
assert view.index == 0
|
|
45
|
-
|
|
46
|
-
frames = view.get_data()
|
|
47
|
-
assert len(frames) == len(view)
|
|
48
|
-
|
|
49
|
-
services.pipeline.get_frame.assert_has_calls(
|
|
50
|
-
[call(uuid=uuid, source="cafe", frame_idx=i) for i in range(42)]
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def test_lima2_protocol(data_store):
|
|
55
|
-
uuid = str(uuid1())
|
|
56
|
-
|
|
57
|
-
stream_def = Lima2Stream.make_definition(
|
|
58
|
-
name="device:cafe",
|
|
59
|
-
source_name="cafe",
|
|
60
|
-
conductor_hostname="www.lima2.org",
|
|
61
|
-
conductor_port=12345,
|
|
62
|
-
acq_uuid=uuid,
|
|
63
|
-
master_file=None,
|
|
64
|
-
dtype=np.float128, # fat pixels >:)
|
|
65
|
-
shape=(4, 1024, 512),
|
|
66
|
-
)
|
|
67
|
-
model = data_store._stream_model(
|
|
68
|
-
encoding=stream_def.encoder.info(), info=stream_def.info
|
|
69
|
-
)
|
|
70
|
-
model.info["protocol_version"] = 1 # hack the protocol number
|
|
71
|
-
event_stream = EventStream.create(data_store, stream_def.name, model)
|
|
72
|
-
|
|
73
|
-
with pytest.raises(RuntimeError):
|
|
74
|
-
_ = Lima2Stream(event_stream=event_stream)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def test_lima2_stream(data_store, monkeypatch):
|
|
78
|
-
uuid = str(uuid1())
|
|
79
|
-
|
|
80
|
-
stream_def = Lima2Stream.make_definition(
|
|
81
|
-
name="device:cafe",
|
|
82
|
-
source_name="cafe",
|
|
83
|
-
conductor_hostname="www.lima2.org",
|
|
84
|
-
conductor_port=12345,
|
|
85
|
-
acq_uuid=uuid,
|
|
86
|
-
master_file=None,
|
|
87
|
-
dtype=np.float128, # fat pixels >:)
|
|
88
|
-
shape=(4, 1024, 512),
|
|
89
|
-
)
|
|
90
|
-
model = data_store._stream_model(
|
|
91
|
-
encoding=stream_def.encoder.info(), info=stream_def.info
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
event_stream = EventStream.create(data_store, stream_def.name, model)
|
|
95
|
-
stream = Lima2Stream(event_stream=event_stream)
|
|
96
|
-
|
|
97
|
-
assert stream.plugin == "lima2"
|
|
98
|
-
assert stream.shape == stream_def.info["shape"]
|
|
99
|
-
|
|
100
|
-
# Feed the event stream
|
|
101
|
-
event_stream.send(np.uint32(42))
|
|
102
|
-
event_stream.join()
|
|
103
|
-
assert len(stream) == 42
|
|
104
|
-
|
|
105
|
-
event_stream.send(np.uint32(123))
|
|
106
|
-
event_stream.join()
|
|
107
|
-
assert len(stream) == 123
|
|
108
|
-
|
|
109
|
-
mock_get_frame = Mock()
|
|
110
|
-
monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
|
|
111
|
-
|
|
112
|
-
# Indexing
|
|
113
|
-
_ = stream[0]
|
|
114
|
-
mock_get_frame.assert_called_with(
|
|
115
|
-
services=stream._services,
|
|
116
|
-
acq_uuid=uuid,
|
|
117
|
-
source="cafe",
|
|
118
|
-
frame_idx=0,
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
with pytest.raises(IndexNotYetThereError):
|
|
122
|
-
_ = stream[-1]
|
|
123
|
-
|
|
124
|
-
# Slicing
|
|
125
|
-
_ = stream[:3]
|
|
126
|
-
assert mock_get_frame.mock_calls[-3:] == [
|
|
127
|
-
call(services=stream._services, acq_uuid=uuid, source="cafe", frame_idx=0),
|
|
128
|
-
call(services=stream._services, acq_uuid=uuid, source="cafe", frame_idx=1),
|
|
129
|
-
call(services=stream._services, acq_uuid=uuid, source="cafe", frame_idx=2),
|
|
130
|
-
]
|
|
131
|
-
|
|
132
|
-
with pytest.raises(IndexNotYetThereError):
|
|
133
|
-
_ = stream[-2:]
|
|
134
|
-
|
|
135
|
-
with pytest.raises(IndexNotYetThereError):
|
|
136
|
-
_ = stream[:-2]
|
|
137
|
-
|
|
138
|
-
event_stream.seal()
|
|
139
|
-
event_stream.join()
|
|
140
|
-
|
|
141
|
-
# Now slicing/indexing from end is ok
|
|
142
|
-
_ = stream[-2:]
|
|
143
|
-
assert mock_get_frame.mock_calls[-2:] == [
|
|
144
|
-
call(
|
|
145
|
-
services=stream._services,
|
|
146
|
-
acq_uuid=uuid,
|
|
147
|
-
source="cafe",
|
|
148
|
-
frame_idx=123 - 2,
|
|
149
|
-
),
|
|
150
|
-
call(
|
|
151
|
-
services=stream._services,
|
|
152
|
-
acq_uuid=uuid,
|
|
153
|
-
source="cafe",
|
|
154
|
-
frame_idx=123 - 1,
|
|
155
|
-
),
|
|
156
|
-
]
|
|
157
|
-
|
|
158
|
-
_ = stream[-3]
|
|
159
|
-
assert mock_get_frame.mock_calls[-1] == call(
|
|
160
|
-
services=stream._services,
|
|
161
|
-
acq_uuid=uuid,
|
|
162
|
-
source="cafe",
|
|
163
|
-
frame_idx=123 - 3,
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
_ = stream[:]
|
|
167
|
-
assert mock_get_frame.mock_calls[-123:] == [
|
|
168
|
-
call(services=stream._services, acq_uuid=uuid, source="cafe", frame_idx=i)
|
|
169
|
-
for i in range(123)
|
|
170
|
-
]
|
|
171
|
-
|
|
172
|
-
_ = stream.get_last_live_image()
|
|
173
|
-
mock_get_frame.assert_called_with(
|
|
174
|
-
services=stream._services,
|
|
175
|
-
acq_uuid=uuid,
|
|
176
|
-
source="cafe",
|
|
177
|
-
frame_idx=-1,
|
|
178
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{blissdata_lima2-2.0 → blissdata_lima2-2.0.2}/src/blissdata_lima2.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|