labmate 0.10.5__py3-none-any.whl → 0.10.6__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.
- labmate/__config__.py +1 -1
- labmate/acquisition/__init__.py +1 -1
- labmate/acquisition/acquisition_loop.py +11 -18
- labmate/acquisition/acquisition_manager.py +28 -48
- labmate/acquisition/analysis_data.py +15 -25
- labmate/acquisition/analysis_loop.py +9 -7
- labmate/acquisition/backend.py +2 -0
- labmate/acquisition/config_file.py +5 -3
- labmate/acquisition/custom_lint.py +2 -3
- labmate/acquisition_notebook/__init__.py +2 -2
- labmate/acquisition_notebook/acquisition_analysis_manager.py +24 -47
- labmate/acquisition_notebook/display_widget.py +9 -9
- labmate/attrdict/attrdict_class.py +4 -10
- labmate/display/__init__.py +2 -3
- labmate/display/buttons.py +1 -0
- labmate/display/links.py +2 -1
- labmate/display/main.py +3 -2
- labmate/display/platform_utils/__init__.py +3 -1
- labmate/display/platform_utils/windows_utils.py +3 -9
- labmate/parsing/__init__.py +3 -5
- labmate/parsing/parsed_value.py +30 -10
- labmate/parsing/saving.py +2 -6
- labmate/utils/async_utils.py +1 -0
- labmate/utils/autoreload.py +2 -0
- labmate/utils/file_read.py +12 -13
- labmate/utils/lint.py +9 -11
- labmate/utils/random_utils.py +1 -0
- labmate/utils/title_parsing.py +4 -14
- {labmate-0.10.5.dist-info → labmate-0.10.6.dist-info}/METADATA +1 -1
- labmate-0.10.6.dist-info/RECORD +41 -0
- {labmate-0.10.5.dist-info → labmate-0.10.6.dist-info}/WHEEL +1 -1
- labmate-0.10.5.dist-info/RECORD +0 -41
- {labmate-0.10.5.dist-info → labmate-0.10.6.dist-info}/licenses/LICENCE +0 -0
- {labmate-0.10.5.dist-info → labmate-0.10.6.dist-info}/top_level.txt +0 -0
labmate/__config__.py
CHANGED
labmate/acquisition/__init__.py
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
from .acquisition_data import NotebookAcquisitionData
|
|
3
3
|
from .acquisition_loop import AcquisitionLoop
|
|
4
4
|
from .acquisition_manager import AcquisitionManager
|
|
5
|
-
from .backend import AcquisitionBackend
|
|
6
5
|
from .analysis_data import AnalysisData, FigureProtocol
|
|
7
6
|
from .analysis_loop import AnalysisLoop
|
|
7
|
+
from .backend import AcquisitionBackend
|
|
@@ -96,9 +96,7 @@ class AcquisitionLoop(DH5):
|
|
|
96
96
|
) -> Iterator:
|
|
97
97
|
"""Return np.arange(start, stop, step) given a start, stop and step."""
|
|
98
98
|
|
|
99
|
-
def __call__(
|
|
100
|
-
self, *args, iterable: Optional[Iterable] = None, **kwds
|
|
101
|
-
) -> Optional[Iterator]:
|
|
99
|
+
def __call__(self, *args, iterable: Optional[Iterable] = None, **kwds) -> Optional[Iterator]:
|
|
102
100
|
"""Append_data or arange.
|
|
103
101
|
|
|
104
102
|
If kwds are provided then is same as calling append_data(kwds),
|
|
@@ -115,10 +113,11 @@ class AcquisitionLoop(DH5):
|
|
|
115
113
|
return None
|
|
116
114
|
|
|
117
115
|
if iterable is None:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
iterable = (
|
|
117
|
+
np.arange(*args)
|
|
118
|
+
if isinstance(args[0], (int, float, np.int_, np.floating)) # type: ignore
|
|
119
|
+
else args[0]
|
|
120
|
+
)
|
|
122
121
|
|
|
123
122
|
if iterable is None:
|
|
124
123
|
raise ValueError("You should provide an iterable")
|
|
@@ -166,8 +165,8 @@ class AcquisitionLoop(DH5):
|
|
|
166
165
|
if len(key_shape) < len(self[key].shape):
|
|
167
166
|
raise ValueError(
|
|
168
167
|
f"Object {key} hasn't the same shape as before. Now it's"
|
|
169
|
-
f" {key_shape[len(shape):]},"
|
|
170
|
-
f" but before it was {self[key].shape[len(shape):]}."
|
|
168
|
+
f" {key_shape[len(shape) :]},"
|
|
169
|
+
f" but before it was {self[key].shape[len(shape) :]}."
|
|
171
170
|
)
|
|
172
171
|
if len(key_shape) > len(self[key].shape):
|
|
173
172
|
raise ValueError(
|
|
@@ -178,9 +177,7 @@ class AcquisitionLoop(DH5):
|
|
|
178
177
|
self[key] = SyncNp(
|
|
179
178
|
np.pad(
|
|
180
179
|
self[key],
|
|
181
|
-
pad_width=tuple(
|
|
182
|
-
(0, i - j) for i, j in zip(key_shape, self[key].shape)
|
|
183
|
-
),
|
|
180
|
+
pad_width=tuple((0, i - j) for i, j in zip(key_shape, self[key].shape)),
|
|
184
181
|
)
|
|
185
182
|
)
|
|
186
183
|
self[key][iteration] = value
|
|
@@ -201,9 +198,7 @@ class AcquisitionLoop(DH5):
|
|
|
201
198
|
):
|
|
202
199
|
if length is None:
|
|
203
200
|
if not hasattr(iterable, "__len__"):
|
|
204
|
-
raise TypeError(
|
|
205
|
-
"Iterable should has __len__ method or length should be provided"
|
|
206
|
-
)
|
|
201
|
+
raise TypeError("Iterable should has __len__ method or length should be provided")
|
|
207
202
|
length = len(iterable) # type: ignore
|
|
208
203
|
|
|
209
204
|
def loop_iter(array, length):
|
|
@@ -283,9 +278,7 @@ class AcquisitionLoop(DH5):
|
|
|
283
278
|
"""
|
|
284
279
|
if key is None:
|
|
285
280
|
if not self._save_indexes:
|
|
286
|
-
raise ValueError(
|
|
287
|
-
"As indexes are not saved with the Loop, key should be provided."
|
|
288
|
-
)
|
|
281
|
+
raise ValueError("As indexes are not saved with the Loop, key should be provided.")
|
|
289
282
|
key = f"__index_{self._level}__"
|
|
290
283
|
|
|
291
284
|
iteration = tuple(self._iteration[: self._level])
|
|
@@ -2,13 +2,14 @@ import os
|
|
|
2
2
|
from concurrent.futures import Future, ThreadPoolExecutor
|
|
3
3
|
from typing import (
|
|
4
4
|
TYPE_CHECKING,
|
|
5
|
+
Any,
|
|
5
6
|
Dict,
|
|
7
|
+
Iterable,
|
|
6
8
|
List,
|
|
7
9
|
NamedTuple,
|
|
8
10
|
Optional,
|
|
9
11
|
Tuple,
|
|
10
12
|
Union,
|
|
11
|
-
Iterable,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
15
|
from dh5 import jsn
|
|
@@ -19,6 +20,7 @@ from ..utils import get_timestamp
|
|
|
19
20
|
from ..utils.file_read import read_file, read_files
|
|
20
21
|
from .acquisition_data import NotebookAcquisitionData
|
|
21
22
|
|
|
23
|
+
|
|
22
24
|
if TYPE_CHECKING:
|
|
23
25
|
from .backend import AcquisitionBackend
|
|
24
26
|
|
|
@@ -57,14 +59,12 @@ class AcquisitionManager:
|
|
|
57
59
|
|
|
58
60
|
def __init__(
|
|
59
61
|
self,
|
|
60
|
-
data_directory: Optional[Union[str, Path]] = None,
|
|
62
|
+
data_directory: Optional[Union[str, Path, Any]] = None,
|
|
61
63
|
*,
|
|
62
64
|
config_files: Optional[List[str]] = None,
|
|
63
65
|
save_files: Optional[bool] = None,
|
|
64
66
|
save_on_edit: Optional[bool] = None,
|
|
65
|
-
backend: Optional[
|
|
66
|
-
Union["AcquisitionBackend", Iterable["AcquisitionBackend"]]
|
|
67
|
-
] = None,
|
|
67
|
+
backend: Optional[Union["AcquisitionBackend", Iterable["AcquisitionBackend"]]] = None,
|
|
68
68
|
):
|
|
69
69
|
if save_files is not None:
|
|
70
70
|
self._save_files = save_files
|
|
@@ -89,7 +89,11 @@ class AcquisitionManager:
|
|
|
89
89
|
self._configs_last_modified = []
|
|
90
90
|
|
|
91
91
|
if data_directory is not None:
|
|
92
|
-
self.data_directory =
|
|
92
|
+
self.data_directory = (
|
|
93
|
+
Path(str(data_directory))
|
|
94
|
+
if not isinstance(data_directory, Path)
|
|
95
|
+
else data_directory
|
|
96
|
+
)
|
|
93
97
|
elif "ACQUISITION_DIR" in os.environ:
|
|
94
98
|
self.data_directory = Path(os.environ["ACQUISITION_DIR"])
|
|
95
99
|
else:
|
|
@@ -134,13 +138,9 @@ class AcquisitionManager:
|
|
|
134
138
|
configs: dict of configurations files to save
|
|
135
139
|
directory: directory where the data is stored
|
|
136
140
|
"""
|
|
137
|
-
acquisition_tmp_data = self._acquisition_tmp_data or self.get_temp_data(
|
|
138
|
-
self.temp_file_path
|
|
139
|
-
)
|
|
141
|
+
acquisition_tmp_data = self._acquisition_tmp_data or self.get_temp_data(self.temp_file_path)
|
|
140
142
|
if acquisition_tmp_data is None:
|
|
141
|
-
raise ValueError(
|
|
142
|
-
"You should create a new acquisition. It will create temp.json file."
|
|
143
|
-
)
|
|
143
|
+
raise ValueError("You should create a new acquisition. It will create temp.json file.")
|
|
144
144
|
return acquisition_tmp_data
|
|
145
145
|
|
|
146
146
|
@acquisition_tmp_data.setter
|
|
@@ -162,12 +162,10 @@ class AcquisitionManager:
|
|
|
162
162
|
filename = [str(filename)]
|
|
163
163
|
|
|
164
164
|
self.config_files = list(filename)
|
|
165
|
-
self._config_files_names_to_path = {
|
|
166
|
-
os.path.basename(file): file for file in self.config_files
|
|
167
|
-
}
|
|
165
|
+
self._config_files_names_to_path = {Path(file).name: file for file in self.config_files}
|
|
168
166
|
|
|
169
167
|
for config_file in self.config_files:
|
|
170
|
-
if not
|
|
168
|
+
if not Path(config_file).exists():
|
|
171
169
|
raise ValueError(f"Configuration file at {config_file} does not exist")
|
|
172
170
|
|
|
173
171
|
return self
|
|
@@ -177,7 +175,7 @@ class AcquisitionManager:
|
|
|
177
175
|
raise ValueError(
|
|
178
176
|
"Configuration file should be specified before with set_config_file function"
|
|
179
177
|
)
|
|
180
|
-
self.config_files_eval[
|
|
178
|
+
self.config_files_eval[Path(file).name] = module
|
|
181
179
|
|
|
182
180
|
def set_init_analyse_file(self, filename: Union[str, Path]) -> None:
|
|
183
181
|
if not isinstance(filename, Path):
|
|
@@ -194,22 +192,18 @@ class AcquisitionManager:
|
|
|
194
192
|
if not experiment_path.exists():
|
|
195
193
|
experiment_path.makedirs()
|
|
196
194
|
# Copy init_analyses code to the experiment directory if it does not exist
|
|
197
|
-
if self._init_code and not
|
|
198
|
-
with open(
|
|
199
|
-
experiment_path / "init_analyse.py", "w", encoding="utf-8"
|
|
200
|
-
) as file:
|
|
195
|
+
if self._init_code and not (experiment_path / "init_analyse.py").exists():
|
|
196
|
+
with open(experiment_path / "init_analyse.py", "w", encoding="utf-8") as file:
|
|
201
197
|
file.write(self._init_code)
|
|
202
198
|
|
|
203
|
-
filepath_original = filepath =
|
|
204
|
-
experiment_path / f"{dic.time_stamp}__{dic.experiment_name}"
|
|
205
|
-
)
|
|
199
|
+
filepath_original = filepath = experiment_path / f"{dic.time_stamp}__{dic.experiment_name}"
|
|
206
200
|
|
|
207
201
|
# If ignore existence is True, no check is required
|
|
208
202
|
if ignore_existence:
|
|
209
203
|
return filepath
|
|
210
204
|
# If the file already exists, add a suffix to the name
|
|
211
205
|
index = 1
|
|
212
|
-
while
|
|
206
|
+
while (filepath + ".h5").exists():
|
|
213
207
|
filepath = filepath_original + f"__{index}"
|
|
214
208
|
index += 1
|
|
215
209
|
|
|
@@ -217,16 +211,14 @@ class AcquisitionManager:
|
|
|
217
211
|
|
|
218
212
|
@staticmethod
|
|
219
213
|
def get_temp_data(path: Path) -> Optional[AcquisitionTmpData]:
|
|
220
|
-
if not
|
|
214
|
+
if not Path(path).exists():
|
|
221
215
|
return None
|
|
222
216
|
return AcquisitionTmpData(**jsn.read(path))
|
|
223
217
|
|
|
224
218
|
def _get_configs_last_modified(self) -> List[float]:
|
|
225
|
-
return [
|
|
219
|
+
return [Path(file).stat().st_mtime for file in self.config_files]
|
|
226
220
|
|
|
227
|
-
def _schedule_backend_save(
|
|
228
|
-
self, acquisition: NotebookAcquisitionData
|
|
229
|
-
) -> Optional[Future]:
|
|
221
|
+
def _schedule_backend_save(self, acquisition: NotebookAcquisitionData) -> Optional[Future]:
|
|
230
222
|
if self._backend is None:
|
|
231
223
|
return None
|
|
232
224
|
|
|
@@ -245,9 +237,7 @@ class AcquisitionManager:
|
|
|
245
237
|
future.add_done_callback(shutdown_executor)
|
|
246
238
|
return future
|
|
247
239
|
|
|
248
|
-
def _schedule_backend_load(
|
|
249
|
-
self, acquisition: NotebookAcquisitionData
|
|
250
|
-
) -> Optional[Future]:
|
|
240
|
+
def _schedule_backend_load(self, acquisition: NotebookAcquisitionData) -> Optional[Future]:
|
|
251
241
|
if self._backend is None:
|
|
252
242
|
return None
|
|
253
243
|
|
|
@@ -277,9 +267,7 @@ class AcquisitionManager:
|
|
|
277
267
|
self._configs_last_modified = self._get_configs_last_modified()
|
|
278
268
|
|
|
279
269
|
if self.config_files_eval:
|
|
280
|
-
configs = append_values_from_modules_to_files(
|
|
281
|
-
configs, self.config_files_eval
|
|
282
|
-
)
|
|
270
|
+
configs = append_values_from_modules_to_files(configs, self.config_files_eval)
|
|
283
271
|
|
|
284
272
|
dic = AcquisitionTmpData(
|
|
285
273
|
experiment_name=name,
|
|
@@ -290,9 +278,7 @@ class AcquisitionManager:
|
|
|
290
278
|
|
|
291
279
|
self.acquisition_tmp_data = dic
|
|
292
280
|
|
|
293
|
-
self._current_acquisition = self.get_acquisition(
|
|
294
|
-
replace=True, save_on_edit=save_on_edit
|
|
295
|
-
)
|
|
281
|
+
self._current_acquisition = self.get_acquisition(replace=True, save_on_edit=save_on_edit)
|
|
296
282
|
|
|
297
283
|
return self.current_acquisition
|
|
298
284
|
|
|
@@ -306,9 +292,7 @@ class AcquisitionManager:
|
|
|
306
292
|
configs = read_files(self.config_files)
|
|
307
293
|
|
|
308
294
|
if self.config_files_eval:
|
|
309
|
-
configs = append_values_from_modules_to_files(
|
|
310
|
-
configs, self.config_files_eval
|
|
311
|
-
)
|
|
295
|
+
configs = append_values_from_modules_to_files(configs, self.config_files_eval)
|
|
312
296
|
|
|
313
297
|
if name is None:
|
|
314
298
|
name = self.current_experiment_name + "_item"
|
|
@@ -356,17 +340,13 @@ class AcquisitionManager:
|
|
|
356
340
|
|
|
357
341
|
@property
|
|
358
342
|
def current_experiment_name(self) -> str:
|
|
359
|
-
return
|
|
360
|
-
self.acquisition_tmp_data.experiment_name
|
|
361
|
-
) # self.current_acquisition.name
|
|
343
|
+
return self.acquisition_tmp_data.experiment_name # self.current_acquisition.name
|
|
362
344
|
|
|
363
345
|
def get_acquisition(
|
|
364
346
|
self, replace: Optional[bool] = False, save_on_edit: Optional[bool] = None
|
|
365
347
|
) -> NotebookAcquisitionData:
|
|
366
348
|
acquisition_tmp_data = self.acquisition_tmp_data
|
|
367
|
-
filepath = self.create_path_from_tmp_data(
|
|
368
|
-
acquisition_tmp_data, ignore_existence=True
|
|
369
|
-
)
|
|
349
|
+
filepath = self.create_path_from_tmp_data(acquisition_tmp_data, ignore_existence=True)
|
|
370
350
|
configs = acquisition_tmp_data.configs
|
|
371
351
|
configs = configs if configs else None
|
|
372
352
|
cell = self.cell
|
|
@@ -12,6 +12,7 @@ from ..logger import logger
|
|
|
12
12
|
from .analysis_loop import AnalysisLoop
|
|
13
13
|
from .config_file import ConfigFile
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
_T = TypeVar("_T", bound="AnalysisData")
|
|
16
17
|
|
|
17
18
|
|
|
@@ -115,7 +116,7 @@ class AnalysisData(DH5):
|
|
|
115
116
|
self._save_files = save_files
|
|
116
117
|
self._save_fig_inside_h5 = save_fig_inside_h5
|
|
117
118
|
|
|
118
|
-
self._default_config_files: Tuple[str, ...] =
|
|
119
|
+
self._default_config_files: Tuple[str, ...] = ()
|
|
119
120
|
if "info" in self and "default_config_files" in self["info"]:
|
|
120
121
|
self._default_config_files = tuple(self["info"]["default_config_files"])
|
|
121
122
|
|
|
@@ -158,9 +159,9 @@ class AnalysisData(DH5):
|
|
|
158
159
|
logger.warning("Analysis cell is not set. Nothing to save")
|
|
159
160
|
return self
|
|
160
161
|
|
|
161
|
-
self.unlock_data(cell_name_key).update({cell_name_key: code}).lock_data(
|
|
162
|
-
cell_name_key
|
|
163
|
-
)
|
|
162
|
+
self.unlock_data(cell_name_key).update({cell_name_key: code}).lock_data(cell_name_key).save(
|
|
163
|
+
[cell_name_key]
|
|
164
|
+
)
|
|
164
165
|
|
|
165
166
|
if self._save_files:
|
|
166
167
|
assert self.filepath, "You must set self.filepath before saving"
|
|
@@ -198,18 +199,14 @@ class AnalysisData(DH5):
|
|
|
198
199
|
"inside_h5", False
|
|
199
200
|
):
|
|
200
201
|
try:
|
|
201
|
-
raise NotImplementedError(
|
|
202
|
-
"save_fig_inside_h5 is not implemented for the moment."
|
|
203
|
-
)
|
|
202
|
+
raise NotImplementedError("save_fig_inside_h5 is not implemented for the moment.")
|
|
204
203
|
# import pltsave
|
|
205
204
|
|
|
206
205
|
# data = pltsave.dumps(fig).to_json()
|
|
207
206
|
# self[f"figures/{fig_name}"] = data
|
|
208
207
|
# self.save([f"figures/{fig_name}"])
|
|
209
208
|
except Exception as error:
|
|
210
|
-
logger.exception(
|
|
211
|
-
"Failed to save the figure inside h5 file due to %s", error
|
|
212
|
-
)
|
|
209
|
+
logger.exception("Failed to save the figure inside h5 file due to %s", error)
|
|
213
210
|
if tight_layout and hasattr(fig, "tight_layout"):
|
|
214
211
|
fig.tight_layout() # type: ignore
|
|
215
212
|
if metadata is None:
|
|
@@ -261,14 +258,12 @@ class AnalysisData(DH5):
|
|
|
261
258
|
name = str(name)
|
|
262
259
|
if not name.isnumeric() and name[0] != "_":
|
|
263
260
|
name = "_" + name
|
|
264
|
-
if
|
|
261
|
+
if Path(name).suffix == "": # check if name has no extension
|
|
265
262
|
name = f"{name}.{extensions}"
|
|
266
263
|
|
|
267
264
|
return "FIG" + name
|
|
268
265
|
|
|
269
|
-
def parse_config(
|
|
270
|
-
self, config_files: Optional[Tuple[str, ...]] = None
|
|
271
|
-
) -> "ConfigFile":
|
|
266
|
+
def parse_config(self, config_files: Optional[Tuple[str, ...]] = None) -> "ConfigFile":
|
|
272
267
|
"""Parse config files. If `config_files` are not provided takes `default_config_files`."""
|
|
273
268
|
|
|
274
269
|
config_files = config_files or self._default_config_files
|
|
@@ -303,9 +298,7 @@ class AnalysisData(DH5):
|
|
|
303
298
|
if key_value == "filename" or key_value == "file" or key_value == "f":
|
|
304
299
|
filename = os.path.split(self.filepath)[-1]
|
|
305
300
|
keys_with_values.append(
|
|
306
|
-
utils.title_parsing.ValueForPrint(
|
|
307
|
-
key_value, filename, key_units, key_format
|
|
308
|
-
)
|
|
301
|
+
utils.title_parsing.ValueForPrint(key_value, filename, key_units, key_format)
|
|
309
302
|
)
|
|
310
303
|
elif key_value in self:
|
|
311
304
|
keys_with_values.append(
|
|
@@ -358,9 +351,7 @@ class AnalysisData(DH5):
|
|
|
358
351
|
)
|
|
359
352
|
|
|
360
353
|
if config_file_name in self._parsed_configs:
|
|
361
|
-
self._parsed_configs[original_config_name] = self._parsed_configs[
|
|
362
|
-
config_file_name
|
|
363
|
-
]
|
|
354
|
+
self._parsed_configs[original_config_name] = self._parsed_configs[config_file_name]
|
|
364
355
|
return self._parsed_configs[config_file_name]
|
|
365
356
|
|
|
366
357
|
else:
|
|
@@ -393,16 +384,14 @@ class AnalysisData(DH5):
|
|
|
393
384
|
code: Optional[dict] = self.get("analysis_cells")
|
|
394
385
|
if code is None:
|
|
395
386
|
raise ValueError(
|
|
396
|
-
|
|
387
|
+
"There is no field 'analysis_cells' inside the data file. "
|
|
397
388
|
f"Possible keys are {tuple(self.keys())}."
|
|
398
389
|
)
|
|
399
390
|
|
|
400
391
|
# if isinstance(code, bytes):
|
|
401
392
|
# code = code.decode()
|
|
402
393
|
if name not in code:
|
|
403
|
-
raise KeyError(
|
|
404
|
-
f"Cannot get cell '{name}'. Possible cells are: {tuple(code.keys())}"
|
|
405
|
-
)
|
|
394
|
+
raise KeyError(f"Cannot get cell '{name}'. Possible cells are: {tuple(code.keys())}")
|
|
406
395
|
|
|
407
396
|
code_str: str = code[name]
|
|
408
397
|
if update_code:
|
|
@@ -426,7 +415,8 @@ class AnalysisData(DH5):
|
|
|
426
415
|
return figures
|
|
427
416
|
|
|
428
417
|
# raise NotImplementedError(
|
|
429
|
-
# "Not implemented for the moment. If you want to open an old figure.
|
|
418
|
+
# "Not implemented for the moment. If you want to open an old figure.
|
|
419
|
+
# Use open_old_figs function" )
|
|
430
420
|
|
|
431
421
|
def pull(self, force_pull: bool = False):
|
|
432
422
|
self._reset_attrs()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
It has mainly __iter__ method and __getitem__ method for slicing.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, List, Optional, Sequence, Tuple, Union
|
|
6
6
|
|
|
7
7
|
from dh5 import DH5
|
|
8
8
|
|
|
@@ -39,16 +39,14 @@ class AnalysisLoop(DH5):
|
|
|
39
39
|
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
def __init__(
|
|
43
|
-
self, data: Optional[dict] = None, loop_shape: Optional[List[int]] = None
|
|
44
|
-
):
|
|
42
|
+
def __init__(self, data: Optional[dict] = None, loop_shape: Optional[List[int]] = None):
|
|
45
43
|
"""Initialize an AnalysisLoop object.
|
|
46
44
|
|
|
47
45
|
Args:
|
|
48
46
|
data (Optional[dict]): A dictionary containing data to initialize the object with.
|
|
49
|
-
loop_shape (
|
|
47
|
+
loop_shape (list[int] | None): A list of ints representing the shape of the analysis loop.
|
|
50
48
|
If not provided, the shape is retrieved from the object's '__loop_shape__' attribute.
|
|
51
|
-
"""
|
|
49
|
+
""" # noqa: E501
|
|
52
50
|
super().__init__(data=data)
|
|
53
51
|
if loop_shape is None:
|
|
54
52
|
loop_shape = self.get("__loop_shape__")
|
|
@@ -86,7 +84,11 @@ class AnalysisLoop(DH5):
|
|
|
86
84
|
child_kwds[key] = value[index]
|
|
87
85
|
|
|
88
86
|
val = child_kwds[key]
|
|
89
|
-
if
|
|
87
|
+
if (
|
|
88
|
+
isinstance(val, (Sequence))
|
|
89
|
+
and len(val) == 1
|
|
90
|
+
and not isinstance(val[0], (Sequence))
|
|
91
|
+
): # type: ignore
|
|
90
92
|
child_kwds[key] = val[0] # type: ignore
|
|
91
93
|
|
|
92
94
|
if len(self._loop_shape) > 1:
|
labmate/acquisition/backend.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""ConfigFile class."""
|
|
2
|
+
|
|
2
3
|
from typing import Any
|
|
4
|
+
|
|
3
5
|
from .. import attrdict
|
|
4
6
|
|
|
5
7
|
|
|
@@ -43,8 +45,8 @@ class ConfigFile(attrdict.AttrDict):
|
|
|
43
45
|
raise ValueError("Content is not defined")
|
|
44
46
|
|
|
45
47
|
module = type(attrdict)("config_module")
|
|
46
|
-
cc = compile(self.content, "<string>", "exec")
|
|
47
|
-
eval(cc, module.__dict__)
|
|
48
|
+
cc = compile(self.content, "<string>", "exec")
|
|
49
|
+
eval(cc, module.__dict__)
|
|
48
50
|
return module
|
|
49
51
|
|
|
50
52
|
def eval_key(self, key) -> Any:
|
|
@@ -59,5 +61,5 @@ class ConfigFile(attrdict.AttrDict):
|
|
|
59
61
|
"""
|
|
60
62
|
val = self.get(key)
|
|
61
63
|
if val and val.value:
|
|
62
|
-
return eval(val.value)
|
|
64
|
+
return eval(val.value)
|
|
63
65
|
return None
|
|
@@ -5,6 +5,7 @@ from typing import Any, Dict
|
|
|
5
5
|
|
|
6
6
|
from ..utils.lint import get_all_args_from_call
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
SPECIAL_FUNCTIONS_LIST = []
|
|
9
10
|
|
|
10
11
|
|
|
@@ -25,9 +26,7 @@ def on_call_functions(node: ast.Call, db: Dict[str, Any]):
|
|
|
25
26
|
h = hash(tuple(get_all_args_from_call(node)))
|
|
26
27
|
data = db.setdefault("save_fig", [])
|
|
27
28
|
if h in data:
|
|
28
|
-
errors.append(
|
|
29
|
-
"save_fig with the save arguments is used more then ones."
|
|
30
|
-
)
|
|
29
|
+
errors.append("save_fig with the save arguments is used more then ones.")
|
|
31
30
|
|
|
32
31
|
data.append(h)
|
|
33
32
|
return errors
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# flake8: noqa: F401
|
|
2
|
+
from ..acquisition.acquisition_loop import AcquisitionLoop
|
|
3
|
+
from ..acquisition.analysis_data import AnalysisData
|
|
2
4
|
from .acquisition_analysis_manager import (
|
|
3
5
|
AcquisitionAnalysisManager,
|
|
4
6
|
AcquisitionAnalysisManagerDataOnly,
|
|
5
7
|
)
|
|
6
|
-
from ..acquisition.acquisition_loop import AcquisitionLoop
|
|
7
|
-
from ..acquisition.analysis_data import AnalysisData
|