labmate 0.8.4__tar.gz → 0.9.0__tar.gz

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.
Files changed (81) hide show
  1. {labmate-0.8.4/labmate.egg-info → labmate-0.9.0}/PKG-INFO +1 -1
  2. {labmate-0.8.4 → labmate-0.9.0}/labmate/__config__.py +1 -1
  3. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/analysis_data.py +28 -2
  4. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition_notebook/acquisition_analysis_manager.py +54 -1
  5. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition_notebook/display_widget.py +26 -31
  6. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/__init__.py +10 -3
  7. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/buttons.py +4 -0
  8. labmate-0.9.0/labmate/display/html_output.py +63 -0
  9. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/main.py +19 -3
  10. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/__init__.py +2 -1
  11. labmate-0.9.0/labmate/utils/file_read.py +96 -0
  12. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/title_parsing.py +23 -6
  13. {labmate-0.8.4 → labmate-0.9.0/labmate.egg-info}/PKG-INFO +1 -1
  14. labmate-0.8.4/labmate/display/html_output.py +0 -15
  15. labmate-0.8.4/labmate/utils/file_read.py +0 -49
  16. {labmate-0.8.4 → labmate-0.9.0}/LICENCE +0 -0
  17. {labmate-0.8.4 → labmate-0.9.0}/MANIFEST.in +0 -0
  18. {labmate-0.8.4 → labmate-0.9.0}/README.md +0 -0
  19. {labmate-0.8.4 → labmate-0.9.0}/docs/about.md +0 -0
  20. {labmate-0.8.4 → labmate-0.9.0}/docs/acquisition_notebook.md +0 -0
  21. {labmate-0.8.4 → labmate-0.9.0}/docs/code/acquisition_loop.md +0 -0
  22. {labmate-0.8.4 → labmate-0.9.0}/docs/code/acquisition_manager.md +0 -0
  23. {labmate-0.8.4 → labmate-0.9.0}/docs/code/acquisition_notebook_manager.md +0 -0
  24. {labmate-0.8.4 → labmate-0.9.0}/docs/code/analysis_data.md +0 -0
  25. {labmate-0.8.4 → labmate-0.9.0}/docs/code/linting.md +0 -0
  26. {labmate-0.8.4 → labmate-0.9.0}/docs/code/parsing_config.md +0 -0
  27. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/acquisition_and_analysis_notebook.ipynb +0 -0
  28. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/aqm_simple_example.ipynb +0 -0
  29. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/files/cfg.py +0 -0
  30. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/files/dummy_config1.txt +0 -0
  31. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/files/dummy_config2.txt +0 -0
  32. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/files/dummy_config3.py +0 -0
  33. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/files/init_analyse.py +0 -0
  34. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/more/acquisition_and_analysis_notebook_with_magic.ipynb +0 -0
  35. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/more/h5nparray.ipynb +0 -0
  36. {labmate-0.8.4 → labmate-0.9.0}/docs/examples/more/loop_example.ipynb +0 -0
  37. {labmate-0.8.4 → labmate-0.9.0}/docs/h5nparray.md +0 -0
  38. {labmate-0.8.4 → labmate-0.9.0}/docs/index.md +0 -0
  39. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.4.0.md +0 -0
  40. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.5.0.md +0 -0
  41. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.6.0.md +0 -0
  42. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.6.1.md +0 -0
  43. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.7.0.md +0 -0
  44. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/0.8.0.md +0 -0
  45. {labmate-0.8.4 → labmate-0.9.0}/docs/releases/index.md +0 -0
  46. {labmate-0.8.4 → labmate-0.9.0}/docs/starting_guide/advanced_examples.md +0 -0
  47. {labmate-0.8.4 → labmate-0.9.0}/docs/starting_guide/fine_tune.md +0 -0
  48. {labmate-0.8.4 → labmate-0.9.0}/docs/starting_guide/first_steps.md +0 -0
  49. {labmate-0.8.4 → labmate-0.9.0}/docs/starting_guide/install.md +0 -0
  50. {labmate-0.8.4 → labmate-0.9.0}/labmate/__init__.py +0 -0
  51. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/__init__.py +0 -0
  52. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/acquisition_data.py +0 -0
  53. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/acquisition_loop.py +0 -0
  54. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/acquisition_manager.py +0 -0
  55. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/analysis_loop.py +0 -0
  56. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/config_file.py +0 -0
  57. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/custom_lint.py +0 -0
  58. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition/logger_setup.py +0 -0
  59. {labmate-0.8.4 → labmate-0.9.0}/labmate/acquisition_notebook/__init__.py +0 -0
  60. {labmate-0.8.4 → labmate-0.9.0}/labmate/attrdict/__init__.py +0 -0
  61. {labmate-0.8.4 → labmate-0.9.0}/labmate/attrdict/attrdict_class.py +0 -0
  62. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/links.py +0 -0
  63. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/platform_utils/__init__.py +0 -0
  64. {labmate-0.8.4 → labmate-0.9.0}/labmate/display/platform_utils/windows_utils.py +0 -0
  65. {labmate-0.8.4 → labmate-0.9.0}/labmate/parsing/__init__.py +0 -0
  66. {labmate-0.8.4 → labmate-0.9.0}/labmate/parsing/brackets_score.py +0 -0
  67. {labmate-0.8.4 → labmate-0.9.0}/labmate/parsing/parsed_value.py +0 -0
  68. {labmate-0.8.4 → labmate-0.9.0}/labmate/parsing/saving.py +0 -0
  69. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/async_utils.py +0 -0
  70. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/autoreload.py +0 -0
  71. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/errors.py +0 -0
  72. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/lint.py +0 -0
  73. {labmate-0.8.4 → labmate-0.9.0}/labmate/utils/random_utils.py +0 -0
  74. {labmate-0.8.4 → labmate-0.9.0}/labmate.egg-info/SOURCES.txt +0 -0
  75. {labmate-0.8.4 → labmate-0.9.0}/labmate.egg-info/dependency_links.txt +0 -0
  76. {labmate-0.8.4 → labmate-0.9.0}/labmate.egg-info/requires.txt +0 -0
  77. {labmate-0.8.4 → labmate-0.9.0}/labmate.egg-info/top_level.txt +0 -0
  78. {labmate-0.8.4 → labmate-0.9.0}/requirements-docs.txt +0 -0
  79. {labmate-0.8.4 → labmate-0.9.0}/requirements.txt +0 -0
  80. {labmate-0.8.4 → labmate-0.9.0}/setup.cfg +0 -0
  81. {labmate-0.8.4 → labmate-0.9.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: labmate
3
- Version: 0.8.4
3
+ Version: 0.9.0
4
4
  Summary: Data management library to save data and plots to hdf5 files
5
5
  Home-page: https://github.com/kyrylo-gr/labmate
6
6
  Author: kyrylo.gr | LKB-OMQ
@@ -1,3 +1,3 @@
1
1
  """This file contains all package constants."""
2
2
 
3
- __version__ = "0.8.4"
3
+ __version__ = "0.9.0"
@@ -1,10 +1,12 @@
1
1
  """AnalysisData class."""
2
2
 
3
+ import json
3
4
  import os
4
- from typing import List, Literal, Optional, Protocol, Tuple, TypeVar, Union
5
+ from typing import List, Literal, Optional, Protocol, Tuple, TypedDict, TypeVar, Union
5
6
 
6
7
  from dh5 import DH5
7
8
  from dh5.path import Path
9
+ from matplotlib.backends.backend_pdf import PdfPages
8
10
 
9
11
  from .. import utils
10
12
  from .analysis_loop import AnalysisLoop
@@ -21,6 +23,13 @@ class FigureProtocol(Protocol):
21
23
  """Save the figure to a file."""
22
24
 
23
25
 
26
+ class PdfMetadataDict(TypedDict, total=False):
27
+ """Metadata for the pdf file."""
28
+
29
+ Subject: Union[str, dict]
30
+ Keywords: Union[str, dict]
31
+
32
+
24
33
  class AnalysisData(DH5):
25
34
  """A subclass of DH5 that provides additional functionality for analyzing data.
26
35
 
@@ -167,6 +176,7 @@ class AnalysisData(DH5):
167
176
  name: Optional[Union[str, int]] = None,
168
177
  extensions: Optional[str] = None,
169
178
  tight_layout: bool = True,
179
+ metadata: Optional[PdfMetadataDict] = None,
170
180
  **kwargs,
171
181
  ) -> _T:
172
182
  """Save the figure with the filename (...)_FIG_name.
@@ -201,7 +211,23 @@ class AnalysisData(DH5):
201
211
  )
