lima2.client 2.1.0__tar.gz → 2.1.1__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.
- {lima2_client-2.1.0/src/lima2.client.egg-info → lima2_client-2.1.1}/PKG-INFO +1 -1
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/pipeline.py +36 -17
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/pipelines/legacy.py +9 -7
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/pipelines/smx.py +17 -14
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/pipelines/xpcs.py +13 -11
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/state_machine.py +19 -10
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/topology.py +3 -2
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/master_file/generate.py +54 -27
- {lima2_client-2.1.0 → lima2_client-2.1.1/src/lima2.client.egg-info}/PKG-INFO +1 -1
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_pipeline.py +35 -5
- {lima2_client-2.1.0 → lima2_client-2.1.1}/LICENSE +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/README.md +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/pyproject.toml +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/setup.cfg +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/__init__.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/client.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/convert.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/detector.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/devencoded/__init__.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/devencoded/dense_frame.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/devencoded/exception.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/devencoded/sparse_frame.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/devencoded/structured_array.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/pipelines/__init__.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/progress_counter.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/py.typed +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/shell.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/client/utils.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/server/__init__.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/server/control.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/server/receiver.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2/server/timer.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2.client.egg-info/SOURCES.txt +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2.client.egg-info/dependency_links.txt +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2.client.egg-info/entry_points.txt +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2.client.egg-info/requires.txt +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/src/lima2.client.egg-info/top_level.txt +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_client.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_convert.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_dense_frame.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_detector.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_pipelines.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_progress_counter.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_sparse_frame.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_state_machine.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_timer.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_topology.py +0 -0
- {lima2_client-2.1.0 → lima2_client-2.1.1}/tests/test_utils.py +0 -0
|
@@ -18,15 +18,17 @@ import traceback
|
|
|
18
18
|
from collections.abc import Callable
|
|
19
19
|
from concurrent.futures import ThreadPoolExecutor
|
|
20
20
|
from dataclasses import dataclass
|
|
21
|
+
from enum import Enum, auto
|
|
21
22
|
from uuid import UUID
|
|
22
23
|
|
|
23
24
|
import numpy as np
|
|
24
25
|
import tango
|
|
25
26
|
from jsonschema_default import create_from
|
|
27
|
+
from typing_extensions import Optional
|
|
26
28
|
|
|
27
29
|
from lima2.client import progress_counter, utils
|
|
28
30
|
from lima2.client.convert import frame_info_to_shape_dtype
|
|
29
|
-
from lima2.client.devencoded import structured_array
|
|
31
|
+
from lima2.client.devencoded import dense_frame, sparse_frame, structured_array
|
|
30
32
|
from lima2.client.progress_counter import ProgressCounter, SingleCounter
|
|
31
33
|
from lima2.client.topology import (
|
|
32
34
|
RoundRobinTopology,
|
|
@@ -40,29 +42,44 @@ from lima2.client.utils import classproperty
|
|
|
40
42
|
logger = logging.getLogger(__name__)
|
|
41
43
|
|
|
42
44
|
|
|
45
|
+
class FrameType(Enum):
|
|
46
|
+
DENSE = auto()
|
|
47
|
+
SPARSE = auto()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
decoder_by_type: dict[FrameType, Callable] = {
|
|
51
|
+
FrameType.DENSE: dense_frame.decode,
|
|
52
|
+
FrameType.SPARSE: sparse_frame.decode,
|
|
53
|
+
}
|
|
54
|
+
"""Mapping from frame type to associated decode function"""
|
|
55
|
+
|
|
56
|
+
|
|
43
57
|
@dataclass
|
|
44
58
|
class FrameSource:
|
|
45
|
-
"""Specifies the name of a getter and a
|
|
59
|
+
"""Specifies the name of a getter and a frame type for a given frame source.
|
|
46
60
|
|
|
47
61
|
From these two attributes, it is possible to fetch a frame from a processing tango
|
|
48
62
|
device and then decode it.
|
|
49
63
|
"""
|
|
50
64
|
|
|
51
65
|
getter_name: str
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
"""Name of the getter method to call on the tango device to fetch the data"""
|
|
54
67
|
|
|
55
|
-
|
|
56
|
-
"""
|
|
68
|
+
frame_type: FrameType
|
|
69
|
+
"""Frame type"""
|
|
57
70
|
|
|
58
|
-
|
|
59
|
-
"""
|
|
71
|
+
saving_channel: Optional[str]
|
|
72
|
+
"""Name of the associated saving_params object in the proc_params struct.
|
|
60
73
|
|
|
61
|
-
|
|
74
|
+
Can be None for sources without persistency.
|
|
62
75
|
"""
|
|
63
76
|
|
|
77
|
+
|
|
78
|
+
class Pipeline:
|
|
79
|
+
"""A base class for all processing pipelines."""
|
|
80
|
+
|
|
64
81
|
FRAME_SOURCES: dict[str, FrameSource]
|
|
65
|
-
"""Map of available frame source names to a corresponding
|
|
82
|
+
"""Map of available frame source names to a corresponding FrameSource descriptor.
|
|
66
83
|
|
|
67
84
|
Definition in child classes is enforced by __init_subclass__().
|
|
68
85
|
"""
|
|
@@ -128,11 +145,6 @@ class Pipeline:
|
|
|
128
145
|
@classmethod
|
|
129
146
|
def __init_subclass__(cls) -> None:
|
|
130
147
|
"""Initialize a pipeline subclass."""
|
|
131
|
-
if not hasattr(cls, "SAVING_PARAMS_NAMES"):
|
|
132
|
-
raise ValueError(
|
|
133
|
-
f"Pipeline subclass {cls} must define a SAVING_PARAMS_NAMES class member"
|
|
134
|
-
)
|
|
135
|
-
|
|
136
148
|
if not hasattr(cls, "FRAME_SOURCES"):
|
|
137
149
|
raise ValueError(
|
|
138
150
|
f"Pipeline subclass {cls} must define a FRAME_SOURCES class member"
|
|
@@ -225,6 +237,13 @@ class Pipeline:
|
|
|
225
237
|
f"Available ones are: {list(self.FRAME_SOURCES.keys())}"
|
|
226
238
|
)
|
|
227
239
|
|
|
240
|
+
try:
|
|
241
|
+
decode = decoder_by_type[frame_source.frame_type]
|
|
242
|
+
except KeyError as e:
|
|
243
|
+
raise NotImplementedError(
|
|
244
|
+
f"Frame type {frame_source.frame_type} decoder missing"
|
|
245
|
+
) from e
|
|
246
|
+
|
|
228
247
|
getters = [getattr(dev, frame_source.getter_name) for dev in self._devs]
|
|
229
248
|
|
|
230
249
|
if frame_idx == -1:
|
|
@@ -238,7 +257,7 @@ class Pipeline:
|
|
|
238
257
|
Returns None if the receiver hasn't yet processed any frames.
|
|
239
258
|
"""
|
|
240
259
|
try:
|
|
241
|
-
return
|
|
260
|
+
return decode(getters[rcv_idx](-1))
|
|
242
261
|
except tango.DevFailed:
|
|
243
262
|
return None
|
|
244
263
|
|
|
@@ -264,7 +283,7 @@ class Pipeline:
|
|
|
264
283
|
# Get a frame by absolute index -> use topology-specific lookup()
|
|
265
284
|
frame = self.topology.lookup(frame_idx=frame_idx, getters=getters)
|
|
266
285
|
|
|
267
|
-
return
|
|
286
|
+
return decode(frame)
|
|
268
287
|
|
|
269
288
|
def cache_byproduct(self, key: str, data: np.ndarray) -> None:
|
|
270
289
|
"""Store `data` into `self.byproduct_cache[key]`.
|
|
@@ -13,8 +13,7 @@ from uuid import UUID
|
|
|
13
13
|
import tango
|
|
14
14
|
from beartype import beartype
|
|
15
15
|
|
|
16
|
-
from lima2.client.
|
|
17
|
-
from lima2.client.pipeline import FrameSource, Pipeline
|
|
16
|
+
from lima2.client.pipeline import FrameSource, FrameType, Pipeline
|
|
18
17
|
from lima2.client.topology import TopologyKind
|
|
19
18
|
|
|
20
19
|
# Create a logger
|
|
@@ -25,14 +24,17 @@ _logger = logging.getLogger(__name__)
|
|
|
25
24
|
class Legacy(Pipeline):
|
|
26
25
|
tango_class = "LimaProcessingLegacy"
|
|
27
26
|
|
|
28
|
-
SAVING_PARAMS_NAMES = ["saving"]
|
|
29
|
-
"""Members of type "saving_params" in the corresponding lima2 "proc_params" struct."""
|
|
30
|
-
|
|
31
27
|
FRAME_SOURCES = {
|
|
32
28
|
"input_frame": FrameSource(
|
|
33
|
-
getter_name="getInputFrame",
|
|
29
|
+
getter_name="getInputFrame",
|
|
30
|
+
frame_type=FrameType.DENSE,
|
|
31
|
+
saving_channel=None,
|
|
32
|
+
),
|
|
33
|
+
"frame": FrameSource(
|
|
34
|
+
getter_name="getFrame",
|
|
35
|
+
frame_type=FrameType.DENSE,
|
|
36
|
+
saving_channel="saving",
|
|
34
37
|
),
|
|
35
|
-
"frame": FrameSource(getter_name="getFrame", decoder=dense_frame.decode),
|
|
36
38
|
}
|
|
37
39
|
"""Available frame sources."""
|
|
38
40
|
|
|
@@ -16,10 +16,9 @@ import tango
|
|
|
16
16
|
from lima2.client import utils
|
|
17
17
|
from lima2.client.devencoded import (
|
|
18
18
|
dense_frame,
|
|
19
|
-
sparse_frame,
|
|
20
19
|
structured_array,
|
|
21
20
|
)
|
|
22
|
-
from lima2.client.pipeline import FrameSource, Pipeline
|
|
21
|
+
from lima2.client.pipeline import FrameSource, FrameType, Pipeline
|
|
23
22
|
from lima2.client.topology import TopologyKind
|
|
24
23
|
|
|
25
24
|
# Create a logger
|
|
@@ -29,23 +28,27 @@ logger = logging.getLogger(__name__)
|
|
|
29
28
|
class Smx(Pipeline):
|
|
30
29
|
tango_class = "LimaProcessingSmx"
|
|
31
30
|
|
|
32
|
-
# Members of type "saving_params" in the corresponding lima2 "proc_params" struct.
|
|
33
|
-
SAVING_PARAMS_NAMES = [
|
|
34
|
-
"saving_dense",
|
|
35
|
-
"saving_sparse",
|
|
36
|
-
"saving_accumulation_corrected",
|
|
37
|
-
"saving_accumulation_peak",
|
|
38
|
-
]
|
|
39
|
-
|
|
40
31
|
FRAME_SOURCES = {
|
|
41
|
-
"frame": FrameSource(
|
|
32
|
+
"frame": FrameSource(
|
|
33
|
+
getter_name="getFrame",
|
|
34
|
+
frame_type=FrameType.DENSE,
|
|
35
|
+
saving_channel="saving_dense",
|
|
36
|
+
),
|
|
42
37
|
"sparse_frame": FrameSource(
|
|
43
|
-
getter_name="getSparseFrame",
|
|
38
|
+
getter_name="getSparseFrame",
|
|
39
|
+
frame_type=FrameType.SPARSE,
|
|
40
|
+
saving_channel="saving_sparse",
|
|
44
41
|
),
|
|
45
42
|
"acc_corrected": FrameSource(
|
|
46
|
-
getter_name="getAccCorrected",
|
|
43
|
+
getter_name="getAccCorrected",
|
|
44
|
+
frame_type=FrameType.DENSE,
|
|
45
|
+
saving_channel="saving_accumulation_corrected",
|
|
46
|
+
),
|
|
47
|
+
"acc_peaks": FrameSource(
|
|
48
|
+
getter_name="getAccPeaks",
|
|
49
|
+
frame_type=FrameType.DENSE,
|
|
50
|
+
saving_channel="saving_accumulation_peak",
|
|
47
51
|
),
|
|
48
|
-
"acc_peaks": FrameSource(getter_name="getAccPeaks", decoder=dense_frame.decode),
|
|
49
52
|
}
|
|
50
53
|
"""Available frame sources."""
|
|
51
54
|
|
|
@@ -14,8 +14,8 @@ import numpy as np
|
|
|
14
14
|
import tango
|
|
15
15
|
|
|
16
16
|
from lima2.client import progress_counter, utils
|
|
17
|
-
from lima2.client.devencoded import
|
|
18
|
-
from lima2.client.pipeline import FrameSource, Pipeline
|
|
17
|
+
from lima2.client.devencoded import structured_array
|
|
18
|
+
from lima2.client.pipeline import FrameSource, FrameType, Pipeline
|
|
19
19
|
from lima2.client.topology import TopologyKind
|
|
20
20
|
|
|
21
21
|
# Create a logger
|
|
@@ -25,19 +25,21 @@ logger = logging.getLogger(__name__)
|
|
|
25
25
|
class Xpcs(Pipeline):
|
|
26
26
|
tango_class = "LimaProcessingXpcs"
|
|
27
27
|
|
|
28
|
-
# Members of type "saving_params" in the corresponding lima2 "proc_params" struct.
|
|
29
|
-
SAVING_PARAMS_NAMES = [
|
|
30
|
-
"saving_dense",
|
|
31
|
-
"saving_sparse",
|
|
32
|
-
]
|
|
33
|
-
|
|
34
28
|
FRAME_SOURCES = {
|
|
35
29
|
"input_frame": FrameSource(
|
|
36
|
-
getter_name="getInputFrame",
|
|
30
|
+
getter_name="getInputFrame",
|
|
31
|
+
frame_type=FrameType.DENSE,
|
|
32
|
+
saving_channel=None,
|
|
33
|
+
),
|
|
34
|
+
"frame": FrameSource(
|
|
35
|
+
getter_name="getFrame",
|
|
36
|
+
frame_type=FrameType.DENSE,
|
|
37
|
+
saving_channel="saving_dense",
|
|
37
38
|
),
|
|
38
|
-
"frame": FrameSource(getter_name="getFrame", decoder=dense_frame.decode),
|
|
39
39
|
"sparse_frame": FrameSource(
|
|
40
|
-
getter_name="getSparseFrame",
|
|
40
|
+
getter_name="getSparseFrame",
|
|
41
|
+
frame_type=FrameType.SPARSE,
|
|
42
|
+
saving_channel="saving_sparse",
|
|
41
43
|
),
|
|
42
44
|
}
|
|
43
45
|
"""Available frame sources."""
|
|
@@ -115,18 +115,27 @@ class StateMachine(fsm.StateMachine):
|
|
|
115
115
|
for device in [self.ctrl] + self.recvs:
|
|
116
116
|
device.ping()
|
|
117
117
|
states = [d.acq_state for d in [self.ctrl] + self.recvs]
|
|
118
|
-
|
|
118
|
+
ctl_state = states[0]
|
|
119
|
+
|
|
120
|
+
ServerState = type(ctl_state)
|
|
121
|
+
|
|
122
|
+
if all(s in [ServerState.idle, ServerState.prepared] for s in states):
|
|
123
|
+
# Tolerate a mix of prepared and idle devices. In this case,
|
|
124
|
+
# the global state shall be IDLE (forcing user to prepare again).
|
|
125
|
+
self.state = State.IDLE
|
|
126
|
+
elif not all(s == ctl_state for s in states):
|
|
127
|
+
# Otherwise, if states are divergent, sync cannot be done
|
|
119
128
|
self._state = State.UNKNOWN
|
|
120
129
|
raise RuntimeError(f"Cannot sync: inconsistent server states ({states})")
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
else:
|
|
131
|
+
map = {
|
|
132
|
+
ServerState.idle: State.IDLE,
|
|
133
|
+
ServerState.prepared: State.PREPARED,
|
|
134
|
+
ServerState.running: State.RUNNING,
|
|
135
|
+
ServerState.stopped: State.IDLE,
|
|
136
|
+
}
|
|
137
|
+
self.state = map[ctl_state]
|
|
138
|
+
|
|
130
139
|
return self.state
|
|
131
140
|
|
|
132
141
|
@property
|
|
@@ -152,8 +152,9 @@ def distribute_acq(
|
|
|
152
152
|
for i in range(num_receivers):
|
|
153
153
|
# Assign unique filename rank per receiver
|
|
154
154
|
processing_class = pipelines.get_class(proc_params["class_name"])
|
|
155
|
-
for
|
|
156
|
-
|
|
155
|
+
for source in processing_class.FRAME_SOURCES.values():
|
|
156
|
+
if source.saving_channel is not None:
|
|
157
|
+
proc[i][source.saving_channel]["filename_rank"] = i
|
|
157
158
|
|
|
158
159
|
# Idem for detector RAW saving params
|
|
159
160
|
if "saving" in acq[i]:
|
|
@@ -19,7 +19,7 @@ import os
|
|
|
19
19
|
import h5py
|
|
20
20
|
import numpy as np
|
|
21
21
|
|
|
22
|
-
from lima2.client.pipeline import Pipeline
|
|
22
|
+
from lima2.client.pipeline import FrameType, Pipeline
|
|
23
23
|
|
|
24
24
|
logger = logging.getLogger(__name__)
|
|
25
25
|
|
|
@@ -42,42 +42,69 @@ def enable_generation(
|
|
|
42
42
|
rr_offset (int): expected receiver of frame 0 in the round robin frame dispatching
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
-
if
|
|
45
|
+
if rr_offset >= len(pipeline._devs):
|
|
46
46
|
raise ValueError(
|
|
47
|
-
f"
|
|
47
|
+
f"Round robin offset cannot exceed the last receiver index ({len(pipeline._devs) - 1})."
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
file_exists_policy = proc_params["saving"]["file_exists_policy"]
|
|
50
|
+
generate_params: list[dict] = []
|
|
51
|
+
"""Params passed to generate_master_file for each enabled saving channel"""
|
|
53
52
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
for name, source in pipeline.FRAME_SOURCES.items():
|
|
54
|
+
# Skip non-dense frame sources
|
|
55
|
+
if source.frame_type != FrameType.DENSE:
|
|
56
|
+
continue
|
|
57
|
+
# Skip non-persistent sources
|
|
58
|
+
if source.saving_channel is None:
|
|
59
|
+
continue
|
|
60
|
+
# Skip source if channel is disabled
|
|
61
|
+
if not proc_params[source.saving_channel]["enabled"]:
|
|
62
|
+
continue
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
)
|
|
64
|
+
base_path = proc_params[source.saving_channel]["base_path"]
|
|
65
|
+
filename_prefix = proc_params[source.saving_channel]["filename_prefix"]
|
|
66
|
+
file_exists_policy = proc_params[source.saving_channel]["file_exists_policy"]
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
master_file_path = f"{base_path}/{filename_prefix}_master.h5"
|
|
69
|
+
if os.path.exists(master_file_path) and file_exists_policy != "overwrite":
|
|
70
|
+
raise ValueError(
|
|
71
|
+
f"Master file (channel={source.saving_channel}) exists at {master_file_path} "
|
|
72
|
+
f"but {file_exists_policy=}. Cannot enable master file generation."
|
|
73
|
+
)
|
|
67
74
|
|
|
68
|
-
|
|
75
|
+
logger.info(
|
|
76
|
+
f"Master file (channel={source.saving_channel}) will be generated "
|
|
77
|
+
f"at {master_file_path}..."
|
|
78
|
+
)
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
frame_info = pipeline.channels[name]
|
|
81
|
+
|
|
82
|
+
# Calling register_on_finished here with a lambda doesn't work as expected
|
|
83
|
+
# because some parameters will be evaluated at the time of calling, and their value
|
|
84
|
+
# will have changed in subsequent loop iterations.
|
|
85
|
+
# One solution is to store the parameters in a dict and call register_on_finished
|
|
86
|
+
# outside of the loop.
|
|
87
|
+
generate_params.append(
|
|
88
|
+
dict(
|
|
89
|
+
num_frames=num_frames,
|
|
90
|
+
frame_shape=frame_info["shape"],
|
|
91
|
+
pixel_dtype=frame_info["dtype"],
|
|
92
|
+
num_receivers=len(pipeline._devs),
|
|
93
|
+
saving_params=proc_params[source.saving_channel],
|
|
94
|
+
rr_offset=rr_offset,
|
|
95
|
+
)
|
|
78
96
|
)
|
|
79
97
|
|
|
80
|
-
|
|
98
|
+
if len(generate_params) == 0:
|
|
99
|
+
logger.warning(
|
|
100
|
+
"Master file generation not enabled: no dense frames saving channel enabled."
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
pipeline.register_on_finished(
|
|
104
|
+
on_finished=lambda: [
|
|
105
|
+
generate_master_file(**params) for params in generate_params
|
|
106
|
+
]
|
|
107
|
+
)
|
|
81
108
|
|
|
82
109
|
|
|
83
110
|
def generate_master_file(
|
|
@@ -15,8 +15,8 @@ import numpy as np
|
|
|
15
15
|
import pytest
|
|
16
16
|
import tango
|
|
17
17
|
|
|
18
|
-
from lima2.client import progress_counter
|
|
19
|
-
from lima2.client.pipeline import FrameSource, Pipeline
|
|
18
|
+
from lima2.client import pipeline, progress_counter
|
|
19
|
+
from lima2.client.pipeline import FrameSource, FrameType, Pipeline
|
|
20
20
|
from lima2.client.pipelines.smx import Smx
|
|
21
21
|
from lima2.client.pipelines.xpcs import Xpcs
|
|
22
22
|
from lima2.client.topology import TopologyKind
|
|
@@ -90,6 +90,20 @@ def test_constructor_uneven(processing_devices):
|
|
|
90
90
|
)
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
def test_bad_subclass():
|
|
94
|
+
with pytest.raises(ValueError):
|
|
95
|
+
|
|
96
|
+
class NoFrameSourcePipeline(Pipeline):
|
|
97
|
+
tango_class = "badcafe"
|
|
98
|
+
# Missing FRAME_SOURCES
|
|
99
|
+
|
|
100
|
+
with pytest.raises(ValueError):
|
|
101
|
+
|
|
102
|
+
class NoTangoClassPipeline(Pipeline):
|
|
103
|
+
FRAME_SOURCES = {}
|
|
104
|
+
# Missing tango_class
|
|
105
|
+
|
|
106
|
+
|
|
93
107
|
def test_progress_counters(processing_devices):
|
|
94
108
|
"""Read progress_counters."""
|
|
95
109
|
processing_devices[0].progress_counters = json.dumps(
|
|
@@ -387,7 +401,7 @@ def test_pop_roi_profiles(processing_devices):
|
|
|
387
401
|
assert proc.byproduct_cache["roi_profiles"].size == 0 # No cache
|
|
388
402
|
|
|
389
403
|
|
|
390
|
-
def test_get_frame(processing_devices):
|
|
404
|
+
def test_get_frame(processing_devices, monkeypatch):
|
|
391
405
|
proc = Pipeline(
|
|
392
406
|
uuid=uuid1(),
|
|
393
407
|
proc_devs=processing_devices,
|
|
@@ -403,10 +417,26 @@ def test_get_frame(processing_devices):
|
|
|
403
417
|
proc.FRAME_SOURCES = {
|
|
404
418
|
"cafedeca": FrameSource(
|
|
405
419
|
getter_name="getFrame",
|
|
406
|
-
|
|
407
|
-
|
|
420
|
+
frame_type=FrameType.DENSE,
|
|
421
|
+
saving_channel=None,
|
|
422
|
+
),
|
|
423
|
+
"sparse": FrameSource(
|
|
424
|
+
getter_name="getSparseFrame",
|
|
425
|
+
frame_type=FrameType.SPARSE,
|
|
426
|
+
saving_channel=None,
|
|
427
|
+
),
|
|
408
428
|
}
|
|
409
429
|
|
|
430
|
+
def mock_decode(data: bytes):
|
|
431
|
+
return MockFrame(data[0], data[1:])
|
|
432
|
+
|
|
433
|
+
# Modify the decoder_by_type map to plug our mock decode function
|
|
434
|
+
# No decoder for SPARSE frame so we can test the case where the decoder is not implemented
|
|
435
|
+
monkeypatch.setattr(pipeline, "decoder_by_type", {FrameType.DENSE: mock_decode})
|
|
436
|
+
|
|
437
|
+
with pytest.raises(NotImplementedError):
|
|
438
|
+
proc.get_frame(0, source="sparse")
|
|
439
|
+
|
|
410
440
|
rcv_0_frames = {
|
|
411
441
|
0: b"\x00milk",
|
|
412
442
|
-1: b"\x02milk",
|
|
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
|