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
|
@@ -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,9 +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,
|
|
86
|
-
backend: Optional[
|
|
87
|
-
Union["AcquisitionBackend", Iterable["AcquisitionBackend"]]
|
|
88
|
-
] = None,
|
|
88
|
+
backend: Optional[Union["AcquisitionBackend", Iterable["AcquisitionBackend"]]] = None,
|
|
89
89
|
):
|
|
90
90
|
"""
|
|
91
91
|
AcquisitionAnalysisManager.
|
|
@@ -118,7 +118,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
118
118
|
self.shell = shell
|
|
119
119
|
|
|
120
120
|
if use_magic:
|
|
121
|
-
from .acquisition_magic_class import load_ipython_extension
|
|
121
|
+
from .acquisition_magic_class import load_ipython_extension # pyright: ignore[reportMissingImports] # noqa: I001
|
|
122
122
|
|
|
123
123
|
load_ipython_extension(aqm=self, shell=self.shell)
|
|
124
124
|
|
|
@@ -177,7 +177,8 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
177
177
|
Args:
|
|
178
178
|
fig (Figure, optional): Figure that should be saved. Figure could be any class with
|
|
179
179
|
function save_fig implemented. By default gets plt.gcf().
|
|
180
|
-
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.
|
|
181
182
|
extensions(str, optional): Extensions of the file. Defaults to `pdf`.
|
|
182
183
|
tight_layout(bool, optional): True to call fig.tight_layout(). Defaults to True.
|
|
183
184
|
|
|
@@ -256,15 +257,12 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
256
257
|
acquisition_finished = time.time()
|
|
257
258
|
if not self._once_saved:
|
|
258
259
|
additional_info: Dict[str, Any] = {
|
|
259
|
-
"acquisition_duration": acquisition_finished
|
|
260
|
-
- self._acquisition_started,
|
|
260
|
+
"acquisition_duration": acquisition_finished - self._acquisition_started,
|
|
261
261
|
"logs": self.logger.getvalue(),
|
|
262
262
|
"prints": self.logger.get_stdout(),
|
|
263
263
|
}
|
|
264
264
|
if self._default_config_files:
|
|
265
|
-
additional_info.update(
|
|
266
|
-
{"default_config_files": self._default_config_files}
|
|
267
|
-
)
|
|
265
|
+
additional_info.update({"default_config_files": self._default_config_files})
|
|
268
266
|
kwds.update({"info": additional_info})
|
|
269
267
|
|
|
270
268
|
super().save_acquisition(update_, file_suffix=file_suffix, **kwds)
|
|
@@ -300,9 +298,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
300
298
|
- If default configuration files are provided, they are set in the loaded data.
|
|
301
299
|
"""
|
|
302
300
|
filename = self._get_full_filename(filename)
|
|
303
|
-
if not os.path.exists(
|
|
304
|
-
filename if filename.endswith(".h5") else filename + ".h5"
|
|
305
|
-
):
|
|
301
|
+
if not os.path.exists(filename if filename.endswith(".h5") else filename + ".h5"): # noqa: PTH110
|
|
306
302
|
raise ValueError(f"File {filename} cannot be found")
|
|
307
303
|
|
|
308
304
|
data = AnalysisData(
|
|
@@ -394,9 +390,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
394
390
|
display_warning("Old data analysis")
|
|
395
391
|
|
|
396
392
|
filename = str(filepath or self._get_full_filename(filename)) # type: ignore
|
|
397
|
-
filename = (
|
|
398
|
-
(filename.rsplit(".h5", 1)[0]) if filename.endswith(".h5") else filename
|
|
399
|
-
)
|
|
393
|
+
filename = (filename.rsplit(".h5", 1)[0]) if filename.endswith(".h5") else filename
|
|
400
394
|
|
|
401
395
|
else:
|
|
402
396
|
self._is_old_data = False
|
|
@@ -411,8 +405,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
411
405
|
)
|
|
412
406
|
or (
|
|
413
407
|
acquisition_name[0] == r"^"
|
|
414
|
-
and re.match(acquisition_name, self.current_experiment_name)
|
|
415
|
-
is None
|
|
408
|
+
and re.match(acquisition_name, self.current_experiment_name) is None
|
|
416
409
|
)
|
|
417
410
|
):
|
|
418
411
|
raise ValueError(
|
|
@@ -421,7 +414,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
421
414
|
)
|
|
422
415
|
|
|
423
416
|
filename = str(self.current_filepath) # without h5
|
|
424
|
-
self.logger.info(os.path.basename(filename))
|
|
417
|
+
self.logger.info(os.path.basename(filename)) # noqa: PTH119
|
|
425
418
|
|
|
426
419
|
if (
|
|
427
420
|
(not self._is_old_data)
|
|
@@ -436,7 +429,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
436
429
|
"Check if everything is ok and executive again"
|
|
437
430
|
)
|
|
438
431
|
|
|
439
|
-
if os.path.exists(filename + ".h5"):
|
|
432
|
+
if os.path.exists(filename + ".h5"): # noqa: PTH110
|
|
440
433
|
self._load_analysis_data(filename)
|
|
441
434
|
else:
|
|
442
435
|
if self._is_old_data:
|
|
@@ -446,9 +439,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
446
439
|
if cell is not None:
|
|
447
440
|
self.save_analysis_cell(cell=cell)
|
|
448
441
|
|
|
449
|
-
if (self._analysis_cell_str is not None) and (
|
|
450
|
-
self._linting_external_vars is not None
|
|
451
|
-
):
|
|
442
|
+
if (self._analysis_cell_str is not None) and (self._linting_external_vars is not None):
|
|
452
443
|
from ..acquisition import custom_lint
|
|
453
444
|
from ..utils import lint
|
|
454
445
|
|
|
@@ -461,9 +452,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
461
452
|
run_on_call=custom_lint.on_call_functions,
|
|
462
453
|
)
|
|
463
454
|
for var in lint_result.external_vars:
|
|
464
|
-
self.logger.warning(
|
|
465
|
-
"External variable used inside the analysis code: %s", var
|
|
466
|
-
)
|
|
455
|
+
self.logger.warning("External variable used inside the analysis code: %s", var)
|
|
467
456
|
for error in lint_result.errors:
|
|
468
457
|
self.logger.warning(error)
|
|
469
458
|
|
|
@@ -488,15 +477,13 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
488
477
|
|
|
489
478
|
filepath = utils.get_path_from_filename(filename)
|
|
490
479
|
if isinstance(filepath, tuple):
|
|
491
|
-
return os.path.join(self.data_directory, *filepath)
|
|
480
|
+
return os.path.join(self.data_directory, *filepath) # noqa: PTH118
|
|
492
481
|
return filepath
|
|
493
482
|
|
|
494
483
|
def parse_config_file(self, config_file_name: str, /) -> "ConfigFile":
|
|
495
484
|
return self.data.parse_config_file(config_file_name)
|
|
496
485
|
|
|
497
|
-
def parse_config(
|
|
498
|
-
self, config_files: Optional[Tuple[str, ...]] = None
|
|
499
|
-
) -> "ConfigFile":
|
|
486
|
+
def parse_config(self, config_files: Optional[Tuple[str, ...]] = None) -> "ConfigFile":
|
|
500
487
|
return self.data.parse_config(config_files=config_files)
|
|
501
488
|
|
|
502
489
|
@property
|
|
@@ -518,16 +505,12 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
518
505
|
):
|
|
519
506
|
from ..utils import lint
|
|
520
507
|
|
|
521
|
-
allowed_variables = (
|
|
522
|
-
set() if allowed_variables is None else set(allowed_variables)
|
|
523
|
-
)
|
|
508
|
+
allowed_variables = set() if allowed_variables is None else set(allowed_variables)
|
|
524
509
|
if init_file is not None:
|
|
525
510
|
allowed_variables.update(lint.find_variables_from_file(init_file)[0])
|
|
526
511
|
self._linting_external_vars = allowed_variables
|
|
527
512
|
|
|
528
|
-
def set_default_config_files(
|
|
529
|
-
self, config_files: Union[str, Tuple[str, ...], List[str]], /
|
|
530
|
-
):
|
|
513
|
+
def set_default_config_files(self, config_files: Union[str, Tuple[str, ...], List[str]], /):
|
|
531
514
|
self._default_config_files = (
|
|
532
515
|
(config_files,) if isinstance(config_files, str) else tuple(config_files)
|
|
533
516
|
)
|
|
@@ -574,7 +557,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
574
557
|
if after_text is not None:
|
|
575
558
|
if not isinstance(params, str):
|
|
576
559
|
raise ValueError(
|
|
577
|
-
"Cannot use after_text with multiple params"
|
|
560
|
+
"Cannot use after_text with multiple params. "
|
|
578
561
|
"Use params=[(param, after_text), ...] instead."
|
|
579
562
|
)
|
|
580
563
|
return self.display_param_link(params=[(params, after_text)], title=title)
|
|
@@ -624,11 +607,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
624
607
|
self.update_config_params_on_disk({param: value})
|
|
625
608
|
|
|
626
609
|
buttons = (
|
|
627
|
-
[
|
|
628
|
-
display.buttons.create_button(
|
|
629
|
-
update_value, param, value, name="Update"
|
|
630
|
-
)
|
|
631
|
-
]
|
|
610
|
+
[display.buttons.create_button(update_value, param, value, name="Update")]
|
|
632
611
|
if update_button
|
|
633
612
|
else None
|
|
634
613
|
)
|
|
@@ -661,9 +640,7 @@ class AcquisitionAnalysisManager(AcquisitionManager):
|
|
|
661
640
|
|
|
662
641
|
def connect_default_widget(
|
|
663
642
|
self,
|
|
664
|
-
objs: Union[
|
|
665
|
-
"display_widget.WidgetProtocol", List["display_widget.WidgetProtocol"]
|
|
666
|
-
],
|
|
643
|
+
objs: Union["display_widget.WidgetProtocol", List["display_widget.WidgetProtocol"]],
|
|
667
644
|
):
|
|
668
645
|
if not isinstance(objs, (list, tuple)):
|
|
669
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(
|
labmate/utils/lint.py
CHANGED
|
@@ -86,7 +86,7 @@ class NameVisitor(ast.NodeVisitor):
|
|
|
86
86
|
external_vars (Set[str]): A set of external variable names.
|
|
87
87
|
errors (List[str]): A list of errors encountered during traversal.
|
|
88
88
|
run_on_call (Optional[Callable]): A function to run on each function call node.
|
|
89
|
-
special_functions_db (Dict[str, Any]): A
|
|
89
|
+
special_functions_db (Dict[str, Any]): A dict of special functions and their attributes.
|
|
90
90
|
"""
|
|
91
91
|
|
|
92
92
|
parent = None
|
|
@@ -107,9 +107,9 @@ class NameVisitor(ast.NodeVisitor):
|
|
|
107
107
|
self.local_vars = ignore_var.copy() if ignore_var else set()
|
|
108
108
|
self.builtins = set(__builtins__.keys())
|
|
109
109
|
self.external_vars = set()
|
|
110
|
-
self.errors =
|
|
110
|
+
self.errors = []
|
|
111
111
|
self.run_on_call = kwargs.get("run_on_call")
|
|
112
|
-
self.special_functions_db =
|
|
112
|
+
self.special_functions_db = {}
|
|
113
113
|
super().__init__()
|
|
114
114
|
|
|
115
115
|
def visit(self, node, parent=None):
|
|
@@ -199,10 +199,9 @@ class LintResult(NamedTuple):
|
|
|
199
199
|
errors: List[str]
|
|
200
200
|
|
|
201
201
|
|
|
202
|
-
def find_variables_from_node(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"""Walk through ast.node and find the variable that was never declared inside this node, but used.
|
|
202
|
+
def find_variables_from_node(node, ignore_var: Optional[set] = None, **kwargs) -> LintResult:
|
|
203
|
+
"""
|
|
204
|
+
Walk through ast.node and find variables that were never declared inside the node, but are used.
|
|
206
205
|
|
|
207
206
|
Variables from ingore_var set is allowed external variables to use.
|
|
208
207
|
Returns (local_vars, external_vars)
|
|
@@ -246,8 +245,7 @@ def find_variables_from_code(
|
|
|
246
245
|
f"Error at line {exception.lineno} in {exception.text}"
|
|
247
246
|
],
|
|
248
247
|
)
|
|
249
|
-
|
|
250
|
-
return lint_results
|
|
248
|
+
return find_variables_from_node(node, ignore_var, run_on_call=run_on_call)
|
|
251
249
|
|
|
252
250
|
|
|
253
251
|
def find_variables_from_file(
|
|
@@ -260,12 +258,12 @@ def find_variables_from_file(
|
|
|
260
258
|
Args:
|
|
261
259
|
file: A string representing the path to the file to be analyzed.
|
|
262
260
|
ignore_var: An optional set of variable names to ignore during analysis.
|
|
263
|
-
run_on_call: An optional callable object to
|
|
261
|
+
run_on_call: An optional callable object to run on each function call found during analysis.
|
|
264
262
|
|
|
265
263
|
Returns:
|
|
266
264
|
A LintResult object containing the used and unused variables,
|
|
267
265
|
and any errors encountered during analysis.
|
|
268
266
|
"""
|
|
269
|
-
with open(file,
|
|
267
|
+
with open(file, encoding="utf-8") as f:
|
|
270
268
|
code = f.read()
|
|
271
269
|
return find_variables_from_code(code, ignore_var, run_on_call=run_on_call)
|