spectre-core 0.0.22__py3-none-any.whl → 0.0.24__py3-none-any.whl
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.
- spectre_core/__init__.py +5 -0
- spectre_core/_file_io/__init__.py +4 -4
- spectre_core/_file_io/file_handlers.py +60 -106
- spectre_core/batches/__init__.py +20 -3
- spectre_core/batches/_base.py +85 -134
- spectre_core/batches/_batches.py +55 -99
- spectre_core/batches/_factory.py +21 -20
- spectre_core/batches/_register.py +8 -8
- spectre_core/batches/plugins/_batch_keys.py +7 -6
- spectre_core/batches/plugins/_callisto.py +65 -97
- spectre_core/batches/plugins/_iq_stream.py +105 -169
- spectre_core/capture_configs/__init__.py +46 -17
- spectre_core/capture_configs/_capture_config.py +25 -52
- spectre_core/capture_configs/_capture_modes.py +8 -6
- spectre_core/capture_configs/_capture_templates.py +50 -110
- spectre_core/capture_configs/_parameters.py +37 -74
- spectre_core/capture_configs/_pconstraints.py +40 -40
- spectre_core/capture_configs/_pnames.py +36 -34
- spectre_core/capture_configs/_ptemplates.py +260 -347
- spectre_core/capture_configs/_pvalidators.py +99 -102
- spectre_core/config/__init__.py +19 -8
- spectre_core/config/_paths.py +25 -47
- spectre_core/config/_time_formats.py +6 -5
- spectre_core/exceptions.py +38 -0
- spectre_core/jobs/__init__.py +3 -6
- spectre_core/jobs/_duration.py +12 -0
- spectre_core/jobs/_jobs.py +72 -43
- spectre_core/jobs/_workers.py +55 -105
- spectre_core/logs/__init__.py +7 -2
- spectre_core/logs/_configure.py +13 -17
- spectre_core/logs/_decorators.py +6 -4
- spectre_core/logs/_logs.py +37 -89
- spectre_core/logs/_process_types.py +5 -3
- spectre_core/plotting/__init__.py +19 -3
- spectre_core/plotting/_base.py +112 -177
- spectre_core/plotting/_format.py +10 -8
- spectre_core/plotting/_panel_names.py +7 -5
- spectre_core/plotting/_panel_stack.py +138 -130
- spectre_core/plotting/_panels.py +152 -162
- spectre_core/post_processing/__init__.py +6 -3
- spectre_core/post_processing/_base.py +41 -55
- spectre_core/post_processing/_factory.py +14 -11
- spectre_core/post_processing/_post_processor.py +16 -12
- spectre_core/post_processing/_register.py +10 -7
- spectre_core/post_processing/plugins/_event_handler_keys.py +4 -3
- spectre_core/post_processing/plugins/_fixed_center_frequency.py +54 -47
- spectre_core/post_processing/plugins/_swept_center_frequency.py +199 -174
- spectre_core/receivers/__init__.py +9 -2
- spectre_core/receivers/_base.py +82 -148
- spectre_core/receivers/_factory.py +20 -30
- spectre_core/receivers/_register.py +7 -10
- spectre_core/receivers/_spec_names.py +17 -15
- spectre_core/receivers/plugins/_b200mini.py +47 -60
- spectre_core/receivers/plugins/_receiver_names.py +8 -6
- spectre_core/receivers/plugins/_rsp1a.py +44 -40
- spectre_core/receivers/plugins/_rspduo.py +59 -44
- spectre_core/receivers/plugins/_sdrplay_receiver.py +67 -83
- spectre_core/receivers/plugins/_test.py +136 -129
- spectre_core/receivers/plugins/_usrp.py +93 -85
- spectre_core/receivers/plugins/gr/__init__.py +1 -1
- spectre_core/receivers/plugins/gr/_base.py +14 -22
- spectre_core/receivers/plugins/gr/_rsp1a.py +53 -60
- spectre_core/receivers/plugins/gr/_rspduo.py +77 -89
- spectre_core/receivers/plugins/gr/_test.py +49 -57
- spectre_core/receivers/plugins/gr/_usrp.py +61 -59
- spectre_core/spectrograms/__init__.py +21 -13
- spectre_core/spectrograms/_analytical.py +108 -99
- spectre_core/spectrograms/_array_operations.py +39 -46
- spectre_core/spectrograms/_spectrogram.py +293 -324
- spectre_core/spectrograms/_transform.py +106 -73
- spectre_core/wgetting/__init__.py +1 -3
- spectre_core/wgetting/_callisto.py +87 -93
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/METADATA +9 -23
- spectre_core-0.0.24.dist-info/RECORD +79 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/WHEEL +1 -1
- spectre_core-0.0.22.dist-info/RECORD +0 -78
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/licenses/LICENSE +0 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.24.dist-info}/top_level.txt +0 -0
@@ -4,19 +4,21 @@
|
|
4
4
|
|
5
5
|
from enum import Enum
|
6
6
|
|
7
|
+
|
7
8
|
class CaptureMode(Enum):
|
8
9
|
"""A default capture mode for `spectre`.
|
9
|
-
|
10
|
-
Each `CaptureMode` has an associated base capture template, which can be fetched using:
|
11
|
-
|
10
|
+
|
11
|
+
Each `CaptureMode` has an associated base capture template, which can be fetched using:
|
12
|
+
|
12
13
|
`get_base_capture_template`
|
13
|
-
|
14
|
+
|
14
15
|
All base capture templates must be registered by one of `CaptureMode`. To introduce a new
|
15
16
|
base capture template, you need to create a new `CaptureMode` constant.
|
16
|
-
|
17
|
+
|
17
18
|
:ivar FIXED_CENTER_FREQUENCY: Indicates data capture at a fixed center frequency.
|
18
19
|
:ivar SWEPT_CENTER_FREQUENCY: Indicates data capture where the center frequency is continually sweeping
|
19
20
|
in fixed increments.
|
20
21
|
"""
|
22
|
+
|
21
23
|
FIXED_CENTER_FREQUENCY = "fixed_center_frequency"
|
22
|
-
SWEPT_CENTER_FREQUENCY = "swept_center_frequency"
|
24
|
+
SWEPT_CENTER_FREQUENCY = "swept_center_frequency"
|
@@ -11,41 +11,29 @@ from ._pconstraints import BasePConstraint
|
|
11
11
|
from ._ptemplates import PTemplate, get_base_ptemplate
|
12
12
|
from ._ptemplates import PName
|
13
13
|
|
14
|
+
|
14
15
|
class CaptureTemplate:
|
15
16
|
"""A managed collection of parameter templates. Strictly defines what parameters are required
|
16
17
|
in a capture config, and the values each parameter can take.
|
17
18
|
"""
|
18
|
-
def __init__(
|
19
|
-
self
|
20
|
-
) -> None:
|
21
|
-
"""Initialise a `CaptureTemplate` instance.
|
22
|
-
"""
|
23
|
-
self._ptemplates: dict[PName, PTemplate] = {}
|
24
19
|
|
20
|
+
def __init__(self) -> None:
|
21
|
+
"""Initialise a `CaptureTemplate` instance."""
|
22
|
+
self._ptemplates: dict[PName, PTemplate] = {}
|
25
23
|
|
26
24
|
@property
|
27
|
-
def name_list(
|
28
|
-
self
|
29
|
-
) -> list[PName]:
|
25
|
+
def name_list(self) -> list[PName]:
|
30
26
|
"""The names of all required parameters in the capture template."""
|
31
27
|
return list(self._ptemplates.keys())
|
32
|
-
|
33
28
|
|
34
|
-
def add_ptemplate(
|
35
|
-
self,
|
36
|
-
ptemplate: PTemplate
|
37
|
-
) -> None:
|
29
|
+
def add_ptemplate(self, ptemplate: PTemplate) -> None:
|
38
30
|
"""Add a parameter template to the capture template.
|
39
31
|
|
40
32
|
:param ptemplate: Describes a required parameter for this capture template.
|
41
33
|
"""
|
42
34
|
self._ptemplates[ptemplate.name] = ptemplate
|
43
35
|
|
44
|
-
|
45
|
-
def get_ptemplate(
|
46
|
-
self,
|
47
|
-
parameter_name: PName
|
48
|
-
) -> PTemplate:
|
36
|
+
def get_ptemplate(self, parameter_name: PName) -> PTemplate:
|
49
37
|
"""Get the parameter template corresponding to the parameter with the name `parameter_name`.
|
50
38
|
|
51
39
|
:param parameter_name: The name of the parameter.
|
@@ -53,37 +41,27 @@ class CaptureTemplate:
|
|
53
41
|
:raises ValueError: If the parameter name is not found in the template.
|
54
42
|
"""
|
55
43
|
if parameter_name not in self._ptemplates:
|
56
|
-
raise ValueError(
|
57
|
-
|
44
|
+
raise ValueError(
|
45
|
+
f"Parameter with name '{parameter_name}' is not found in the template. "
|
46
|
+
f"Expected one of {self.name_list}"
|
47
|
+
)
|
58
48
|
return self._ptemplates[parameter_name]
|
59
|
-
|
60
49
|
|
61
|
-
def __apply_parameter_template(
|
62
|
-
self,
|
63
|
-
parameter: Parameter
|
64
|
-
) -> None:
|
50
|
+
def __apply_parameter_template(self, parameter: Parameter) -> None:
|
65
51
|
"""Apply the corresponding parameter template to the input parameter.
|
66
|
-
|
52
|
+
|
67
53
|
As a side effect, the value of the input parameter will be type cast
|
68
54
|
according to the template.
|
69
55
|
"""
|
70
56
|
ptemplate = self.get_ptemplate(parameter.name)
|
71
57
|
parameter.value = ptemplate.apply_template(parameter.value)
|
72
58
|
|
73
|
-
|
74
|
-
def __apply_parameter_templates(
|
75
|
-
self,
|
76
|
-
parameters: Parameters
|
77
|
-
) -> None:
|
59
|
+
def __apply_parameter_templates(self, parameters: Parameters) -> None:
|
78
60
|
"""Apply the corresponding parameter template to each of the input parameters."""
|
79
61
|
for parameter in parameters:
|
80
62
|
self.__apply_parameter_template(parameter)
|
81
63
|
|
82
|
-
|
83
|
-
def __fill_missing_with_defaults(
|
84
|
-
self,
|
85
|
-
parameters: Parameters
|
86
|
-
) -> None:
|
64
|
+
def __fill_missing_with_defaults(self, parameters: Parameters) -> None:
|
87
65
|
"""Add default parameters to `parameters` for any missing entries.
|
88
66
|
|
89
67
|
Missing parameters are identified by comparing `parameters` against the
|
@@ -94,16 +72,11 @@ class CaptureTemplate:
|
|
94
72
|
if ptemplate.name not in parameters.name_list:
|
95
73
|
# no args for `make_parameter` implies the parameter with the default value will be used.
|
96
74
|
parameter = ptemplate.make_parameter()
|
97
|
-
parameters.add_parameter(parameter.name,
|
98
|
-
parameter.value)
|
99
|
-
|
75
|
+
parameters.add_parameter(parameter.name, parameter.value)
|
100
76
|
|
101
|
-
def apply_template(
|
102
|
-
self,
|
103
|
-
parameters: Parameters
|
104
|
-
) -> Parameters:
|
77
|
+
def apply_template(self, parameters: Parameters) -> Parameters:
|
105
78
|
"""Apply the capture template to the input parameters. This involves:
|
106
|
-
|
79
|
+
|
107
80
|
- Adding default parameters if they are missing with respect to this template.
|
108
81
|
- Type casting the value of each input parameter according to the corresponding parameter template.
|
109
82
|
- Validating the value of each input parameter against any corresponding pconstraints.
|
@@ -115,19 +88,11 @@ class CaptureTemplate:
|
|
115
88
|
self.__apply_parameter_templates(parameters)
|
116
89
|
return parameters
|
117
90
|
|
118
|
-
|
119
|
-
def __iter__(
|
120
|
-
self
|
121
|
-
) -> Iterator[PTemplate]:
|
91
|
+
def __iter__(self) -> Iterator[PTemplate]:
|
122
92
|
"""Iterate over stored ptemplates."""
|
123
|
-
yield from self._ptemplates.values()
|
93
|
+
yield from self._ptemplates.values()
|
124
94
|
|
125
|
-
|
126
|
-
def set_default(
|
127
|
-
self,
|
128
|
-
parameter_name: PName,
|
129
|
-
default: Any
|
130
|
-
) -> None:
|
95
|
+
def set_default(self, parameter_name: PName, default: Any) -> None:
|
131
96
|
"""Set the default of an existing parameter template.
|
132
97
|
|
133
98
|
:param parameter_name: The name of the parameter template to be updated.
|
@@ -135,34 +100,22 @@ class CaptureTemplate:
|
|
135
100
|
"""
|
136
101
|
self.get_ptemplate(parameter_name).default = default
|
137
102
|
|
138
|
-
|
139
|
-
def set_defaults(
|
140
|
-
self,
|
141
|
-
*ptuples: tuple[PName, Any]
|
142
|
-
) -> None:
|
103
|
+
def set_defaults(self, *ptuples: tuple[PName, Any]) -> None:
|
143
104
|
"""Update the defaults of multiple parameter templates.
|
144
105
|
|
145
106
|
:param ptuples: Tuples of the form (`parameter_name`, `new_default`) to update defaults.
|
146
107
|
"""
|
147
|
-
for
|
108
|
+
for parameter_name, default in ptuples:
|
148
109
|
self.set_default(parameter_name, default)
|
149
110
|
|
150
|
-
|
151
|
-
def enforce_default(
|
152
|
-
self,
|
153
|
-
parameter_name: PName
|
154
|
-
) -> None:
|
111
|
+
def enforce_default(self, parameter_name: PName) -> None:
|
155
112
|
"""Set the `enforce_default` attribute of an existing parameter template to True.
|
156
113
|
|
157
114
|
:param parameter_name: The name of the parameter template to enforce its default value.
|
158
115
|
"""
|
159
116
|
self.get_ptemplate(parameter_name).enforce_default = True
|
160
117
|
|
161
|
-
|
162
|
-
def enforce_defaults(
|
163
|
-
self,
|
164
|
-
*parameter_names: PName
|
165
|
-
) -> None:
|
118
|
+
def enforce_defaults(self, *parameter_names: PName) -> None:
|
166
119
|
"""Set the `enforce_default` attribute of multiple existing parameter templates to True.
|
167
120
|
|
168
121
|
:param parameter_names: The names of the parameter templates to enforce their default values.
|
@@ -170,11 +123,8 @@ class CaptureTemplate:
|
|
170
123
|
for name in parameter_names:
|
171
124
|
self.enforce_default(name)
|
172
125
|
|
173
|
-
|
174
126
|
def add_pconstraint(
|
175
|
-
self,
|
176
|
-
parameter_name: PName,
|
177
|
-
pconstraints: list[BasePConstraint]
|
127
|
+
self, parameter_name: PName, pconstraints: list[BasePConstraint]
|
178
128
|
) -> None:
|
179
129
|
"""Add one or more `PConstraint` instances to an existing parameter template.
|
180
130
|
|
@@ -184,22 +134,16 @@ class CaptureTemplate:
|
|
184
134
|
for pconstraint in pconstraints:
|
185
135
|
self.get_ptemplate(parameter_name).add_pconstraint(pconstraint)
|
186
136
|
|
187
|
-
|
188
|
-
def to_dict(
|
189
|
-
self
|
190
|
-
) -> dict[str, dict[str, str]]:
|
137
|
+
def to_dict(self) -> dict[str, dict[str, str]]:
|
191
138
|
"""Convert the current instance to a serialisable dictionary.
|
192
139
|
|
193
140
|
:return: A dictionary representation of this capture template, where all values
|
194
141
|
are formatted strings.
|
195
142
|
"""
|
196
143
|
return {ptemplate.name.value: ptemplate.to_dict() for ptemplate in self}
|
197
|
-
|
198
|
-
|
199
144
|
|
200
|
-
|
201
|
-
|
202
|
-
) -> CaptureTemplate:
|
145
|
+
|
146
|
+
def make_base_capture_template(*pnames: PName) -> CaptureTemplate:
|
203
147
|
"""Make a capture template composed entirely of base `PTemplate` instances.
|
204
148
|
|
205
149
|
:param pnames: The names of parameters to include in the capture template.
|
@@ -207,12 +151,11 @@ def make_base_capture_template(
|
|
207
151
|
"""
|
208
152
|
capture_template = CaptureTemplate()
|
209
153
|
for pname in pnames:
|
210
|
-
capture_template.add_ptemplate(
|
154
|
+
capture_template.add_ptemplate(get_base_ptemplate(pname))
|
211
155
|
return capture_template
|
212
156
|
|
213
157
|
|
214
|
-
def _make_fixed_frequency_capture_template(
|
215
|
-
) -> CaptureTemplate:
|
158
|
+
def _make_fixed_frequency_capture_template() -> CaptureTemplate:
|
216
159
|
"""The absolute minimum required parameters for any fixed frequency capture template."""
|
217
160
|
capture_template = make_base_capture_template(
|
218
161
|
PName.BATCH_SIZE,
|
@@ -236,19 +179,17 @@ def _make_fixed_frequency_capture_template(
|
|
236
179
|
PName.WINDOW_TYPE,
|
237
180
|
)
|
238
181
|
capture_template.set_defaults(
|
239
|
-
|
240
|
-
|
241
|
-
|
182
|
+
(PName.EVENT_HANDLER_KEY, "fixed_center_frequency"),
|
183
|
+
(PName.BATCH_KEY, "iq_stream"),
|
184
|
+
(PName.WATCH_EXTENSION, "bin"),
|
242
185
|
)
|
243
186
|
capture_template.enforce_defaults(
|
244
|
-
PName.EVENT_HANDLER_KEY,
|
245
|
-
PName.BATCH_KEY,
|
246
|
-
PName.WATCH_EXTENSION
|
187
|
+
PName.EVENT_HANDLER_KEY, PName.BATCH_KEY, PName.WATCH_EXTENSION
|
247
188
|
)
|
248
189
|
return capture_template
|
249
190
|
|
250
|
-
|
251
|
-
) -> CaptureTemplate:
|
191
|
+
|
192
|
+
def _make_swept_frequency_capture_template() -> CaptureTemplate:
|
252
193
|
"""The absolute minimum required parameters for any swept frequency capture template."""
|
253
194
|
capture_template = make_base_capture_template(
|
254
195
|
PName.BATCH_SIZE,
|
@@ -272,29 +213,26 @@ def _make_swept_frequency_capture_template(
|
|
272
213
|
PName.WATCH_EXTENSION,
|
273
214
|
PName.WINDOW_HOP,
|
274
215
|
PName.WINDOW_SIZE,
|
275
|
-
PName.WINDOW_TYPE
|
216
|
+
PName.WINDOW_TYPE,
|
217
|
+
)
|
276
218
|
capture_template.set_defaults(
|
277
|
-
|
278
|
-
|
279
|
-
|
219
|
+
(PName.EVENT_HANDLER_KEY, "swept_center_frequency"),
|
220
|
+
(PName.BATCH_KEY, "iq_stream"),
|
221
|
+
(PName.WATCH_EXTENSION, "bin"),
|
280
222
|
)
|
281
223
|
capture_template.enforce_defaults(
|
282
|
-
PName.EVENT_HANDLER_KEY,
|
283
|
-
PName.BATCH_KEY,
|
284
|
-
PName.WATCH_EXTENSION
|
224
|
+
PName.EVENT_HANDLER_KEY, PName.BATCH_KEY, PName.WATCH_EXTENSION
|
285
225
|
)
|
286
226
|
return capture_template
|
287
227
|
|
288
228
|
|
289
229
|
_base_capture_templates: dict[CaptureMode, CaptureTemplate] = {
|
290
230
|
CaptureMode.FIXED_CENTER_FREQUENCY: _make_fixed_frequency_capture_template(),
|
291
|
-
CaptureMode.SWEPT_CENTER_FREQUENCY: _make_swept_frequency_capture_template()
|
231
|
+
CaptureMode.SWEPT_CENTER_FREQUENCY: _make_swept_frequency_capture_template(),
|
292
232
|
}
|
293
233
|
|
294
234
|
|
295
|
-
def get_base_capture_template(
|
296
|
-
capture_mode: CaptureMode
|
297
|
-
) -> CaptureTemplate:
|
235
|
+
def get_base_capture_template(capture_mode: CaptureMode) -> CaptureTemplate:
|
298
236
|
"""Get a pre-defined capture template, to be configured according to the specific use-case.
|
299
237
|
|
300
238
|
:param capture_mode: The mode used to retrieve the capture template.
|
@@ -302,6 +240,8 @@ def get_base_capture_template(
|
|
302
240
|
:raises KeyError: If no capture template is found for the given mode.
|
303
241
|
"""
|
304
242
|
if capture_mode not in _base_capture_templates:
|
305
|
-
raise KeyError(
|
306
|
-
|
307
|
-
|
243
|
+
raise KeyError(
|
244
|
+
f"No capture template found for the capture mode '{capture_mode}'. "
|
245
|
+
f"Expected one of {list(_base_capture_templates.keys())}"
|
246
|
+
)
|
247
|
+
return deepcopy(_base_capture_templates[capture_mode])
|
@@ -7,15 +7,13 @@ from typing import Any, Optional, TypeVar, Generic, Iterator, overload, cast
|
|
7
7
|
from ._pnames import PName
|
8
8
|
|
9
9
|
# value type
|
10
|
-
VT = TypeVar(
|
10
|
+
VT = TypeVar("VT")
|
11
|
+
|
11
12
|
|
12
13
|
class Parameter(Generic[VT]):
|
13
14
|
"""A simple container for a named value."""
|
14
|
-
|
15
|
-
|
16
|
-
name: PName,
|
17
|
-
value: Optional[VT] = None
|
18
|
-
) -> None:
|
15
|
+
|
16
|
+
def __init__(self, name: PName, value: Optional[VT] = None) -> None:
|
19
17
|
"""Initialise a `Parameter` instance.
|
20
18
|
|
21
19
|
:param name: The name of the parameter.
|
@@ -24,28 +22,18 @@ class Parameter(Generic[VT]):
|
|
24
22
|
self._name = name
|
25
23
|
self._value: Optional[VT] = value
|
26
24
|
|
27
|
-
|
28
25
|
@property
|
29
|
-
def name(
|
30
|
-
self
|
31
|
-
) -> PName:
|
26
|
+
def name(self) -> PName:
|
32
27
|
"""The parameter name."""
|
33
28
|
return self._name
|
34
|
-
|
35
29
|
|
36
30
|
@property
|
37
|
-
def value(
|
38
|
-
self
|
39
|
-
) -> Optional[VT]:
|
31
|
+
def value(self) -> Optional[VT]:
|
40
32
|
"""The parameter value."""
|
41
33
|
return self._value
|
42
|
-
|
43
|
-
|
34
|
+
|
44
35
|
@value.setter
|
45
|
-
def value(
|
46
|
-
self,
|
47
|
-
v: Optional[VT]
|
48
|
-
) -> None:
|
36
|
+
def value(self, v: Optional[VT]) -> None:
|
49
37
|
"""Update the parameter value.
|
50
38
|
|
51
39
|
:param v: The new value to set for the parameter.
|
@@ -55,26 +43,17 @@ class Parameter(Generic[VT]):
|
|
55
43
|
|
56
44
|
class Parameters:
|
57
45
|
"""A managed collection of parameters."""
|
58
|
-
|
59
|
-
|
60
|
-
) -> None:
|
46
|
+
|
47
|
+
def __init__(self) -> None:
|
61
48
|
"""Initialise a `Parameters` instance."""
|
62
49
|
self._parameters: dict[PName, Parameter] = {}
|
63
|
-
|
64
|
-
|
50
|
+
|
65
51
|
@property
|
66
|
-
def name_list(
|
67
|
-
self
|
68
|
-
) -> list[PName]:
|
52
|
+
def name_list(self) -> list[PName]:
|
69
53
|
"""List the names of stored parameters."""
|
70
54
|
return list(self._parameters.keys())
|
71
55
|
|
72
|
-
|
73
|
-
def add_parameter(
|
74
|
-
self,
|
75
|
-
name: PName,
|
76
|
-
value: Optional[VT]
|
77
|
-
) -> None:
|
56
|
+
def add_parameter(self, name: PName, value: Optional[VT]) -> None:
|
78
57
|
"""Add a `Parameter` instance to this `Parameters` instance with the input name and value.
|
79
58
|
|
80
59
|
:param name: The name of the parameter.
|
@@ -82,15 +61,13 @@ class Parameters:
|
|
82
61
|
:raises KeyError: If a parameter already exists under the input name.
|
83
62
|
"""
|
84
63
|
if name in self._parameters:
|
85
|
-
raise KeyError(
|
86
|
-
|
64
|
+
raise KeyError(
|
65
|
+
f"Cannot add a parameter with name '{name}', "
|
66
|
+
f"since a parameter already exists with that name. "
|
67
|
+
)
|
87
68
|
self._parameters[name] = Parameter(name, value)
|
88
69
|
|
89
|
-
|
90
|
-
def get_parameter(
|
91
|
-
self,
|
92
|
-
name: PName
|
93
|
-
) -> Parameter:
|
70
|
+
def get_parameter(self, name: PName) -> Parameter:
|
94
71
|
"""Get the stored `Parameter` instance corresponding to the input name.
|
95
72
|
|
96
73
|
:param name: The name of the parameter.
|
@@ -98,43 +75,33 @@ class Parameters:
|
|
98
75
|
:return: A `Parameter` instance with the input name, if it exists.
|
99
76
|
"""
|
100
77
|
if name not in self._parameters:
|
101
|
-
raise KeyError(
|
102
|
-
|
78
|
+
raise KeyError(
|
79
|
+
f"Parameter with name '{name}' does not exist. "
|
80
|
+
f"Expected one of {self.name_list}"
|
81
|
+
)
|
103
82
|
return self._parameters[name]
|
104
83
|
|
105
|
-
|
106
|
-
def get_parameter_value(
|
107
|
-
self,
|
108
|
-
name: PName
|
109
|
-
) -> Optional[VT]:
|
84
|
+
def get_parameter_value(self, name: PName) -> Optional[VT]:
|
110
85
|
"""Get the value of the parameter with the corresponding name.
|
111
86
|
|
112
87
|
:param name: The name of the parameter.
|
113
88
|
:return: The value of the parameter with the input name.
|
114
89
|
"""
|
115
90
|
return self.get_parameter(name).value
|
116
|
-
|
117
91
|
|
118
|
-
def __iter__(
|
119
|
-
self
|
120
|
-
) -> Iterator[Parameter]:
|
92
|
+
def __iter__(self) -> Iterator[Parameter]:
|
121
93
|
"""Iterate over stored parameters."""
|
122
|
-
yield from self._parameters.values()
|
94
|
+
yield from self._parameters.values()
|
123
95
|
|
124
|
-
|
125
|
-
def to_dict(
|
126
|
-
self
|
127
|
-
) -> dict[str, Optional[Any]]:
|
96
|
+
def to_dict(self) -> dict[str, Optional[Any]]:
|
128
97
|
"""Convert the `Parameters` instance to a serialisable dictionary.
|
129
98
|
|
130
99
|
:return: A dictionary representation of the stored parameters.
|
131
100
|
"""
|
132
101
|
return {p.name.value: p.value for p in self}
|
133
|
-
|
134
102
|
|
135
|
-
|
136
|
-
|
137
|
-
) -> list[str]:
|
103
|
+
|
104
|
+
def _parse_string_parameter(string_parameter: str) -> list[str]:
|
138
105
|
"""Parse string of the form `a=b` into a list of the form `[a, b]`.
|
139
106
|
|
140
107
|
:param string_parameter: A string representation of a capture config parameter.
|
@@ -142,18 +109,16 @@ def _parse_string_parameter(
|
|
142
109
|
:return: The parsed components of the input string parameter, using the `=` character as a separator.
|
143
110
|
The return list will always contain two elements.
|
144
111
|
"""
|
145
|
-
if not string_parameter or
|
112
|
+
if not string_parameter or "=" not in string_parameter:
|
146
113
|
raise ValueError(f"Invalid format: '{string_parameter}'. Expected 'KEY=VALUE'.")
|
147
|
-
if string_parameter.startswith(
|
114
|
+
if string_parameter.startswith("=") or string_parameter.endswith("="):
|
148
115
|
raise ValueError(f"Invalid format: '{string_parameter}'. Expected 'KEY=VALUE'.")
|
149
116
|
# remove leading and trailing whitespace.
|
150
117
|
string_parameter = string_parameter.strip()
|
151
|
-
return string_parameter.split(
|
152
|
-
|
153
|
-
|
154
|
-
def parse_string_parameters(
|
155
|
-
string_parameters: list[str]
|
156
|
-
) -> dict[str, str]:
|
118
|
+
return string_parameter.split("=", 1)
|
119
|
+
|
120
|
+
|
121
|
+
def parse_string_parameters(string_parameters: list[str]) -> dict[str, str]:
|
157
122
|
"""Parses a list of strings of the form `a=b` into a dictionary mapping each `a` to each `b`.
|
158
123
|
|
159
124
|
:param string_parameters: A list of strings, where each element is of the form `a=b`.
|
@@ -164,11 +129,9 @@ def parse_string_parameters(
|
|
164
129
|
k, v = _parse_string_parameter(string_parameter)
|
165
130
|
d[k] = v
|
166
131
|
return d
|
167
|
-
|
168
132
|
|
169
|
-
|
170
|
-
|
171
|
-
) -> Parameters:
|
133
|
+
|
134
|
+
def make_parameters(d: dict[str, Any]) -> Parameters:
|
172
135
|
"""Create a `Parameters` instance from the given dictionary. Each key is interpreted as a valid `PName`.
|
173
136
|
|
174
137
|
:param d: A dictionary where keys represent parameter names and values represent their corresponding values.
|
@@ -177,4 +140,4 @@ def make_parameters(
|
|
177
140
|
parameters = Parameters()
|
178
141
|
for k, v in d.items():
|
179
142
|
parameters.add_parameter(PName(k), v)
|
180
|
-
return parameters
|
143
|
+
return parameters
|