spectre-core 0.0.22__py3-none-any.whl → 0.0.23__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/_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 +13 -8
- spectre_core/config/_paths.py +18 -35
- 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 +13 -3
- spectre_core/plotting/_base.py +64 -138
- spectre_core/plotting/_format.py +10 -8
- spectre_core/plotting/_panel_names.py +7 -5
- spectre_core/plotting/_panel_stack.py +82 -115
- spectre_core/plotting/_panels.py +120 -155
- 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 +289 -322
- 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.23.dist-info}/METADATA +9 -23
- spectre_core-0.0.23.dist-info/RECORD +79 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.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.23.dist-info}/licenses/LICENSE +0 -0
- {spectre_core-0.0.22.dist-info → spectre_core-0.0.23.dist-info}/top_level.txt +0 -0
@@ -10,69 +10,63 @@ from scipy.signal import get_window
|
|
10
10
|
from ._parameters import Parameters
|
11
11
|
from ._pnames import PName
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
# `get_parameter_value` method. This is purely to signify intent and keep
|
16
|
-
# the static type checkers happy.
|
17
|
-
#
|
18
|
-
# This is okay, as whenever the validators are called, the parameter values
|
19
|
-
# have already been individually casted and constrained according to the
|
20
|
-
# parameter templates. There is negligible runtime impact. Though a bit
|
21
|
-
# of a pain for maintenance.
|
22
|
-
# ----------------------------------------------------------------------- #
|
23
|
-
|
24
|
-
|
25
|
-
def validate_window(
|
26
|
-
parameters: Parameters
|
27
|
-
) -> None:
|
13
|
+
|
14
|
+
def validate_window(parameters: Parameters) -> None:
|
28
15
|
"""Ensure that the capture config describes a valid window.
|
29
16
|
|
30
17
|
:param parameters: The parameters to be validated.
|
31
18
|
:raises ValueError: If the window interval is greater than the batch size.
|
32
|
-
:raises ValueError: If the specified window type cannot be fetched using
|
19
|
+
:raises ValueError: If the specified window type cannot be fetched using
|
33
20
|
the SciPy `get_window` function.
|
34
21
|
"""
|
35
22
|
window_size = cast(int, parameters.get_parameter_value(PName.WINDOW_SIZE))
|
36
23
|
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
37
|
-
batch_size
|
24
|
+
batch_size = cast(int, parameters.get_parameter_value(PName.BATCH_SIZE))
|
38
25
|
window_type = cast(str, parameters.get_parameter_value(PName.WINDOW_TYPE))
|
39
|
-
|
40
|
-
window_interval = window_size*(1 / sample_rate)
|
26
|
+
|
27
|
+
window_interval = window_size * (1 / sample_rate)
|
41
28
|
if window_interval > batch_size:
|
42
|
-
raise ValueError(
|
43
|
-
|
44
|
-
|
45
|
-
|
29
|
+
raise ValueError(
|
30
|
+
(
|
31
|
+
f"The windowing interval must be strictly less than the batch size. "
|
32
|
+
f"Computed the windowing interval to be {window_interval} [s], "
|
33
|
+
f"but the batch size is {batch_size} [s]"
|
34
|
+
)
|
35
|
+
)
|
36
|
+
|
46
37
|
try:
|
47
38
|
_ = get_window(window_type, window_size)
|
48
39
|
except Exception as e:
|
49
|
-
raise ValueError(
|
50
|
-
|
51
|
-
|
40
|
+
raise ValueError(
|
41
|
+
(f"An error has occurred while validating the window. " f"Got {str(e)}")
|
42
|
+
)
|
52
43
|
|
53
|
-
|
54
|
-
|
55
|
-
) -> None:
|
44
|
+
|
45
|
+
def validate_nyquist_criterion(parameters: Parameters) -> None:
|
56
46
|
"""Ensure that the Nyquist criterion is satisfied.
|
57
47
|
|
58
48
|
:param parameters: The parameters to be validated.
|
59
49
|
:raises ValueError: If the sample rate is less than the bandwidth.
|
60
50
|
"""
|
61
51
|
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
62
|
-
bandwidth
|
52
|
+
bandwidth = cast(float, parameters.get_parameter_value(PName.BANDWIDTH))
|
63
53
|
|
64
54
|
if sample_rate < bandwidth:
|
65
|
-
raise ValueError(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
55
|
+
raise ValueError(
|
56
|
+
(
|
57
|
+
f"Nyquist criterion has not been satisfied. "
|
58
|
+
f"Sample rate must be greater than or equal to the bandwidth. "
|
59
|
+
f"Got sample rate {sample_rate} [Hz], and bandwidth {bandwidth} [Hz]"
|
60
|
+
)
|
61
|
+
)
|
62
|
+
|
63
|
+
|
64
|
+
def _compute_num_steps_per_sweep(
|
65
|
+
min_freq: float, max_freq: float, freq_step: float
|
66
|
+
) -> int:
|
73
67
|
"""Compute the number of steps in one frequency sweep.
|
74
68
|
|
75
|
-
The center frequency starts at `min_freq` and increments in steps of `freq_step`
|
69
|
+
The center frequency starts at `min_freq` and increments in steps of `freq_step`
|
76
70
|
until the next step would exceed `max_freq`.
|
77
71
|
|
78
72
|
:param min_freq: The minimum frequency of the sweep.
|
@@ -83,92 +77,91 @@ def _compute_num_steps_per_sweep(min_freq: float,
|
|
83
77
|
return floor((max_freq - min_freq) / freq_step)
|
84
78
|
|
85
79
|
|
86
|
-
def validate_num_steps_per_sweep(
|
87
|
-
parameters: Parameters
|
88
|
-
) -> None:
|
80
|
+
def validate_num_steps_per_sweep(parameters: Parameters) -> None:
|
89
81
|
"""Ensure that there are at least two steps in frequency per sweep.
|
90
82
|
|
91
83
|
:param parameters: The parameters to be validated.
|
92
84
|
:raises ValueError: If the number of steps per sweep is less than or equal to one.
|
93
85
|
"""
|
94
|
-
min_freq
|
95
|
-
max_freq
|
96
|
-
freq_step
|
86
|
+
min_freq = cast(float, parameters.get_parameter_value(PName.MIN_FREQUENCY))
|
87
|
+
max_freq = cast(float, parameters.get_parameter_value(PName.MAX_FREQUENCY))
|
88
|
+
freq_step = cast(float, parameters.get_parameter_value(PName.FREQUENCY_STEP))
|
97
89
|
|
98
|
-
num_steps_per_sweep = _compute_num_steps_per_sweep(min_freq,
|
99
|
-
max_freq,
|
100
|
-
freq_step)
|
90
|
+
num_steps_per_sweep = _compute_num_steps_per_sweep(min_freq, max_freq, freq_step)
|
101
91
|
if num_steps_per_sweep <= 1:
|
102
|
-
raise ValueError(
|
103
|
-
|
104
|
-
|
92
|
+
raise ValueError(
|
93
|
+
(
|
94
|
+
f"We need strictly greater than one step per sweep. "
|
95
|
+
f"Computed {num_steps_per_sweep} step per sweep"
|
96
|
+
)
|
97
|
+
)
|
98
|
+
|
105
99
|
|
106
|
-
def validate_sweep_interval(
|
107
|
-
parameters: Parameters
|
108
|
-
) -> None:
|
100
|
+
def validate_sweep_interval(parameters: Parameters) -> None:
|
109
101
|
"""Ensure that the sweep interval is greater than the batch size.
|
110
102
|
|
111
103
|
:param parameters: The parameters to be validated.
|
112
104
|
:raises ValueError: If the sweep interval is greater than the batch size.
|
113
105
|
"""
|
114
|
-
min_freq
|
115
|
-
max_freq
|
116
|
-
freq_step
|
106
|
+
min_freq = cast(float, parameters.get_parameter_value(PName.MIN_FREQUENCY))
|
107
|
+
max_freq = cast(float, parameters.get_parameter_value(PName.MAX_FREQUENCY))
|
108
|
+
freq_step = cast(float, parameters.get_parameter_value(PName.FREQUENCY_STEP))
|
117
109
|
samples_per_step = cast(int, parameters.get_parameter_value(PName.SAMPLES_PER_STEP))
|
118
|
-
batch_size
|
119
|
-
sample_rate
|
110
|
+
batch_size = cast(int, parameters.get_parameter_value(PName.BATCH_SIZE))
|
111
|
+
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
120
112
|
|
121
|
-
num_steps_per_sweep = _compute_num_steps_per_sweep(min_freq,
|
122
|
-
max_freq,
|
123
|
-
freq_step)
|
113
|
+
num_steps_per_sweep = _compute_num_steps_per_sweep(min_freq, max_freq, freq_step)
|
124
114
|
num_samples_per_sweep = num_steps_per_sweep * samples_per_step
|
125
|
-
sweep_interval = num_samples_per_sweep * 1/sample_rate
|
115
|
+
sweep_interval = num_samples_per_sweep * 1 / sample_rate
|
126
116
|
if sweep_interval > batch_size:
|
127
|
-
raise ValueError(
|
128
|
-
|
129
|
-
|
130
|
-
|
117
|
+
raise ValueError(
|
118
|
+
(
|
119
|
+
f"Sweep interval must be less than the batch size. "
|
120
|
+
f"The computed sweep interval is {sweep_interval} [s], "
|
121
|
+
f"but the given batch size is {batch_size} [s]"
|
122
|
+
)
|
123
|
+
)
|
131
124
|
|
132
|
-
|
133
|
-
|
134
|
-
) -> None:
|
125
|
+
|
126
|
+
def validate_num_samples_per_step(parameters: Parameters) -> None:
|
135
127
|
"""Ensure that the number of samples per step is greater than the window size.
|
136
128
|
|
137
129
|
:param parameters: The parameters to be validated.
|
138
130
|
:raises ValueError: If the window size is greater than the number of samples per step.
|
139
131
|
"""
|
140
|
-
window_size
|
132
|
+
window_size = cast(int, parameters.get_parameter_value(PName.WINDOW_SIZE))
|
141
133
|
samples_per_step = cast(int, parameters.get_parameter_value(PName.SAMPLES_PER_STEP))
|
142
134
|
|
143
135
|
if window_size >= samples_per_step:
|
144
|
-
raise ValueError(
|
145
|
-
|
146
|
-
|
147
|
-
|
136
|
+
raise ValueError(
|
137
|
+
(
|
138
|
+
f"Window size must be strictly less than the number of samples per step. "
|
139
|
+
f"Got window size {window_size} [samples], which is more than or equal "
|
140
|
+
f"to the number of samples per step {samples_per_step}"
|
141
|
+
)
|
142
|
+
)
|
148
143
|
|
149
|
-
|
150
|
-
|
151
|
-
) -> None:
|
144
|
+
|
145
|
+
def validate_non_overlapping_steps(parameters: Parameters) -> None:
|
152
146
|
"""Ensure that the stepped spectrograms are non-overlapping in the frequency domain.
|
153
147
|
|
154
148
|
:param parameters: The parameters to be validated.
|
155
149
|
:raises NotImplementedError: If the spectrograms overlap in the frequency domain.
|
156
150
|
"""
|
157
|
-
|
158
|
-
freq_step
|
151
|
+
|
152
|
+
freq_step = cast(float, parameters.get_parameter_value(PName.FREQUENCY_STEP))
|
159
153
|
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
160
154
|
|
161
155
|
if freq_step < sample_rate:
|
162
|
-
raise NotImplementedError(
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
"""Ensure that the time elapsed collecting samples at a fixed frequency is greater
|
156
|
+
raise NotImplementedError(
|
157
|
+
f"SPECTRE does not yet support spectral steps overlapping in frequency. "
|
158
|
+
f"Got frequency step {freq_step * 1e-6} [MHz] which is less than the sample "
|
159
|
+
f"rate {sample_rate * 1e-6} [MHz]"
|
160
|
+
)
|
161
|
+
|
162
|
+
|
163
|
+
def validate_step_interval(parameters: Parameters, api_retuning_latency: float) -> None:
|
164
|
+
"""Ensure that the time elapsed collecting samples at a fixed frequency is greater
|
172
165
|
than the empirically derived API retuning latency.
|
173
166
|
|
174
167
|
:param parameters: The parameters to be validated.
|
@@ -176,12 +169,14 @@ def validate_step_interval(
|
|
176
169
|
:raises ValueError: If the time elapsed for a step is less than the API retuning latency.
|
177
170
|
"""
|
178
171
|
samples_per_step = cast(int, parameters.get_parameter_value(PName.SAMPLES_PER_STEP))
|
179
|
-
sample_rate
|
172
|
+
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
180
173
|
|
181
|
-
step_interval = samples_per_step * 1/ sample_rate
|
174
|
+
step_interval = samples_per_step * 1 / sample_rate # [s]
|
182
175
|
if step_interval < api_retuning_latency:
|
183
|
-
raise ValueError(
|
184
|
-
|
176
|
+
raise ValueError(
|
177
|
+
f"The computed step interval of {step_interval} [s] is of the order of empirically "
|
178
|
+
f"derived api latency {api_retuning_latency} [s]; you may experience undefined behaviour!"
|
179
|
+
)
|
185
180
|
|
186
181
|
|
187
182
|
def validate_sample_rate_with_master_clock_rate(
|
@@ -192,17 +187,19 @@ def validate_sample_rate_with_master_clock_rate(
|
|
192
187
|
:param parameters: The parameters to be validated.
|
193
188
|
:raises ValueError: If the master clock rate is not an integer multiple of the sample rate
|
194
189
|
"""
|
195
|
-
master_clock_rate = cast(
|
196
|
-
|
190
|
+
master_clock_rate = cast(
|
191
|
+
int, parameters.get_parameter_value(PName.MASTER_CLOCK_RATE)
|
192
|
+
)
|
193
|
+
sample_rate = cast(int, parameters.get_parameter_value(PName.SAMPLE_RATE))
|
197
194
|
|
198
195
|
if master_clock_rate % sample_rate != 0:
|
199
|
-
raise ValueError(
|
200
|
-
|
196
|
+
raise ValueError(
|
197
|
+
f"The master clock rate of {master_clock_rate} [Hz] is not an integer "
|
198
|
+
f"multiple of the sample rate {sample_rate} [Hz]."
|
199
|
+
)
|
201
200
|
|
202
201
|
|
203
|
-
def validate_fixed_center_frequency(
|
204
|
-
parameters: Parameters
|
205
|
-
) -> None:
|
202
|
+
def validate_fixed_center_frequency(parameters: Parameters) -> None:
|
206
203
|
"""Apply validators for capture config parameters describing fixed center frequency capture.
|
207
204
|
|
208
205
|
:param parameters: The parameters to be validated.
|
@@ -226,6 +223,6 @@ def validate_swept_center_frequency(
|
|
226
223
|
validate_num_steps_per_sweep(parameters)
|
227
224
|
validate_num_samples_per_step(parameters)
|
228
225
|
validate_sweep_interval(parameters)
|
229
|
-
|
226
|
+
|
230
227
|
if api_retuning_latency is not None:
|
231
228
|
validate_step_interval(parameters, api_retuning_latency)
|
spectre_core/config/__init__.py
CHANGED
@@ -6,14 +6,19 @@
|
|
6
6
|
"""General `spectre` package configurations."""
|
7
7
|
|
8
8
|
from ._paths import (
|
9
|
-
get_spectre_data_dir_path,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
get_spectre_data_dir_path,
|
10
|
+
get_batches_dir_path,
|
11
|
+
get_configs_dir_path,
|
12
|
+
get_logs_dir_path,
|
13
|
+
trim_spectre_data_dir_path,
|
14
14
|
)
|
15
|
+
from ._time_formats import TimeFormat
|
15
16
|
|
16
17
|
__all__ = [
|
17
|
-
"get_spectre_data_dir_path",
|
18
|
-
"
|
19
|
-
|
18
|
+
"get_spectre_data_dir_path",
|
19
|
+
"get_batches_dir_path",
|
20
|
+
"get_configs_dir_path",
|
21
|
+
"get_logs_dir_path",
|
22
|
+
"TimeFormat",
|
23
|
+
"trim_spectre_data_dir_path",
|
24
|
+
]
|
spectre_core/config/_paths.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
File system path definitions.
|
7
7
|
|
8
8
|
`spectre` uses the required environment variable `SPECTRE_DATA_DIR_PATH`
|
9
|
-
and creates three directories inside it:
|
9
|
+
and creates three directories inside it:
|
10
10
|
|
11
11
|
- `batches`: To hold the batched data files.
|
12
12
|
- `logs`: To hold log files generated at runtime.
|
@@ -20,17 +20,16 @@ _SPECTRE_DATA_DIR_PATH = os.environ.get("SPECTRE_DATA_DIR_PATH", "NOTSET")
|
|
20
20
|
if _SPECTRE_DATA_DIR_PATH == "NOTSET":
|
21
21
|
raise ValueError("The environment variable `SPECTRE_DATA_DIR_PATH` must be set.")
|
22
22
|
|
23
|
-
_BATCHES_DIR_PATH = os.path.join(_SPECTRE_DATA_DIR_PATH,
|
24
|
-
_LOGS_DIR_PATH
|
23
|
+
_BATCHES_DIR_PATH = os.path.join(_SPECTRE_DATA_DIR_PATH, "batches")
|
24
|
+
_LOGS_DIR_PATH = os.path.join(_SPECTRE_DATA_DIR_PATH, "logs")
|
25
25
|
_CONFIGS_DIR_PATH = os.path.join(_SPECTRE_DATA_DIR_PATH, "configs")
|
26
26
|
|
27
27
|
os.makedirs(_BATCHES_DIR_PATH, exist_ok=True)
|
28
|
-
os.makedirs(_LOGS_DIR_PATH,
|
28
|
+
os.makedirs(_LOGS_DIR_PATH, exist_ok=True)
|
29
29
|
os.makedirs(_CONFIGS_DIR_PATH, exist_ok=True)
|
30
30
|
|
31
31
|
|
32
|
-
def get_spectre_data_dir_path(
|
33
|
-
) -> str:
|
32
|
+
def get_spectre_data_dir_path() -> str:
|
34
33
|
"""The default ancestral path for all `spectre` file system data.
|
35
34
|
|
36
35
|
:return: The value stored by the `SPECTRE_DATA_DIR_PATH` environment variable.
|
@@ -39,10 +38,10 @@ def get_spectre_data_dir_path(
|
|
39
38
|
|
40
39
|
|
41
40
|
def _get_date_based_dir_path(
|
42
|
-
base_dir: str,
|
43
|
-
year: Optional[int] = None,
|
44
|
-
month: Optional[int] = None,
|
45
|
-
day: Optional[int] = None
|
41
|
+
base_dir: str,
|
42
|
+
year: Optional[int] = None,
|
43
|
+
month: Optional[int] = None,
|
44
|
+
day: Optional[int] = None,
|
46
45
|
) -> str:
|
47
46
|
"""Append a date-based directory onto the base directory.
|
48
47
|
|
@@ -58,7 +57,7 @@ def _get_date_based_dir_path(
|
|
58
57
|
raise ValueError("A day requires both a month and a year")
|
59
58
|
if month and not year:
|
60
59
|
raise ValueError("A month requires a year")
|
61
|
-
|
60
|
+
|
62
61
|
date_dir_components = []
|
63
62
|
if year:
|
64
63
|
date_dir_components.append(f"{year:04}")
|
@@ -66,14 +65,12 @@ def _get_date_based_dir_path(
|
|
66
65
|
date_dir_components.append(f"{month:02}")
|
67
66
|
if day:
|
68
67
|
date_dir_components.append(f"{day:02}")
|
69
|
-
|
68
|
+
|
70
69
|
return os.path.join(base_dir, *date_dir_components)
|
71
70
|
|
72
71
|
|
73
72
|
def get_batches_dir_path(
|
74
|
-
year: Optional[int] = None,
|
75
|
-
month: Optional[int] = None,
|
76
|
-
day: Optional[int] = None
|
73
|
+
year: Optional[int] = None, month: Optional[int] = None, day: Optional[int] = None
|
77
74
|
) -> str:
|
78
75
|
"""The directory in the file system containing the batched data files. Optionally, append
|
79
76
|
a date-based directory to the end of the path.
|
@@ -83,16 +80,11 @@ def get_batches_dir_path(
|
|
83
80
|
:param day: The numeric day. Defaults to None.
|
84
81
|
:return: The directory path for batched data files, optionally with a date-based subdirectory.
|
85
82
|
"""
|
86
|
-
return _get_date_based_dir_path(_BATCHES_DIR_PATH,
|
87
|
-
year,
|
88
|
-
month,
|
89
|
-
day)
|
83
|
+
return _get_date_based_dir_path(_BATCHES_DIR_PATH, year, month, day)
|
90
84
|
|
91
85
|
|
92
86
|
def get_logs_dir_path(
|
93
|
-
year: Optional[int] = None,
|
94
|
-
month: Optional[int] = None,
|
95
|
-
day: Optional[int] = None
|
87
|
+
year: Optional[int] = None, month: Optional[int] = None, day: Optional[int] = None
|
96
88
|
) -> str:
|
97
89
|
"""The directory in the file system containing the log files generated at runtime. Optionally, append
|
98
90
|
a date-based directory to the end of the path.
|
@@ -102,14 +94,10 @@ def get_logs_dir_path(
|
|
102
94
|
:param day: The numeric day. Defaults to None.
|
103
95
|
:return: The directory path for log files, optionally with a date-based subdirectory.
|
104
96
|
"""
|
105
|
-
return _get_date_based_dir_path(_LOGS_DIR_PATH,
|
106
|
-
year,
|
107
|
-
month,
|
108
|
-
day)
|
97
|
+
return _get_date_based_dir_path(_LOGS_DIR_PATH, year, month, day)
|
109
98
|
|
110
99
|
|
111
|
-
def get_configs_dir_path(
|
112
|
-
) -> str:
|
100
|
+
def get_configs_dir_path() -> str:
|
113
101
|
"""The directory in the file system containing the capture configs.
|
114
102
|
|
115
103
|
:return: The directory path for configuration files.
|
@@ -117,9 +105,7 @@ def get_configs_dir_path(
|
|
117
105
|
return _CONFIGS_DIR_PATH
|
118
106
|
|
119
107
|
|
120
|
-
def trim_spectre_data_dir_path(
|
121
|
-
full_path: str
|
122
|
-
) -> str:
|
108
|
+
def trim_spectre_data_dir_path(full_path: str) -> str:
|
123
109
|
"""Remove the `SPECTRE_DATA_DIR_PATH` prefix from a full file path.
|
124
110
|
|
125
111
|
This function returns the relative path of `full_path` with respect to
|
@@ -133,9 +119,7 @@ def trim_spectre_data_dir_path(
|
|
133
119
|
return os.path.relpath(full_path, _SPECTRE_DATA_DIR_PATH)
|
134
120
|
|
135
121
|
|
136
|
-
def add_spectre_data_dir_path(
|
137
|
-
rel_path: str
|
138
|
-
) -> str:
|
122
|
+
def add_spectre_data_dir_path(rel_path: str) -> str:
|
139
123
|
"""Prepend the `SPECTRE_DATA_DIR_PATH` prefix to a relative file path.
|
140
124
|
|
141
125
|
This function constructs an absolute path by joining the given relative
|
@@ -146,4 +130,3 @@ def add_spectre_data_dir_path(
|
|
146
130
|
:return: The full file path prefixed with `SPECTRE_DATA_DIR_PATH`.
|
147
131
|
"""
|
148
132
|
return os.path.join(_SPECTRE_DATA_DIR_PATH, rel_path)
|
149
|
-
|
@@ -15,8 +15,9 @@ class TimeFormat:
|
|
15
15
|
:ivar PRECISE_TIME: Format for times with microseconds (e.g., '23:59:59.123456').
|
16
16
|
:ivar PRECISE_DATETIME: Combined date and precise time format (e.g., '2025-01-11T23:59:59.123456').
|
17
17
|
"""
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
|
19
|
+
DATE = "%Y-%m-%d"
|
20
|
+
TIME = "%H:%M:%S"
|
21
|
+
DATETIME = f"{DATE}T{TIME}"
|
22
|
+
PRECISE_TIME = "%H:%M:%S.%f"
|
23
|
+
PRECISE_DATETIME = f"{DATE}T{PRECISE_TIME}"
|
spectre_core/exceptions.py
CHANGED
@@ -6,9 +6,47 @@
|
|
6
6
|
`spectre` custom exceptions.
|
7
7
|
"""
|
8
8
|
|
9
|
+
import warnings
|
10
|
+
from functools import wraps
|
11
|
+
from typing import TypeVar, Callable, Any, cast
|
12
|
+
|
13
|
+
F = TypeVar("F", bound=Callable[..., Any])
|
14
|
+
|
15
|
+
|
16
|
+
def deprecated(message: str) -> Callable[[F], F]:
|
17
|
+
"""A decorator to mark functions as deprecated.
|
18
|
+
|
19
|
+
:param message: Warning message explaining what to use instead
|
20
|
+
"""
|
21
|
+
|
22
|
+
def decorator(func: F) -> F:
|
23
|
+
@wraps(func)
|
24
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
25
|
+
warnings.warn(
|
26
|
+
f"{func.__name__} is deprecated. {message}",
|
27
|
+
category=DeprecationWarning,
|
28
|
+
stacklevel=2,
|
29
|
+
)
|
30
|
+
return func(*args, **kwargs)
|
31
|
+
|
32
|
+
return cast(F, wrapper)
|
33
|
+
|
34
|
+
return decorator
|
35
|
+
|
36
|
+
|
9
37
|
class BatchNotFoundError(KeyError): ...
|
38
|
+
|
39
|
+
|
10
40
|
class ModeNotFoundError(KeyError): ...
|
41
|
+
|
42
|
+
|
11
43
|
class EventHandlerNotFoundError(KeyError): ...
|
44
|
+
|
45
|
+
|
12
46
|
class ReceiverNotFoundError(KeyError): ...
|
47
|
+
|
48
|
+
|
13
49
|
class InvalidTagError(ValueError): ...
|
50
|
+
|
51
|
+
|
14
52
|
class InvalidSweepMetadataError(ValueError): ...
|
spectre_core/jobs/__init__.py
CHANGED
@@ -5,10 +5,7 @@
|
|
5
5
|
"""Manage `spectre` jobs and workers."""
|
6
6
|
|
7
7
|
from ._jobs import Job, start_job
|
8
|
-
from ._workers import
|
9
|
-
|
10
|
-
)
|
8
|
+
from ._workers import Worker, make_worker
|
9
|
+
from ._duration import Duration
|
11
10
|
|
12
|
-
__all__ = [
|
13
|
-
"Job", "Worker", "make_worker", "start_job", "do_capture", "do_post_processing"
|
14
|
-
]
|
11
|
+
__all__ = ["Job", "Worker", "make_worker", "start_job", "Duration"]
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# SPDX-FileCopyrightText: © 2024-2025 Jimmy Fitzpatrick <jcfitzpatrick12@gmail.com>
|
2
|
+
# This file is part of SPECTRE
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
4
|
+
|
5
|
+
|
6
|
+
class Duration:
|
7
|
+
"""A selection of set durations, in seconds."""
|
8
|
+
|
9
|
+
ONE_CENTISECOND = 0.01
|
10
|
+
ONE_DECISECOND = 0.1
|
11
|
+
ONE_SECOND = 1.0
|
12
|
+
TEN_SECONDS = 10.0
|