labmate 0.10.4__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 +3 -2
- labmate/acquisition/acquisition_data.py +18 -0
- labmate/acquisition/acquisition_loop.py +11 -18
- labmate/acquisition/acquisition_manager.py +101 -41
- labmate/acquisition/analysis_data.py +15 -25
- labmate/acquisition/analysis_loop.py +9 -7
- labmate/acquisition/backend.py +24 -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 +30 -45
- 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.4.dist-info → labmate-0.10.6.dist-info}/METADATA +13 -2
- labmate-0.10.6.dist-info/RECORD +41 -0
- {labmate-0.10.4.dist-info → labmate-0.10.6.dist-info}/WHEEL +1 -1
- labmate-0.10.4.dist-info/RECORD +0 -40
- {labmate-0.10.4.dist-info → labmate-0.10.6.dist-info/licenses}/LICENCE +0 -0
- {labmate-0.10.4.dist-info → labmate-0.10.6.dist-info}/top_level.txt +0 -0
|
@@ -19,10 +19,12 @@ from ..acquisition import AcquisitionManager, AnalysisData
|
|
|
19
19
|
from ..logger import logger
|
|
20
20
|
from . import display_widget
|
|
21
21
|
|
|
22
|
+
|
|
22
23
|
if TYPE_CHECKING:
|
|
23
24
|
from dh5.path import Path
|
|
24
25
|
|
|
25
26
|
from ..acquisition import FigureProtocol
|
|
27
|
+
from ..acquisition.backend import AcquisitionBackend
|
|
26
28
|
from ..acquisition.config_file import ConfigFile
|
|
27
29
|
|
|
28
30
|
# from ..logger import Logger
|
|
@@ -65,7 +67,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
65
67
|
_analysis_cell_str = None
|
|
66
68
|
_is_old_data = False
|
|
67
69
|
_last_fig_name = None
|
|
68
|
-
_default_config_files: Tuple[str, ...] =
|
|
70
|
+
_default_config_files: Tuple[str, ...] = ()
|
|
69
71
|
_acquisition_started = 0
|
|
70
72
|
_linting_external_vars = None
|
|
71
73
|
_analysis_cell_prerun_hook: Optional[Tuple[_CallableWithNoArgs, ...]] = None
|
|
@@ -83,6 +85,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
83
85
|
save_on_edit_analysis: Optional[bool] = None,
|
|
84
86
|
save_fig_inside_h5: bool = False,
|
|
85
87
|
shell: Any = True,
|
|
88
|
+
backend: Optional[Union["AcquisitionBackend", Iterable["AcquisitionBackend"]]] = None,
|
|
86
89
|
):
|
|
87
90
|
"""
|
|
88
91
|
AcquisitionAnalysisManager.
|
|
@@ -115,7 +118,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
115
118
|
self.shell = shell
|
|
116
119
|
|
|
117
120
|
if use_magic:
|
|
118
|
-
from .acquisition_magic_class import load_ipython_extension
|
|
121
|
+
from .acquisition_magic_class import load_ipython_extension # pyright: ignore[reportMissingImports] # noqa: I001
|
|
119
122
|
|
|
120
123
|
load_ipython_extension(aqm=self, shell=self.shell)
|
|
121
124
|
|
|
@@ -131,6 +134,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
131
134
|
config_files=config_files,
|
|
132
135
|
save_files=save_files,
|
|
133
136
|
save_on_edit=save_on_edit,
|
|
137
|
+
backend=backend,
|
|
134
138
|
)
|
|
135
139
|
|
|
136
140
|
@property
|
|
@@ -173,7 +177,8 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
173
177
|
Args:
|
|
174
178
|
fig (Figure, optional): Figure that should be saved. Figure could be any class with
|
|
175
179
|
function save_fig implemented. By default gets plt.gcf().
|
|
176
|
-
name (str, optional): Name of the fig. It's a suffix that will be added to the filename.
|
|
180
|
+
name (str, optional): Name of the fig. It's a suffix that will be added to the filename.
|
|
181
|
+
Defaults to None.
|
|
177
182
|
extensions(str, optional): Extensions of the file. Defaults to `pdf`.
|
|
178
183
|
tight_layout(bool, optional): True to call fig.tight_layout(). Defaults to True.
|
|
179
184
|
|
|
@@ -220,6 +225,10 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
220
225
|
fig = fig or fig_or_name
|
|
221
226
|
self.save_fig_only(fig=fig, name=name, **kwds)
|
|
222
227
|
self.save_analysis_cell(name=name, cell=cell)
|
|
228
|
+
|
|
229
|
+
if self.current_acquisition is not None:
|
|
230
|
+
self._schedule_backend_save(self.current_acquisition)
|
|
231
|
+
|
|
223
232
|
if self._connected_widgets:
|
|
224
233
|
display_widget.display_widgets(
|
|
225
234
|
self._connected_widgets,
|
|
@@ -248,15 +257,12 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
248
257
|
acquisition_finished = time.time()
|
|
249
258
|
if not self._once_saved:
|
|
250
259
|
additional_info: Dict[str, Any] = {
|
|
251
|
-
"acquisition_duration": acquisition_finished
|
|
252
|
-
- self._acquisition_started,
|
|
260
|
+
"acquisition_duration": acquisition_finished - self._acquisition_started,
|
|
253
261
|
"logs": self.logger.getvalue(),
|
|
254
262
|
"prints": self.logger.get_stdout(),
|
|
255
263
|
}
|
|
256
264
|
if self._default_config_files:
|
|
257
|
-
additional_info.update(
|
|
258
|
-
{"default_config_files": self._default_config_files}
|
|
259
|
-
)
|
|
265
|
+
additional_info.update({"default_config_files": self._default_config_files})
|
|
260
266
|
kwds.update({"info": additional_info})
|
|
261
267
|
|
|
262
268
|
super().save_acquisition(update_, file_suffix=file_suffix, **kwds)
|
|
@@ -292,9 +298,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
292
298
|
- If default configuration files are provided, they are set in the loaded data.
|
|
293
299
|
"""
|
|
294
300
|
filename = self._get_full_filename(filename)
|
|
295
|
-
if not os.path.exists(
|
|
296
|
-
filename if filename.endswith(".h5") else filename + ".h5"
|
|
297
|
-
):
|
|
301
|
+
if not os.path.exists(filename if filename.endswith(".h5") else filename + ".h5"): # noqa: PTH110
|
|
298
302
|
raise ValueError(f"File {filename} cannot be found")
|
|
299
303
|
|
|
300
304
|
data = AnalysisData(
|
|
@@ -386,9 +390,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
386
390
|
display_warning("Old data analysis")
|
|
387
391
|
|
|
388
392
|
filename = str(filepath or self._get_full_filename(filename)) # type: ignore
|
|
389
|
-
filename = (
|
|
390
|
-
(filename.rsplit(".h5", 1)[0]) if filename.endswith(".h5") else filename
|
|
391
|
-
)
|
|
393
|
+
filename = (filename.rsplit(".h5", 1)[0]) if filename.endswith(".h5") else filename
|
|
392
394
|
|
|
393
395
|
else:
|
|
394
396
|
self._is_old_data = False
|
|
@@ -403,8 +405,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
403
405
|
)
|
|
404
406
|
or (
|
|
405
407
|
acquisition_name[0] == r"^"
|
|
406
|
-
and re.match(acquisition_name, self.current_experiment_name)
|
|
407
|
-
is None
|
|
408
|
+
and re.match(acquisition_name, self.current_experiment_name) is None
|
|
408
409
|
)
|
|
409
410
|
):
|
|
410
411
|
raise ValueError(
|
|
@@ -413,14 +414,14 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
413
414
|
)
|
|
414
415
|
|
|
415
416
|
filename = str(self.current_filepath) # without h5
|
|
416
|
-
self.logger.info(os.path.basename(filename))
|
|
417
|
+
self.logger.info(os.path.basename(filename)) # noqa: PTH119
|
|
417
418
|
|
|
418
419
|
if (
|
|
419
420
|
(not self._is_old_data)
|
|
420
421
|
and (self.shell is not None)
|
|
421
422
|
and (
|
|
422
|
-
"acquisition_cell(" in self.shell.last_execution_result.info.raw_cell
|
|
423
|
-
and not self.shell.last_execution_result.success
|
|
423
|
+
"acquisition_cell(" in self.shell.last_execution_result.info.raw_cell # type: ignore
|
|
424
|
+
and not self.shell.last_execution_result.success # type: ignore
|
|
424
425
|
)
|
|
425
426
|
):
|
|
426
427
|
raise ChildProcessError(
|
|
@@ -428,7 +429,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
428
429
|
"Check if everything is ok and executive again"
|
|
429
430
|
)
|
|
430
431
|
|
|
431
|
-
if os.path.exists(filename + ".h5"):
|
|
432
|
+
if os.path.exists(filename + ".h5"): # noqa: PTH110
|
|
432
433
|
self._load_analysis_data(filename)
|
|
433
434
|
else:
|
|
434
435
|
if self._is_old_data:
|
|
@@ -438,9 +439,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
438
439
|
if cell is not None:
|
|
439
440
|
self.save_analysis_cell(cell=cell)
|
|
440
441
|
|
|
441
|
-
if (self._analysis_cell_str is not None) and (
|
|
442
|
-
self._linting_external_vars is not None
|
|
443
|
-
):
|
|
442
|
+
if (self._analysis_cell_str is not None) and (self._linting_external_vars is not None):
|
|
444
443
|
from ..acquisition import custom_lint
|
|
445
444
|
from ..utils import lint
|
|
446
445
|
|
|
@@ -453,9 +452,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
453
452
|
run_on_call=custom_lint.on_call_functions,
|
|
454
453
|
)
|
|
455
454
|
for var in lint_result.external_vars:
|
|
456
|
-
self.logger.warning(
|
|
457
|
-
"External variable used inside the analysis code: %s", var
|
|
458
|
-
)
|
|
455
|
+
self.logger.warning("External variable used inside the analysis code: %s", var)
|
|
459
456
|
for error in lint_result.errors:
|
|
460
457
|
self.logger.warning(error)
|
|
461
458
|
|
|
@@ -480,15 +477,13 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
480
477
|
|
|
481
478
|
filepath = utils.get_path_from_filename(filename)
|
|
482
479
|
if isinstance(filepath, tuple):
|
|
483
|
-
return os.path.join(self.data_directory, *filepath)
|
|
480
|
+
return os.path.join(self.data_directory, *filepath) # noqa: PTH118
|
|
484
481
|
return filepath
|
|
485
482
|
|
|
486
483
|
def parse_config_file(self, config_file_name: str, /) -> "ConfigFile":
|
|
487
484
|
return self.data.parse_config_file(config_file_name)
|
|
488
485
|
|
|
489
|
-
def parse_config(
|
|
490
|
-
self, config_files: Optional[Tuple[str, ...]] = None
|
|
491
|
-
) -> "ConfigFile":
|
|
486
|
+
def parse_config(self, config_files: Optional[Tuple[str, ...]] = None) -> "ConfigFile":
|
|
492
487
|
return self.data.parse_config(config_files=config_files)
|
|
493
488
|
|
|
494
489
|
@property
|
|
@@ -510,16 +505,12 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
510
505
|
):
|
|
511
506
|
from ..utils import lint
|
|
512
507
|
|
|
513
|
-
allowed_variables = (
|
|
514
|
-
set() if allowed_variables is None else set(allowed_variables)
|
|
515
|
-
)
|
|
508
|
+
allowed_variables = set() if allowed_variables is None else set(allowed_variables)
|
|
516
509
|
if init_file is not None:
|
|
517
510
|
allowed_variables.update(lint.find_variables_from_file(init_file)[0])
|
|
518
511
|
self._linting_external_vars = allowed_variables
|
|
519
512
|
|
|
520
|
-
def set_default_config_files(
|
|
521
|
-
self, config_files: Union[str, Tuple[str, ...], List[str]], /
|
|
522
|
-
):
|
|
513
|
+
def set_default_config_files(self, config_files: Union[str, Tuple[str, ...], List[str]], /):
|
|
523
514
|
self._default_config_files = (
|
|
524
515
|
(config_files,) if isinstance(config_files, str) else tuple(config_files)
|
|
525
516
|
)
|
|
@@ -566,7 +557,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
566
557
|
if after_text is not None:
|
|
567
558
|
if not isinstance(params, str):
|
|
568
559
|
raise ValueError(
|
|
569
|
-
"Cannot use after_text with multiple params"
|
|
560
|
+
"Cannot use after_text with multiple params. "
|
|
570
561
|
"Use params=[(param, after_text), ...] instead."
|
|
571
562
|
)
|
|
572
563
|
return self.display_param_link(params=[(params, after_text)], title=title)
|
|
@@ -616,11 +607,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
616
607
|
self.update_config_params_on_disk({param: value})
|
|
617
608
|
|
|
618
609
|
buttons = (
|
|
619
|
-
[
|
|
620
|
-
display.buttons.create_button(
|
|
621
|
-
update_value, param, value, name="Update"
|
|
622
|
-
)
|
|
623
|
-
]
|
|
610
|
+
[display.buttons.create_button(update_value, param, value, name="Update")]
|
|
624
611
|
if update_button
|
|
625
612
|
else None
|
|
626
613
|
)
|
|
@@ -653,9 +640,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
653
640
|
|
|
654
641
|
def connect_default_widget(
|
|
655
642
|
self,
|
|
656
|
-
objs: Union[
|
|
657
|
-
"display_widget.WidgetProtocol", List["display_widget.WidgetProtocol"]
|
|
658
|
-
],
|
|
643
|
+
objs: Union["display_widget.WidgetProtocol", List["display_widget.WidgetProtocol"]],
|
|
659
644
|
):
|
|
660
645
|
if not isinstance(objs, (list, tuple)):
|
|
661
646
|
objs = [objs]
|
|
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, List, Optional, Protocol, TypeVar
|
|
|
4
4
|
from .. import display as lm_display
|
|
5
5
|
from ..display import platform_utils
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from labmate.acquisition_notebook import AcquisitionAnalysisManager
|
|
9
10
|
|
|
@@ -19,12 +20,11 @@ def _create_file_link(aqm: "AcquisitionAnalysisManager", level_up) -> str:
|
|
|
19
20
|
filepath = _get_filepath(aqm)
|
|
20
21
|
if filepath is None:
|
|
21
22
|
return ""
|
|
22
|
-
link_name = os.path.basename(filepath)
|
|
23
|
-
link = "/".join(
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
return link
|
|
23
|
+
link_name = os.path.basename(filepath) # noqa: PTH119
|
|
24
|
+
link = "/".join(os.path.abspath(filepath).replace("\\", "/").split("/")[-level_up:]).replace( # noqa: PTH100
|
|
25
|
+
" ", "%20"
|
|
26
|
+
)
|
|
27
|
+
return f"[{link_name}](//kyrylo-gr.github.io/h5viewer/open?url={link})"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def display_widgets(objs: List["WidgetProtocol"], *args, **kwargs):
|
|
@@ -193,14 +193,14 @@ class OpenFinderButton(BaseWidget):
|
|
|
193
193
|
import sys
|
|
194
194
|
|
|
195
195
|
def open_finder():
|
|
196
|
-
path = os.path.abspath(filepath) + ".h5"
|
|
196
|
+
path = os.path.abspath(filepath) + ".h5" # noqa: PTH100
|
|
197
197
|
if sys.platform == "win32":
|
|
198
198
|
path = path.replace("/", "\\")
|
|
199
199
|
subprocess.run(["explorer", "/select,", path], shell=True)
|
|
200
200
|
elif sys.platform == "darwin":
|
|
201
|
-
subprocess.Popen(["open", "-R", os.path.dirname(path)])
|
|
201
|
+
subprocess.Popen(["open", "-R", os.path.dirname(path)]) # noqa: PTH120
|
|
202
202
|
else:
|
|
203
|
-
subprocess.Popen(["nautilus", "--select", os.path.dirname(path)])
|
|
203
|
+
subprocess.Popen(["nautilus", "--select", os.path.dirname(path)]) # noqa: PTH120
|
|
204
204
|
|
|
205
205
|
self.widget = lm_display.buttons.create_button(open_finder, name="Open finder")
|
|
206
206
|
return self.widget
|
|
@@ -92,21 +92,15 @@ class AttrDict(dict):
|
|
|
92
92
|
keys_with_values = self.__get_value_for_output(keys)
|
|
93
93
|
return utils_parse.format_title(keys_with_values, max_length=max_length)
|
|
94
94
|
|
|
95
|
-
def __get_value_for_output(
|
|
96
|
-
|
|
97
|
-
) -> List[utils_parse.ValueForPrint]:
|
|
98
|
-
"""Prepare the values for output. Returns list of ValueForPrint(key, value, unit, format))."""
|
|
95
|
+
def __get_value_for_output(self, keys: List[str]) -> List[utils_parse.ValueForPrint]:
|
|
96
|
+
"""Prepare values for output. Returns list of ValueForPrint(key, value, unit, format)."""
|
|
99
97
|
keys_with_values = []
|
|
100
98
|
for key in keys:
|
|
101
99
|
key_value, key_units, key_format = utils_parse.parse_get_format(key)
|
|
102
100
|
if key_value in self:
|
|
103
101
|
keys_with_values.append(
|
|
104
|
-
utils_parse.ValueForPrint(
|
|
105
|
-
key_value, self[key_value], key_units, key_format
|
|
106
|
-
)
|
|
102
|
+
utils_parse.ValueForPrint(key_value, self[key_value], key_units, key_format)
|
|
107
103
|
)
|
|
108
104
|
else:
|
|
109
|
-
raise ValueError(
|
|
110
|
-
f"Cannot find key={key} inside {self.__class__.__name__}"
|
|
111
|
-
)
|
|
105
|
+
raise ValueError(f"Cannot find key={key} inside {self.__class__.__name__}")
|
|
112
106
|
return keys_with_values
|
labmate/display/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ from .main import (
|
|
|
10
10
|
logger,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
+
|
|
13
14
|
__all__ = ["links", "buttons", "logger", "html_output"]
|
|
14
15
|
|
|
15
16
|
|
|
@@ -20,9 +21,7 @@ class _LazyModule:
|
|
|
20
21
|
|
|
21
22
|
def __getattr__(self, name):
|
|
22
23
|
if self.__module is None:
|
|
23
|
-
self.__module = importlib.import_module(
|
|
24
|
-
f".{self.__name}", package=__package__
|
|
25
|
-
)
|
|
24
|
+
self.__module = importlib.import_module(f".{self.__name}", package=__package__)
|
|
26
25
|
return getattr(self.__module, name)
|
|
27
26
|
|
|
28
27
|
# @property
|
labmate/display/buttons.py
CHANGED
labmate/display/links.py
CHANGED
labmate/display/main.py
CHANGED
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import sys
|
|
5
5
|
from typing import Callable, List
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.WARNING)
|
|
8
9
|
logger = logging.getLogger(__name__)
|
|
9
10
|
handler = logging.StreamHandler()
|
|
@@ -28,13 +29,13 @@ except (ImportError, AttributeError):
|
|
|
28
29
|
# For testing purposes every IPython function should have a simpler version.
|
|
29
30
|
# pylint: disable=C0115, C0103, R0903
|
|
30
31
|
|
|
31
|
-
def HTML(text): # noqa: D103
|
|
32
|
+
def HTML(text): # noqa: D103, N802
|
|
32
33
|
return text
|
|
33
34
|
|
|
34
35
|
def display(text): # noqa: D103
|
|
35
36
|
logger.info(text)
|
|
36
37
|
|
|
37
|
-
class widgets: # noqa: D101
|
|
38
|
+
class widgets: # noqa: D101, N801
|
|
38
39
|
class Button: # noqa: D106
|
|
39
40
|
func: str
|
|
40
41
|
description: str
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"""This submodule contains functions that are specific for windows."""
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
def copy_fig(
|
|
5
|
-
fig=None, format_=None, text_to_copy=None, **kwargs
|
|
6
|
-
): # pragma: no cover <--
|
|
4
|
+
def copy_fig(fig=None, format_=None, text_to_copy=None, **kwargs): # pragma: no cover <--
|
|
7
5
|
"""Copy fig to the clipboard.
|
|
8
6
|
|
|
9
7
|
Parameters
|
|
@@ -73,9 +71,7 @@ def copy_fig(
|
|
|
73
71
|
im = Image.open(buf)
|
|
74
72
|
with BytesIO() as output:
|
|
75
73
|
im.convert("RGB").save(output, "BMP")
|
|
76
|
-
data = output.getvalue()[
|
|
77
|
-
14:
|
|
78
|
-
] # The file header off-set of BMP is 14 bytes
|
|
74
|
+
data = output.getvalue()[14:] # The file header off-set of BMP is 14 bytes
|
|
79
75
|
format_id = win32clipboard.CF_DIB # DIB = device independent bitmap
|
|
80
76
|
|
|
81
77
|
except ImportError:
|
|
@@ -89,8 +85,6 @@ def copy_fig(
|
|
|
89
85
|
win32clipboard.EmptyClipboard()
|
|
90
86
|
win32clipboard.SetClipboardData(format_id, data)
|
|
91
87
|
if text_to_copy:
|
|
92
|
-
win32clipboard.SetClipboardData(
|
|
93
|
-
win32clipboard.CF_TEXT, text_to_copy.encode("utf-8")
|
|
94
|
-
)
|
|
88
|
+
win32clipboard.SetClipboardData(win32clipboard.CF_TEXT, text_to_copy.encode("utf-8"))
|
|
95
89
|
|
|
96
90
|
win32clipboard.CloseClipboard()
|
labmate/parsing/__init__.py
CHANGED
|
@@ -10,10 +10,11 @@ Examples:
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
"""
|
|
13
|
+
|
|
13
14
|
from typing import Dict
|
|
14
15
|
|
|
15
|
-
from .parsed_value import ParsedValue
|
|
16
16
|
from .brackets_score import BracketsScore
|
|
17
|
+
from .parsed_value import ParsedValue
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
def parse_str(file: str, /) -> Dict[str, ParsedValue]:
|
|
@@ -36,10 +37,7 @@ def parse_str(file: str, /) -> Dict[str, ParsedValue]:
|
|
|
36
37
|
if not brackets.is_zero():
|
|
37
38
|
continue
|
|
38
39
|
|
|
39
|
-
if "# value: " in value
|
|
40
|
-
value_eval = value[value.rfind("# value: ") + 9 :]
|
|
41
|
-
else:
|
|
42
|
-
value_eval = None
|
|
40
|
+
value_eval = value[value.rfind("# value: ") + 9 :] if ("# value: " in value) else None
|
|
43
41
|
|
|
44
42
|
value = value.split("#")[0].strip()
|
|
45
43
|
|
labmate/parsing/parsed_value.py
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from typing import Any, Union
|
|
4
4
|
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def parse_value(value: str) -> Union[str, int, float]:
|
|
7
9
|
"""Convert str to int or float if possible."""
|
|
@@ -16,14 +18,14 @@ def parse_value(value: str) -> Union[str, int, float]:
|
|
|
16
18
|
value_without_underscores[0] == "-" and value[1:].isdigit()
|
|
17
19
|
):
|
|
18
20
|
return int(value)
|
|
19
|
-
elif value_without_underscores.replace(".", "").isdigit() or (
|
|
20
|
-
value[0] == "-" and value_without_underscores[1:].replace(".", "").isdigit()
|
|
21
|
-
):
|
|
22
|
-
return float(value)
|
|
23
21
|
elif (
|
|
24
|
-
(
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
value_without_underscores.replace(".", "").isdigit()
|
|
23
|
+
or (value[0] == "-" and value_without_underscores[1:].replace(".", "").isdigit())
|
|
24
|
+
or (
|
|
25
|
+
(value[0].isdigit() or (value[0] == "-" and value[1].isdigit()))
|
|
26
|
+
and value[-1].isdigit()
|
|
27
|
+
and "e" in value
|
|
28
|
+
)
|
|
27
29
|
):
|
|
28
30
|
return float(value)
|
|
29
31
|
except ValueError:
|
|
@@ -44,9 +46,11 @@ class ParsedValue:
|
|
|
44
46
|
|
|
45
47
|
Examples:
|
|
46
48
|
>>> v1 = ParsedValue("1", 1)
|
|
47
|
-
>>> v2 = ParsedValue("
|
|
49
|
+
>>> v2 = ParsedValue("6/3", 2)
|
|
48
50
|
>>> v1 + v2
|
|
49
51
|
3
|
|
52
|
+
>>> v2.unpack()
|
|
53
|
+
('6/3', 2)
|
|
50
54
|
|
|
51
55
|
"""
|
|
52
56
|
|
|
@@ -63,8 +67,11 @@ class ParsedValue:
|
|
|
63
67
|
self.original = parse_value(original)
|
|
64
68
|
self.value = parse_value(value)
|
|
65
69
|
|
|
66
|
-
def __iter__(self):
|
|
67
|
-
|
|
70
|
+
# def __iter__(self):
|
|
71
|
+
# return iter((self.original, self.value))
|
|
72
|
+
|
|
73
|
+
def unpack(self):
|
|
74
|
+
return self.original, self.value
|
|
68
75
|
|
|
69
76
|
def __str__(self) -> str:
|
|
70
77
|
return str(self.value)
|
|
@@ -81,9 +88,18 @@ class ParsedValue:
|
|
|
81
88
|
def __abs__(self) -> float:
|
|
82
89
|
return abs(self.value) # type: ignore
|
|
83
90
|
|
|
91
|
+
def __int__(self) -> int:
|
|
92
|
+
return int(self.value) # type: ignore
|
|
93
|
+
|
|
84
94
|
def __float__(self) -> float:
|
|
85
95
|
return float(self.value) # type: ignore
|
|
86
96
|
|
|
97
|
+
def __array__(self, dtype=None, **kwargs):
|
|
98
|
+
# So numpy/matplotlib can use it: np.asarray(obj) works
|
|
99
|
+
if dtype is not None:
|
|
100
|
+
return np.array(self.value, dtype=dtype, **kwargs)
|
|
101
|
+
return np.array(self.value, **kwargs)
|
|
102
|
+
|
|
87
103
|
def __neg__(self) -> float:
|
|
88
104
|
return -self.value # type: ignore
|
|
89
105
|
|
|
@@ -195,3 +211,7 @@ class ParsedValue:
|
|
|
195
211
|
if isinstance(other, ParsedValue):
|
|
196
212
|
return other.value
|
|
197
213
|
return other
|
|
214
|
+
|
|
215
|
+
def __hash__(self) -> int:
|
|
216
|
+
return hash(self.value)
|
|
217
|
+
# return hash((self.original, self.value))
|
labmate/parsing/saving.py
CHANGED
|
@@ -27,9 +27,7 @@ def append_values_from_modules_to_files(
|
|
|
27
27
|
return configs
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def append_values_from_module_to_file(
|
|
31
|
-
body: str, module, separator=" # value: "
|
|
32
|
-
) -> str:
|
|
30
|
+
def append_values_from_module_to_file(body: str, module, separator=" # value: ") -> str:
|
|
33
31
|
"""Add values from a module to a given file body.
|
|
34
32
|
|
|
35
33
|
Args:
|
|
@@ -68,9 +66,7 @@ def append_values_from_module_to_file(
|
|
|
68
66
|
for key, (val, _) in parse_str(line).items():
|
|
69
67
|
real_val = variables.get(key, "")
|
|
70
68
|
if (
|
|
71
|
-
isinstance(val, str)
|
|
72
|
-
and isinstance(real_val, str)
|
|
73
|
-
and real_val != val.strip("\"'")
|
|
69
|
+
isinstance(val, str) and isinstance(real_val, str) and real_val != val.strip("\"'")
|
|
74
70
|
) or (
|
|
75
71
|
isinstance(val, str)
|
|
76
72
|
and isinstance(real_val, (float, int, complex))
|
labmate/utils/async_utils.py
CHANGED
labmate/utils/autoreload.py
CHANGED
labmate/utils/file_read.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Different method to read files."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
import os
|
|
5
4
|
import re
|
|
5
|
+
from pathlib import Path
|
|
6
6
|
from typing import Any, Dict, List, Optional
|
|
7
7
|
|
|
8
8
|
from ..parsing.brackets_score import BracketsScore
|
|
@@ -20,13 +20,13 @@ def read_file(file: str, /) -> str:
|
|
|
20
20
|
Raises:
|
|
21
21
|
ValueError: If the file does not exist or is not a file.
|
|
22
22
|
"""
|
|
23
|
-
if not
|
|
23
|
+
if not Path(file).is_file():
|
|
24
24
|
raise ValueError(
|
|
25
|
-
"Cannot read a file if it doesn't exist or it's not a file."
|
|
26
|
-
f"Path: {
|
|
25
|
+
"Cannot read a file if it doesn't exist or it's not a file. "
|
|
26
|
+
f"Path: {Path(file).absolute()}"
|
|
27
27
|
)
|
|
28
28
|
|
|
29
|
-
with open(file,
|
|
29
|
+
with open(file, encoding="utf-8") as file_opened:
|
|
30
30
|
return file_opened.read()
|
|
31
31
|
|
|
32
32
|
|
|
@@ -40,15 +40,16 @@ def read_files(files: List[str], /) -> Dict[str, str]:
|
|
|
40
40
|
A dictionary where the keys are the file names and the values are the contents of the files.
|
|
41
41
|
|
|
42
42
|
Raises:
|
|
43
|
-
ValueError: If some of the files have the same name,
|
|
43
|
+
ValueError: If some of the files have the same name,
|
|
44
|
+
which would cause a key collision in the dict.
|
|
44
45
|
"""
|
|
45
46
|
configs: Dict[str, str] = {}
|
|
46
47
|
for config_file in files:
|
|
47
|
-
config_file_name =
|
|
48
|
+
config_file_name = Path(config_file).name
|
|
48
49
|
if config_file_name in configs:
|
|
49
50
|
raise ValueError(
|
|
50
|
-
"Some of the files have the same name.
|
|
51
|
-
" preserve unique key"
|
|
51
|
+
"Some of the files have the same name. "
|
|
52
|
+
"So it cannot be pushed into dict to preserve unique key"
|
|
52
53
|
)
|
|
53
54
|
configs[config_file_name] = read_file(config_file)
|
|
54
55
|
return configs
|
|
@@ -62,7 +63,7 @@ def update_file_variable(file, params: Dict[str, Any]):
|
|
|
62
63
|
file (str): The path to the file to update.
|
|
63
64
|
params (Dict[str, Any]): The parameters to update the file with.
|
|
64
65
|
"""
|
|
65
|
-
with open(file,
|
|
66
|
+
with open(file, encoding="utf-8") as file_opened:
|
|
66
67
|
lines = file_opened.readlines()
|
|
67
68
|
brackets = BracketsScore()
|
|
68
69
|
current_param: Optional[str] = None
|
|
@@ -87,9 +88,7 @@ def update_file_variable(file, params: Dict[str, Any]):
|
|
|
87
88
|
value_str = json.JSONEncoder().encode(params[current_param])
|
|
88
89
|
|
|
89
90
|
print("value_str", value_str)
|
|
90
|
-
if re.match(
|
|
91
|
-
r"^['\"]?[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?['\"]?$", value_str
|
|
92
|
-
):
|
|
91
|
+
if re.match(r"^['\"]?[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?['\"]?$", value_str):
|
|
93
92
|
value_str = value_str.replace('"', "")
|
|
94
93
|
|
|
95
94
|
lines.insert(
|