blissdata-lima2 2.0.2__tar.gz → 2.0.3__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blissdata-lima2
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: Lima2 plugin for blissdata
5
5
  Maintainer: BCU (ESRF)
6
6
  License-Expression: MIT
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3
11
11
  Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: blissdata~=2.3
14
+ Requires-Dist: blissdata~=2.4
15
15
  Requires-Dist: lima2-client~=4.1
16
16
  Provides-Extra: dev
17
17
  Requires-Dist: black; extra == "dev"
@@ -0,0 +1,70 @@
1
+ [build-system]
2
+ requires = ["setuptools"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "blissdata-lima2"
7
+ version = "2.0.3"
8
+ description = "Lima2 plugin for blissdata"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE.md"]
12
+ maintainers = [{ name = "BCU (ESRF)" }]
13
+ classifiers = [
14
+ "Intended Audience :: Science/Research",
15
+ "Programming Language :: Python :: 3",
16
+ ]
17
+ keywords = ["blissdata", "lima2"]
18
+ requires-python = ">=3.10"
19
+ dependencies = ["blissdata~=2.4", "lima2-client~=4.1"]
20
+
21
+ [project.urls]
22
+ Repository = "https://gitlab.esrf.fr/bliss/blissdata-lima2"
23
+
24
+ [project.optional-dependencies]
25
+ dev = ["black", "flake8", "mypy", "pytest", "pytest-cov", "pytest-redis"]
26
+
27
+ [project.entry-points.blissdata]
28
+ lima2 = "blissdata_lima2"
29
+
30
+ [tool.pixi.workspace]
31
+ channels = ["conda-forge", "esrf-bcu"]
32
+ platforms = ["linux-64"]
33
+
34
+ [tool.pixi.dependencies]
35
+ python = ">=3.10,<3.15"
36
+
37
+ [tool.pixi.pypi-dependencies]
38
+ blissdata-lima2 = { path = ".", editable = true }
39
+
40
+ [tool.pixi.environments]
41
+ default = { solve-group = "default" }
42
+ test = { features = ["test"], solve-group = "default" }
43
+ dev = { features = ["dev"], no-default-feature = true }
44
+ build = { features = ["build"], no-default-feature = true }
45
+
46
+ [dependency-groups]
47
+ test = ["blissdata-lima2[dev]"]
48
+ build = ["build"]
49
+
50
+ [tool.pixi.feature.test.dependencies]
51
+ redis-server = "7.*"
52
+ redisearch = ">=2.6.5"
53
+ redisjson = ">=2.4.5"
54
+
55
+ [tool.pixi.feature.test.tasks]
56
+ test = { cmd = "pytest -v", description = "Run tests" }
57
+
58
+ [tool.pixi.feature.dev.dependencies]
59
+ python = ">=3.10"
60
+
61
+ [tool.pixi.feature.dev.tasks]
62
+ style = { cmd = "black . --check", description = "Check the style of the source code" }
63
+ fix-style = { cmd = "black .", description = "Fixes the style of the source code" }
64
+ lint = { cmd = "flake8", description = "Check the linting" }
65
+
66
+ [tool.pixi.feature.build.dependencies]
67
+ python = ">=3.10"
68
+
69
+ [tool.pixi.feature.build.tasks]
70
+ build = { cmd = "python -m build .", description = "Build packages" }
@@ -10,6 +10,7 @@ from collections.abc import Sequence
10
10
 
11
11
  import lima2.client.services as l2s
12
12
  import numpy as np
13
+ from functools import cached_property
13
14
  from blissdata.exceptions import (
14
15
  EmptyViewException,
15
16
  EndOfStream,
@@ -52,18 +53,12 @@ def get_frame(
52
53
  class Lima2View(BaseView):
53
54
  def __init__(
54
55
  self,
55
- services: l2s.ConductorServices,
56
- acq_uuid: str,
57
- source: str,
56
+ stream: Lima2Stream,
58
57
  start: int,
59
58
  stop: int,
60
59
  ) -> None:
61
- self._services = services
62
- """Lima2 client services."""
63
- self._acq_uuid = acq_uuid
64
- """Lima2 acquisition id."""
65
- self._source = source
66
- """Frame source name."""
60
+ self._stream = stream
61
+ """Lima2 stream."""
67
62
  self._idx_range = range(start, stop)
68
63
  """Range of absolute frame indices accessible via this view."""
69
64
 
@@ -75,29 +70,10 @@ class Lima2View(BaseView):
75
70
  return len(self._idx_range)
76
71
 
77
72
  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
88
- )
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)
73
+ stream_range = self._idx_range[start:stop]
74
+ return self._stream._fetch_online(
75
+ stream_range.start, stream_range.stop, stream_range.step
76
+ )
101
77
 
102
78
 
103
79
  class Lima2Stream(BaseStream, LimaDirectAccess):
@@ -130,23 +106,25 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
130
106
  self._source = str(event_stream.info["source_name"])
131
107
  self._master_file: tuple[str, str] | None = event_stream.info["master_file"]
132
108
 
133
- self._services = l2s.init(
134
- hostname=str(event_stream.info["conductor_hostname"]),
135
- port=int(event_stream.info["conductor_port"]),
136
- )
137
- """Lima2 client session."""
138
-
139
109
  self._length = 0
140
110
  """Current number of accessible frames."""
141
111
 
142
112
  self._cursor = Stream(event_stream).cursor()
143
113
 
144
- self._services.handshake()
145
-
146
114
  ####################################################################################
147
115
  # BaseStream
148
116
  ####################################################################################
149
117
 
118
+ @cached_property
119
+ def _services(self):
120
+ """Lima2 client session."""
121
+ services = l2s.init(
122
+ hostname=str(self._event_stream.info["conductor_hostname"]),
123
+ port=int(self._event_stream.info["conductor_port"]),
124
+ )
125
+ services.handshake()
126
+ return services
127
+
150
128
  @property
151
129
  def kind(self) -> str:
152
130
  return "array"
@@ -262,9 +240,7 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
262
240
  raise EmptyViewException
263
241
 
264
242
  return Lima2View(
265
- services=self._services,
266
- acq_uuid=self._acq_uuid,
267
- source=self._source,
243
+ stream=self,
268
244
  start=stop_idx - 1 if last_only else index,
269
245
  stop=stop_idx,
270
246
  )
@@ -337,7 +313,7 @@ class Lima2Stream(BaseStream, LimaDirectAccess):
337
313
  f"Can't fetch {self._source}: no associated live data"
338
314
  ) from e