202
212
  if tight_layout and hasattr(fig, "tight_layout"):
203
213
  fig.tight_layout() # type: ignore
204
- fig.savefig(full_fig_name, **kwargs)
214
+ if metadata is None:
215
+ fig.savefig(full_fig_name, **kwargs)
216
+ else:
217
+ if not full_fig_name.endswith(".pdf"):
218
+ raise ValueError("Metadata can be added only to pdf files.")
219
+ pdf_fig = PdfPages(full_fig_name)
220
+ fig.savefig(pdf_fig, format="pdf", **kwargs) # type: ignore
221
+ metadata = metadata or {}
222
+ if not isinstance(metadata.get("Subject", ""), str):
223
+ metadata["Subject"] = json.dumps(metadata.get("Subject"))
224
+
225
+ if not isinstance(metadata.get("Keywords", ""), str):
226
+ metadata["Keywords"] = json.dumps(metadata.get("Keywords"))
227
+
228
+ pdf_metadata = pdf_fig.infodict()
229
+ pdf_metadata.update(metadata)
230
+ pdf_fig.close()
205
231
 
206
232
  self._figure_saved = True
207
233
 
@@ -314,7 +314,9 @@ class AcquisitionAnalysisManager(AcquisitionManager):
314
314
 
315
315
  logger.info(self.current_filepath.basename)