339
315
 
340
- return np.asarray(frames)
316
+ return np.asarray(frames).reshape(-1, *self.shape)
341
317
 
342
318
  def _fetch_from_disk(
343
319
  self, filepath: str, datapath: str, start: int, stop: int, step: int
@@ -66,45 +66,23 @@ def test_lima2_get_sparse_frame():
66
66
 
67
67
 
68
68
  def test_lima2_view(monkeypatch):
69
- services = Mock()
70
- uuid = str(uuid1())
69
+ stream = Mock()
71
70
  view = Lima2View(
72
- services=services,
73
- acq_uuid=uuid,
74
- source="cafe",
71
+ stream=stream,
75
72
  start=0,
76
73
  stop=42,
77
74
  )
78
75
  assert len(view) == 42
79
76
  assert view.index == 0
80
77
 
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")
78
+ _ = view.get_data()
91
79
 
92
- monkeypatch.setattr(
93
- "blissdata_lima2.stream.get_frame", mock_get_frame_runtime_error
80
+ stream._fetch_online.assert_has_calls(
81
+ [
82
+ call(0, 42, 1),
83
+ ]
94
84
  )
95
85
 
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
86
 
109
87
  def test_lima2_protocol(data_store):
110
88
  uuid = str(uuid1())
@@ -141,7 +119,7 @@ def lima2_stream(data_store, mock_handshake):
141
119
  acq_uuid=uuid,
142
120
  master_file=None,
143
121
  dtype=np.float128, # fat pixels >:)
144
- shape=(4, 1024, 512),
122
+ shape=(),
145
123
  )
146
124
  model = data_store._stream_model(
147
125
  encoding=stream_def.encoder.info(), info=stream_def.info
@@ -150,162 +128,152 @@ def lima2_stream(data_store, mock_handshake):
150
128
  event_stream = EventStream.create(data_store, stream_def.name, model)
151
129
  stream = Lima2Stream(event_stream=event_stream)
152
130
 
153
- return (stream_def, event_stream, stream)
131
+ return stream
154
132
 
155
133
 
156
134
  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)
135
+ assert lima2_stream.plugin == "lima2"
136
+ assert lima2_stream.shape == lima2_stream.info["shape"]
137
+ assert lima2_stream.kind == "array"
138
+ assert lima2_stream.dtype == lima2_stream._dtype
139
+ assert lima2_stream._need_last_only(last_only=True)
140
+ assert lima2_stream._need_last_only(last_only=False)
165
141
 
166
142
 
167
143
  def test_lima2_stream_indexing(lima2_stream, monkeypatch):
168
- stream_def, event_stream, stream = lima2_stream
169
-
170
144
  # Feed the event stream
171
- event_stream.send(np.uint32(42))
172
- event_stream.join()
173
- assert len(stream) == 42
145
+ lima2_stream.send(np.uint32(42))
146
+ lima2_stream.join()
147
+ assert len(lima2_stream) == 42
174
148
 
175
- event_stream.send(np.uint32(123))
176
- event_stream.join()
177
- assert len(stream) == 123
149
+ lima2_stream.send(np.uint32(123))
150
+ lima2_stream.join()
151
+ assert len(lima2_stream) == 123
178
152
 
179
153
  mock_get_frame = Mock()
180
154
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
181
155
 
182
156
  # Indexing
183
- _ = stream[0]
157
+ _ = lima2_stream[0]
184
158
  mock_get_frame.assert_called_with(
185
- services=stream._services,
186
- acq_uuid=stream._acq_uuid,
159
+ services=lima2_stream._services,
160
+ acq_uuid=lima2_stream._acq_uuid,
187
161
  source="cafe",
188
162
  frame_idx=0,
189
163
  )
190
164
 
191
165
  with pytest.raises(IndexNotYetThereError):
192
- _ = stream[-1]
166
+ _ = lima2_stream[-1]
193
167
 
194
168
  with pytest.raises(IndexNotYetThereError):
195
- _ = stream[123123] # wayyy out of bounds, but we're not sealed yet
169
+ _ = lima2_stream[123123] # wayyy out of bounds, but we're not sealed yet
196
170
 
197
171
  with monkeypatch.context() as mpc:
198
- mpc.setattr(stream, "is_sealed", lambda: True)
172
+ mpc.setattr(lima2_stream, "is_sealed", lambda: True)
199
173
 
200
174
  with pytest.raises(IndexWontBeThereError):
201
- _ = stream[123123] # wayyy out of bounds and we're sealed
175
+ _ = lima2_stream[123123] # wayyy out of bounds and we're sealed
202
176
 
203
- event_stream.seal()
204
- event_stream.join()
177
+ lima2_stream.seal()
205
178
 
206
- _ = stream[-3]
179
+ _ = lima2_stream[-3]
207
180
  assert mock_get_frame.mock_calls[-1] == call(
208
- services=stream._services,
209
- acq_uuid=stream._acq_uuid,
181
+ services=lima2_stream._services,
182
+ acq_uuid=lima2_stream._acq_uuid,
210
183
  source="cafe",
211
184
  frame_idx=123 - 3,
212
185
  )
213
186
 
214
187
 
215
188
  def test_lima2_stream_slicing(lima2_stream, monkeypatch):
216
- stream_def, event_stream, stream = lima2_stream
189
+ # Feed the stream
190
+ lima2_stream.send(np.uint32(42))
191
+ lima2_stream.join()
192
+ assert len(lima2_stream) == 42
217
193
 
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
194
+ lima2_stream.send(np.uint32(123))
195
+ lima2_stream.join()
196
+ assert len(lima2_stream) == 123
226
197
 
227
198
  mock_get_frame = Mock()
228
199
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
229
200
 
230
201
  # Slicing
231
- _ = stream[:3]
202
+ _ = lima2_stream[:3]
232
203
  assert mock_get_frame.mock_calls[-3:] == [
233
204
  call(
234
- services=stream._services,
235
- acq_uuid=stream._acq_uuid,
205
+ services=lima2_stream._services,
206
+ acq_uuid=lima2_stream._acq_uuid,
236
207
  source="cafe",
237
208
  frame_idx=0,
238
209
  ),
239
210
  call(
240
- services=stream._services,
241
- acq_uuid=stream._acq_uuid,
211
+ services=lima2_stream._services,
212
+ acq_uuid=lima2_stream._acq_uuid,
242
213
  source="cafe",
243
214
  frame_idx=1,
244
215
  ),
245
216
  call(
246
- services=stream._services,
247
- acq_uuid=stream._acq_uuid,
217
+ services=lima2_stream._services,
218
+ acq_uuid=lima2_stream._acq_uuid,
248
219
  source="cafe",
249
220
  frame_idx=2,
250
221
  ),
251
222
  ]
252
223
 
253
224
  with pytest.raises(IndexNotYetThereError):
254
- _ = stream[-2:]
225
+ _ = lima2_stream[-2:]
255
226
 
256
227
  with pytest.raises(IndexNotYetThereError):
257
- _ = stream[:-2]
228
+ _ = lima2_stream[:-2]
258
229
 
259
230
  with pytest.raises(TypeError):
260
- _ = stream["hi :)"]
231
+ _ = lima2_stream["hi :)"]
261
232
 
262
- event_stream.seal()
263
- event_stream.join()
233
+ lima2_stream.seal()
264
234
 
265
235
  # Now slicing/indexing from end is ok
266
- _ = stream[-2:]
236
+ _ = lima2_stream[-2:]
267
237
  assert mock_get_frame.mock_calls[-2:] == [
268
238
  call(
269
- services=stream._services,
270
- acq_uuid=stream._acq_uuid,
239
+ services=lima2_stream._services,
240
+ acq_uuid=lima2_stream._acq_uuid,
271
241
  source="cafe",
272
242
  frame_idx=123 - 2,
273
243
  ),
274
244
  call(
275
- services=stream._services,
276
- acq_uuid=stream._acq_uuid,
245
+ services=lima2_stream._services,
246
+ acq_uuid=lima2_stream._acq_uuid,
277
247
  source="cafe",
278
248
  frame_idx=123 - 1,
279
249
  ),
280
250
  ]
281
251
 
282
- _ = stream[:]
252
+ _ = lima2_stream[:]
283
253
  assert mock_get_frame.mock_calls[-123:] == [
284
254
  call(
285
- services=stream._services,
286
- acq_uuid=stream._acq_uuid,
255
+ services=lima2_stream._services,
256
+ acq_uuid=lima2_stream._acq_uuid,
287
257
  source="cafe",
288
258
  frame_idx=i,
289
259
  )
290
260
  for i in range(123)
291
261
  ]
292
262
 
293
- _ = stream.get_last_live_image()
263
+ _ = lima2_stream.get_last_live_image()
294
264
  mock_get_frame.assert_called_with(
295
- services=stream._services,
296
- acq_uuid=stream._acq_uuid,
265
+ services=lima2_stream._services,
266
+ acq_uuid=lima2_stream._acq_uuid,
297
267
  source="cafe",
298
268
  frame_idx=-1,
299
269
  )
300
270
 
301
271
 
302
272
  def test_lima2_stream_build_view(lima2_stream, monkeypatch):
303
- stream_def, event_stream, stream = lima2_stream
304
-
305
273
  mock_get_frame = Mock()
306
274
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
307
275
 
308
- view = stream._build_view_from_events(
276
+ view = lima2_stream._build_view_from_events(
309
277
  index=0,
310
278
  events=EventRange(
311
279
  index=0,
@@ -317,7 +285,7 @@ def test_lima2_stream_build_view(lima2_stream, monkeypatch):
317
285
  )
318
286
  assert view._idx_range == range(0, 42)
319
287
 
320
- view = stream._build_view_from_events(
288
+ view = lima2_stream._build_view_from_events(
321
289
  index=0,
322
290
  events=EventRange(
323
291
  index=0,
@@ -331,7 +299,7 @@ def test_lima2_stream_build_view(lima2_stream, monkeypatch):
331
299
 
332
300
  with pytest.raises(EmptyViewException):
333
301
  # index >= data[-1]
334
- view = stream._build_view_from_events(
302
+ view = lima2_stream._build_view_from_events(
335
303
  index=42,
336
304
  events=EventRange(
337
305
  index=0,
@@ -344,23 +312,21 @@ def test_lima2_stream_build_view(lima2_stream, monkeypatch):
344
312
 
345
313
 
346
314
  def test_lima2_stream_fetch_frames(lima2_stream, monkeypatch):
347
- stream_def, event_stream, stream = lima2_stream
348
-
349
315
  mock_get_frame = Mock()
350
316
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
351
317
 
352
318
  with monkeypatch.context() as mpc:
353
319
  # Stream sealed, has master file
354
320
  mock_fetch = Mock()
355
- mpc.setattr(stream, "_fetch_from_disk", mock_fetch)
356
- mpc.setattr(stream, "is_sealed", lambda: True)
321
+ mpc.setattr(lima2_stream, "_fetch_from_disk", mock_fetch)
322
+ mpc.setattr(lima2_stream, "is_sealed", lambda: True)
357
323
  mpc.setattr(
358
- stream,
324
+ lima2_stream,
359
325
  "_master_file",
360
326
  ("/path/to/master.h5", "entry/instrument/detector/dataset"),
361
327
  )
362
328
 
363
- stream._fetch_frames(start=0, stop=42, step=3)
329
+ lima2_stream._fetch_frames(start=0, stop=42, step=3)
364
330
 
365
331
  mock_fetch.assert_called_once_with(
366
332
  filepath="/path/to/master.h5",
@@ -373,11 +339,11 @@ def test_lima2_stream_fetch_frames(lima2_stream, monkeypatch):
373
339
  with monkeypatch.context() as mpc:
374
340
  # Stream sealed, no master file
375
341
  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)
342
+ mpc.setattr(lima2_stream, "_fetch_online", mock_fetch)
343
+ mpc.setattr(lima2_stream, "is_sealed", lambda: True)
344
+ mpc.setattr(lima2_stream, "_master_file", None)
379
345
 
380
- stream._fetch_frames(start=0, stop=42, step=3)
346
+ lima2_stream._fetch_frames(start=0, stop=42, step=3)
381
347
 
382
348
  mock_fetch.assert_called_once_with(
383
349
  start=0,
@@ -388,10 +354,10 @@ def test_lima2_stream_fetch_frames(lima2_stream, monkeypatch):
388
354
  with monkeypatch.context() as mpc:
389
355
  # Stream not sealed
390
356
  mock_fetch = Mock()
391
- mpc.setattr(stream, "_fetch_online", mock_fetch)
392
- mpc.setattr(stream, "is_sealed", lambda: False)
357
+ mpc.setattr(lima2_stream, "_fetch_online", mock_fetch)
358
+ mpc.setattr(lima2_stream, "is_sealed", lambda: False)
393
359
 
394
- stream._fetch_frames(start=0, stop=42, step=3)
360
+ lima2_stream._fetch_frames(start=0, stop=42, step=3)
395
361
 
396
362
  mock_fetch.assert_called_once_with(
397
363
  start=0,
@@ -401,19 +367,17 @@ def test_lima2_stream_fetch_frames(lima2_stream, monkeypatch):
401
367
 
402
368
 
403
369
  def test_lima2_stream_fetch_online(lima2_stream, monkeypatch):
404
- stream_def, event_stream, stream = lima2_stream
405
-
406
370
  mock_get_frame = Mock()
407
371
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame)
408
372
 
409
- stream._fetch_online(start=0, stop=42, step=3)
373
+ lima2_stream._fetch_online(start=0, stop=42, step=3)
410
374
 
411
375
  mock_get_frame.assert_has_calls(
412
376
  [
413
377
  call(
414
- services=stream._services,
415
- acq_uuid=stream._acq_uuid,
416
- source=stream._source,
378
+ services=lima2_stream._services,
379
+ acq_uuid=lima2_stream._acq_uuid,
380
+ source=lima2_stream._source,
417
381
  frame_idx=idx,
418
382
  )
419
383
  for idx in range(0, 42, 3)
@@ -429,7 +393,7 @@ def test_lima2_stream_fetch_online(lima2_stream, monkeypatch):
429
393
  )
430
394
 
431
395
  with pytest.raises(IndexNoMoreThereError):
432
- _ = stream._fetch_online(start=0, stop=1, step=1)
396
+ _ = lima2_stream._fetch_online(start=0, stop=1, step=1)
433
397
 
434
398
  # ValueError
435
399
  def mock_get_frame_value_error(services, acq_uuid, source, frame_idx):
@@ -438,16 +402,14 @@ def test_lima2_stream_fetch_online(lima2_stream, monkeypatch):
438
402
  monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame_value_error)
439
403
 
440
404
  with pytest.raises(IndexNoMoreThereError):
441
- _ = stream._fetch_online(start=0, stop=1, step=1)
405
+ _ = lima2_stream._fetch_online(start=0, stop=1, step=1)
442
406
 
443
407
 
444
408
  def test_lima2_stream_fetch_offline(lima2_stream, monkeypatch):
445
- stream_def, event_stream, stream = lima2_stream
446
-
447
409
  mock_dynamic_hdf5 = MagicMock()
448
410
  monkeypatch.setattr("blissdata_lima2.stream.dynamic_hdf5", mock_dynamic_hdf5)
449
411
 
450
- stream._fetch_from_disk(
412
+ lima2_stream._fetch_from_disk(
451
413
  filepath="/path/to/master.h5",
452
414
  datapath="entry/instrument/detector/dataset",
453
415
  start=0,
@@ -456,3 +418,55 @@ def test_lima2_stream_fetch_offline(lima2_stream, monkeypatch):
456
418
  )
457
419
 
458
420
  mock_dynamic_hdf5.File.assert_called_once()
421
+
422
+
423
+ def test_lima2_stream_reshape(data_store, mock_handshake, monkeypatch):
424
+ """Verify proper reshaping of the frame on online frame fetch."""
425
+
426
+ stream_def = Lima2Stream.make_definition(
427
+ name="device:cafe",
428
+ source_name="cafe",
429
+ conductor_hostname="www.lima2.org",
430
+ conductor_port=12345,
431
+ acq_uuid=uuid1(),
432
+ master_file=None,
433
+ dtype=np.uint32,
434
+ shape=(13, 37), # note 2D
435
+ )
436
+ lima2_stream = Lima2Stream(
437
+ event_stream=EventStream.create(
438
+ data_store=data_store,
439
+ name=stream_def.name,
440
+ model=data_store._stream_model(
441
+ encoding=stream_def.encoder.info(), info=stream_def.info
442
+ ),
443
+ )
444
+ )
445
+
446
+ def mock_get_frame_3d(services, acq_uuid, source, frame_idx):
447
+ return ImageData(array=np.zeros((1, 13, 37)), frame_id=0, acq_tag=None)
448
+
449
+ monkeypatch.setattr("blissdata_lima2.stream.get_frame", mock_get_frame_3d)
450
+
451
+ data = lima2_stream._fetch_online(start=0, stop=4, step=1)
452
+ assert data.shape == (4, 13, 37)
453
+
454
+
455
+ def test_lima2_client_lazy_init(data_store, monkeypatch, lima2_stream):
456
+ class InitForbiddenError(Exception):
457
+ pass
458
+
459
+ def mock_client_init(*args, **kwargs):
460
+ raise InitForbiddenError()
461
+
462
+ monkeypatch.setattr("lima2.client.services.init", mock_client_init)
463
+
464
+ lima2_stream.send(np.uint32(42))
465
+ lima2_stream.join()
466
+ view = lima2_stream.cursor().read(block=False)
467
+
468
+ with pytest.raises(InitForbiddenError):
469
+ view.get_data()
470
+
471
+ with pytest.raises(InitForbiddenError):
472
+ lima2_stream[0]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: blissdata-lima2
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: Lima2 plugin for blissdata
5
5
  Maintainer: BCU (ESRF)
6
6
  License-Expression: MIT
@@ -11,7 +11,7 @@ Classifier: Programming Language :: Python :: 3
11
11
  Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE.md
14
- Requires-Dist: blissdata~=2.3
14
+ Requires-Dist: blissdata~=2.4
15
15
  Requires-Dist: lima2-client~=4.1
16
16
  Provides-Extra: dev
17
17
  Requires-Dist: black; extra == "dev"
@@ -1,4 +1,4 @@
1
- blissdata~=2.3
1
+ blissdata~=2.4
2
2
  lima2-client~=4.1
3
3
 
4
4
  [dev]
@@ -1,28 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "blissdata-lima2"
7
- version = "2.0.2"
8
- description = "Lima2 plugin for blissdata"
9
- readme = "README.md"
10
- license = "MIT"
11
- license-files = ["LICENSE.md"]
12
- maintainers = [{ name = "BCU (ESRF)" }]
13
- classifiers = [
14
- "Intended Audience :: Science/Research",
15
- "Programming Language :: Python :: 3",
16
- ]
17
- keywords = ["blissdata", "lima2"]
18
- requires-python = ">=3.10"
19
- dependencies = ["blissdata~=2.3", "lima2-client~=4.1"]
20
-
21
- [project.urls]
22
- Repository = "https://gitlab.esrf.fr/bliss/blissdata-lima2"
23
-
24
- [project.optional-dependencies]
25
- dev = ["black", "flake8", "mypy", "pytest", "pytest-cov", "pytest-redis"]
26
-
27
- [project.entry-points.blissdata]
28
- lima2 = "blissdata_lima2"