316
316
 
317
- utils.run_functions(self._acquisition_cell_prerun_hook)
317
+ if step == 1:
318
+ utils.run_functions(self._acquisition_cell_prerun_hook)
319
+
318
320
  utils.run_functions(prerun)
319
321
 
320
322
  return self
@@ -545,6 +547,57 @@ class AcquisitionAnalysisManager(AcquisitionManager):
545
547
  links += link + "<br/>"
546
548
  return display.display_html(links)
547
549
 
550
+ def display_cfg_link(
551
+ self,
552
+ parameters: Dict[str, Any],
553
+ ):
554
+ from labmate.display import html_output
555
+
556
+ links = []
557
+ for param, value in parameters.items():
558
+ param_eq = f"{param.strip()} = "
559
+ res = self.find_param_in_config(param_eq)
560
+ if res is None:
561
+ logger.warning(
562
+ "Parameter '%s' cannot be found in default config files.", param
563
+ )
564
+ continue
565
+ file, line_no = res
566
+ file = self._config_files_names_to_path.get(file, file)
567
+
568
+ def update_value(param, value):
569
+ self.update_config_params_on_disk({param: value})
570
+
571
+ buttons = [
572
+ display.buttons.create_button(update_value, param, value, name="Update")
573
+ ]
574
+
575
+ link = html_output.create_link_row(
576
+ link_text=f"{param} = ",
577
+ link_url=f"{file}:{line_no}",
578
+ text=str(value),
579
+ buttons=buttons, # type: ignore
580
+ )
581
+ links.append(link)
582
+ return display.display_widgets_vertically(links, class_="labmate-params")
583
+
584
+ def update_config_params_on_disk(self, params: Dict[str, Any]):
585
+ # params_per_files = {}
586
+ # for param, value in params.items():
587
+ # res = self.find_param_in_data_config(param)
588
+ # if res is None:
589
+ # raise ValueError(
590
+ # f"Parameter '{param}' cannot be found in default config files."
591
+ # )
592
+ # file, _ = res
593
+ # params_per_files.setdefault(file, {})[param] = value
594
+
595
+ for file in self.config_files:
596
+ file = self._config_files_names_to_path.get(file, file)
597
+ utils.file_read.update_file_variable(file, params)
598
+
599
+ return self
600
+
548
601
  def connect_default_widget(
549
602
  self,
550
603
  objs: Union[
@@ -1,20 +1,38 @@
1
- """Module with widgets that can be displayed with AcquisitionAnalysisManager."""
2
-
3
1
  import os
4
2
  from typing import TYPE_CHECKING, List, Optional, Protocol, TypeVar
5
3
 
6
4
  from .. import display as lm_display
7
5
  from ..display import platform_utils
8
6
 
9
- # import abc
10
-
11
-
12
7
  if TYPE_CHECKING:
13
8
  from labmate.acquisition_notebook import AcquisitionAnalysisManager
14
9
 
15
10
  _T = TypeVar("_T")
16
11
 
17
12
 
13
+ def _get_filepath(aqm: "AcquisitionAnalysisManager") -> Optional[str]:
14
+ filepath = aqm.current_analysis or aqm.current_acquisition
15
+ return filepath.filepath if filepath else None
16
+
17
+
18
+ def _create_file_link(aqm: "AcquisitionAnalysisManager", level_up) -> str:
19
+ filepath = _get_filepath(aqm)
20
+ if filepath is None:
21
+ return ""
22
+ link_name = os.path.basename(filepath)
23
+ link = "/".join(
24
+ os.path.abspath(filepath).replace("\\", "/").split("/")[-level_up:]
25
+ ).replace(" ", "%20")
26
+ link = f"[{link_name}](//kyrylo-gr.github.io/h5viewer/open?url={link})"
27
+ return link
28
+
29
+
30
+ def display_widgets(objs: List["WidgetProtocol"], *args, **kwargs):
31
+ """Create (with *args, **kwargs) and display a list of widgets."""
32
+ widgets = [obj.create(*args, **kwargs) for obj in objs]
33
+ lm_display.display_widgets(widgets) # type: ignore
34
+
35
+
18
36
  class WidgetProtocol(Protocol):
19
37
  """Protocol for widgets that can be displayed with AcquisitionAnalysisManager.
20
38
 
@@ -73,7 +91,7 @@ class BaseWidget:
73
91
  raise NotImplementedError("This method is not implemented for the base class.")
74
92
 
75
93
 
76
- class CopyFilePathButton(BaseWidget):
94
+ class CopyFileURLPathButton(BaseWidget):
77
95
  """Create button to copy file path to clipboard.
78
96
 
79
97
  Examples:
@@ -180,32 +198,9 @@ class OpenFinderButton(BaseWidget):
180
198
  path = path.replace("/", "\\")
181
199
  subprocess.run(["explorer", "/select,", path], shell=True)
182
200
  elif sys.platform == "darwin":
183
- subprocess.Popen(["open", "-R", path])
201
+ subprocess.Popen(["open", "-R", os.path.dirname(path)])
184
202
  else:
185
- subprocess.Popen(["nautilus", "--select", path])
203
+ subprocess.Popen(["nautilus", "--select", os.path.dirname(path)])
186
204
 
187
205
  self.widget = lm_display.buttons.create_button(open_finder, name="Open finder")
188
206
  return self.widget
189
-
190
-
191
- def _get_filepath(aqm: "AcquisitionAnalysisManager") -> Optional[str]:
192
- filepath = aqm.current_analysis or aqm.current_acquisition
193
- return filepath.filepath if filepath else None
194
-
195
-
196
- def _create_file_link(aqm: "AcquisitionAnalysisManager", level_up) -> str:
197
- filepath = _get_filepath(aqm)
198
- if filepath is None:
199
- return ""
200
- link_name = os.path.basename(filepath)
201
- link = "/".join(
202
- os.path.abspath(filepath).replace("\\", "/").split("/")[-level_up:]
203
- ).replace(" ", "%20")
204
- link = f"[{link_name}](//kyrylo-gr.github.io/h5viewer/open?url={link})"
205
- return link
206
-
207
-
208
- def display_widgets(objs: List["WidgetProtocol"], *args, **kwargs):
209
- """Create (with *args, **kwargs) and display a list of widgets."""
210
- widgets = [obj.create(*args, **kwargs) for obj in objs]
211
- lm_display.display_widgets(widgets) # type: ignore
@@ -2,9 +2,15 @@
2
2
  import importlib
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- from .main import display, display_html, display_widgets, logger
5
+ from .main import (
6
+ display,
7
+ display_html,
8
+ display_widgets,
9
+ display_widgets_vertically,
10
+ logger,
11
+ )
6
12
 
7
- __all__ = ["links", "buttons", "logger"]
13
+ __all__ = ["links", "buttons", "logger", "html_output"]
8
14
 
9
15
 
10
16
  class _LazyModule:
@@ -28,7 +34,8 @@ class _LazyModule:
28
34
 
29
35
  links = _LazyModule("links")
30
36
  buttons = _LazyModule("buttons")
37
+ html_output = _LazyModule("html_output")
31
38
 
32
39
 
33
40
  if TYPE_CHECKING:
34
- from . import buttons, links
41
+ from . import buttons, html_output, links
@@ -1,5 +1,7 @@
1
1
  """This submodule contains functions that create Button widgets."""
2
+
2
3
  from typing import TypeVar
4
+
3
5
  from .main import display, widgets
4
6
 
5
7
  # from functools import wraps
@@ -69,6 +71,8 @@ def create_button(func, *args, name=None, **kwargs) -> "DisplayingButton":
69
71
  def on_button_click(_):
70
72
  func(*args, **kwargs)
71
73
 
74
+ button.style.button_color = "transparent" # type: ignore
75
+
72
76
  button.on_click(on_button_click)
73
77
  return button
74
78
 
@@ -0,0 +1,63 @@
1
+ """This submodule contains functions that create different html."""
2
+
3
+ from typing import List, Optional
4
+
5
+ from .main import widgets
6
+
7
+
8
+ def display_warning(text: str):
9
+ """Display div warning block with `text`.
10
+
11
+ If IPython is not installed, log into logger from display submodule at warning level.
12
+ """
13
+ from .main import display_html
14
+
15
+ html = f"""<div style="
16
+ background-color:#ec7413; padding: .5em; text-align:center"
17
+ >{text}</div>"""
18
+
19
+ display_html(str(html))
20
+
21
+
22
+ def create_link_row(
23
+ link_text: str,
24
+ link_url: str,
25
+ text: str,
26
+ buttons: Optional[List[widgets.Button]] = None,
27
+ ):
28
+
29
+ # Create the HTML link with custom styling
30
+ link_widget = widgets.HTML(
31
+ value=f'<a href="{link_url}" target="_blank" onclick="return false;">{link_text}</a>'
32
+ )
33
+
34
+ # Create the text with custom styling
35
+ text_widget = widgets.HTML(
36
+ value=f'<span style="padding: 0 10px;">{text}</span>',
37
+ layout=widgets.Layout(background_color="transparent"),
38
+ )
39
+
40
+ custom_css = """
41
+ <style>
42
+ .cell-output-ipywidget-background:has(.labmate-params) {
43
+ background: transparent !important;
44
+ }
45
+ .labmate-params, .labmate-params * {
46
+ color: inherit !important;
47
+ }
48
+ .labmate-params a {
49
+ text-decoration: underline;
50
+ color: blue;
51
+
52
+ }
53
+
54
+ </style>
55
+ """
56
+ buttons = buttons or []
57
+
58
+ hbox = widgets.HBox(
59
+ [widgets.HTML(custom_css), link_widget, text_widget, *buttons],
60
+ layout=widgets.Layout(background_color="transparent"),
61
+ )
62
+ hbox.add_class("labmate-params")
63
+ return hbox
@@ -1,9 +1,9 @@
1
1
  """This submodule contains functions that help to display content in IPython."""
2
+
2
3
  import logging
3
4
  import sys
4
5
  from typing import Callable, List
5
6
 
6
-
7
7
  logging.basicConfig(format="%(levelname)s:%(message)s", level=logging.WARNING)
8
8
  logger = logging.getLogger(__name__)
9
9
  handler = logging.StreamHandler()
@@ -18,9 +18,9 @@ try:
18
18
  if "pytest" in sys.modules:
19
19
  raise ImportError
20
20
 
21
- from IPython.core.display import HTML # type: ignore
22
- from IPython.core import display # type: ignore
23
21
  import ipywidgets as widgets # pylint: disable=W0611 # type: ignore
22
+ from IPython.core import display # type: ignore
23
+ from IPython.core.display import HTML # type: ignore
24
24
 
25
25
  display = display.display_functions.display
26
26
 
@@ -49,9 +49,17 @@ except ImportError:
49
49
  def __init__(self, lst: list) -> None: # noqa: D107
50
50
  pass
51
51
 
52
+ class VBox: # noqa: D106
53
+ def __init__(self, lst: list) -> None: # noqa: D107
54
+ pass
55
+
52
56
  class CoreWidget: # noqa: D106
53
57
  pass
54
58
 
59
+ class Layout:
60
+ def __init__(self, *args, **kwargs) -> None:
61
+ del args, kwargs
62
+
55
63
  # pylint: enable=C0115, C0103, R0903
56
64
 
57
65
 
@@ -64,3 +72,11 @@ def display_widgets(objs: List[widgets.CoreWidget]):
64
72
  """Display the given list of widgets in a HBox ."""
65
73
  button_row = widgets.HBox(objs)
66
74
  display(button_row)
75
+
76
+
77
+ def display_widgets_vertically(objs: List[widgets.CoreWidget], class_: str = ""):
78
+ """Display the given list of widgets in a VBox ."""
79
+ button_row = widgets.VBox(objs)
80
+ if class_:
81
+ button_row.add_class(class_) # type: ignore
82
+ display(button_row)
@@ -1,2 +1,3 @@
1
- from .random_utils import * # noqa
1
+ from . import file_read # noqa
2
2
  from . import title_parsing # noqa
3
+ from .random_utils import * # noqa
@@ -0,0 +1,96 @@
1
+ """Different method to read files."""
2
+
3
+ import json
4
+ import os
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from ..parsing.brackets_score import BracketsScore
8
+
9
+
10
+ def read_file(file: str, /) -> str:
11
+ """Read the contents of a file and returns it as a string.
12
+
13
+ Args:
14
+ file (str): The path to the file to be read.
15
+
16
+ Returns:
17
+ str: The contents of the file as a string.
18
+
19
+ Raises:
20
+ ValueError: If the file does not exist or is not a file.
21
+ """
22
+ if not os.path.isfile(file):
23
+ raise ValueError(
24
+ "Cannot read a file if it doesn't exist or it's not a file."
25
+ f"Path: {os.path.abspath(file)}"
26
+ )
27
+
28
+ with open(file, "r", encoding="utf-8") as file_opened:
29
+ return file_opened.read()
30
+
31
+
32
+ def read_files(files: List[str], /) -> Dict[str, str]:
33
+ """Read the contents of the given files and returns them as a dictionary.
34
+
35
+ Args:
36
+ files: A list of file paths to read.
37
+
38
+ Returns:
39
+ A dictionary where the keys are the file names and the values are the contents of the files.
40
+
41
+ Raises:
42
+ ValueError: If some of the files have the same name, which would cause a key collision in the dictionary.
43
+ """
44
+ configs: Dict[str, str] = {}
45
+ for config_file in files:
46
+ config_file_name = os.path.basename(config_file)
47
+ if config_file_name in configs:
48
+ raise ValueError(
49
+ "Some of the files have the same name. So it cannot be pushed into dictionary to"
50
+ " preserve unique key"
51
+ )
52
+ configs[config_file_name] = read_file(config_file)
53
+ return configs
54
+
55
+
56
+ def update_file_variable(file, params: Dict[str, Any]):
57
+ """
58
+ Update the variables in a file with the given parameters.
59
+
60
+ Args:
61
+ file (str): The path to the file to update.
62
+ params (Dict[str, Any]): The parameters to update the file with.
63
+ """
64
+ with open(file, "r", encoding="utf-8") as file_opened:
65
+ lines = file_opened.readlines()
66
+ brackets = BracketsScore()
67
+ current_param: Optional[str] = None
68
+ # print(lines)
69
+ for line in lines:
70
+ # print(line)
71
+ if len(line) == 0:
72
+ continue
73
+ if brackets.is_zero() and "=" in line:
74
+ param = line.split("=")[0].strip()
75
+ # print("param", param)
76
+ if param in params:
77
+ current_param = param
78
+ start_line = lines.index(line)
79
+ brackets.update_from_str(line)
80
+ if brackets.is_zero() and current_param is not None:
81
+ end_line = lines.index(line)
82
+ end_comment = line.split("#")[-1].strip() if "#" in line else None
83
+ del lines[start_line : end_line + 1]
84
+ value_str = json.JSONEncoder().encode(params[current_param])
85
+ lines.insert(
86
+ start_line,
87
+ (
88
+ f"{current_param} = {value_str}"
89
+ + (f" # {end_comment}" if end_comment is not None else "")
90
+ + "\n"
91
+ ),
92
+ )
93
+ current_param = None
94
+
95
+ with open(file, "w", encoding="utf-8") as file_opened:
96
+ file_opened.writelines(lines)
@@ -17,7 +17,11 @@ def parse_get_format(key: str) -> Tuple[str, Optional[str], Optional[str]]:
17
17
  args = key.split("__")
18
18
  if len(args) >= 3:
19
19
  return args[0], args[1], args[2]
20
- elif len(args) == 2 and len(args[1]) > 0 and args[1][0].isdigit():
20
+ elif (
21
+ len(args) == 2
22
+ and len(args[1]) > 0
23
+ and (args[1][0].isdigit() or args[1][0] in (".", "_"))
24
+ ):
21
25
  return args[0], None, args[1]
22
26
  elif len(args) == 2:
23
27
  return args[0], args[1], None
@@ -32,6 +36,23 @@ class ValueForPrint(NamedTuple):
32
36
  units: Optional[str] = None
33
37
  format: Optional[str] = None
34
38
 
39
+ def format_value(self, format_spec: Optional[str] = None) -> str:
40
+ format_spec = format_spec or self.format
41
+ if not format_spec:
42
+ return str(self.value)
43
+ if format_spec.endswith("p"):
44
+ format_spec = format_spec[:-1] + "e"
45
+ value_str = format(self.value, format_spec)
46
+ number, power = value_str.split("e")
47
+ number = number.rstrip("0_").rstrip(".") if "." in number else number
48
+ power = (
49
+ (power[0].lstrip("+0") + power[1:].lstrip("+0"))
50
+ if len(power) > 1
51
+ else power
52
+ )
53
+ return f"{number}e{power}"
54
+ return format(self.value, format_spec)
55
+
35
56
 
36
57
  def format_title(values: List[ValueForPrint], max_length: Optional[int] = None) -> str:
37
58
  """Create title out of a list of valuesForPrint.
@@ -47,11 +68,7 @@ def format_title(values: List[ValueForPrint], max_length: Optional[int] = None)
47
68
  last_line_len = 0
48
69
  for value in values:
49
70
  units = f" ({value.units})" if value.units is not None else ""
50
- value_str = (
51
- value.value
52
- if value.format is None
53
- else value.value.__format__(f".{value.format}")
54
- )
71
+ value_str = value.format_value()
55
72
  new_txt = f"{value.key} = {value_str}{units}"
56
73
  if not max_length or (
57
74
  (last_line_len + len(new_txt) < max_length) or last_line_len == 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: labmate
3
- Version: 0.8.4
3
+ Version: 0.9.0
4
4
  Summary: Data management library to save data and plots to hdf5 files
5
5
  Home-page: https://github.com/kyrylo-gr/labmate
6
6
  Author: kyrylo.gr | LKB-OMQ
@@ -1,15 +0,0 @@
1
- """This submodule contains functions that create different html."""
2
-
3
-
4
- def display_warning(text: str):
5
- """Display div warning block with `text`.
6
-
7
- If IPython is not installed, log into logger from display submodule at warning level.
8
- """
9
- from .main import display_html
10
-
11
- html = f"""<div style="
12
- background-color:#ec7413; padding: .5em; text-align:center"
13
- >{text}</div>"""
14
-
15
- display_html(str(html))
@@ -1,49 +0,0 @@
1
- """Different method to read files."""
2
- import os
3
- from typing import Dict, List
4
-
5
-
6
- def read_file(file: str, /) -> str:
7
- """Read the contents of a file and returns it as a string.
8
-
9
- Args:
10
- file (str): The path to the file to be read.
11
-
12
- Returns:
13
- str: The contents of the file as a string.
14
-
15
- Raises:
16
- ValueError: If the file does not exist or is not a file.
17
- """
18
- if not os.path.isfile(file):
19
- raise ValueError(
20
- "Cannot read a file if it doesn't exist or it's not a file."
21
- f"Path: {os.path.abspath(file)}"
22
- )
23
-
24
- with open(file, "r", encoding="utf-8") as file_opened:
25
- return file_opened.read()
26
-
27
-
28
- def read_files(files: List[str], /) -> Dict[str, str]:
29
- """Read the contents of the given files and returns them as a dictionary.
30
-
31
- Args:
32
- files: A list of file paths to read.
33
-
34
- Returns:
35
- A dictionary where the keys are the file names and the values are the contents of the files.
36
-
37
- Raises:
38
- ValueError: If some of the files have the same name, which would cause a key collision in the dictionary.
39
- """
40
- configs: Dict[str, str] = {}
41
- for config_file in files:
42
- config_file_name = os.path.basename(config_file)
43
- if config_file_name in configs:
44
- raise ValueError(
45
- "Some of the files have the same name. So it cannot be pushed into dictionary to"
46
- " preserve unique key"
47
- )
48
- configs[config_file_name] = read_file(config_file)
49
- return configs
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes