machineconfig 6.52__py3-none-any.whl → 6.53__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.

Potentially problematic release.


This version of machineconfig might be problematic. Click here for more details.

@@ -5,13 +5,13 @@ from machineconfig.utils.schemas.layouts.layout_types import TabConfig, LayoutCo
5
5
  from pathlib import Path
6
6
 
7
7
  def get_fire_command_and_artifact_files(func: FunctionType):
8
- from machineconfig.utils.meta import function_to_script
9
- py_script = function_to_script(func, call_with_kwargs=None)
8
+ from machineconfig.utils.meta import lambda_to_defstring
9
+ py_script = lambda_to_defstring(lmb=lambda: func, in_global=True)
10
10
  from machineconfig.utils.accessories import randstr
11
11
  py_script_path = Path.home().joinpath("tmp_results", "tmp_py_scripts", f"tmp_{randstr(10)}.py")
12
12
  py_script_path.parent.mkdir(parents=True, exist_ok=True)
13
13
  py_script_path.write_text(py_script, encoding="utf-8")
14
- command_to_run = f"uv run --project $HOME/ {py_script_path}"
14
+ command_to_run = f"uv run {py_script_path}"
15
15
  tab_config: TabConfig = {
16
16
  "command": command_to_run,
17
17
  "startDir": "$HOME",
@@ -78,8 +78,51 @@ def download(
78
78
  raise typer.Exit(code=1)
79
79
 
80
80
 
81
+ def merge_pdfs(
82
+ pdf1: Annotated[str, typer.Argument(..., help="Path to the first PDF file.")],
83
+ pdf2: Annotated[str, typer.Argument(..., help="Path to the second PDF file.")],
84
+ output: Annotated[Optional[str], typer.Option("--output", "-o", help="Output merged PDF file path.")] = None,
85
+ compress: Annotated[bool, typer.Option("--compress", "-c", help="Compress the output PDF.")] = False,
86
+ ) -> None:
87
+ def merge_pdfs_internal(pdf1: str, pdf2: str, output: Optional[str], compress: bool) -> None:
88
+ from pypdf import PdfReader, PdfWriter
89
+ writer = PdfWriter()
90
+ for pdf_path in [pdf1, pdf2]:
91
+ reader = PdfReader(pdf_path)
92
+ for page in reader.pages:
93
+ writer.add_page(page)
94
+ output_path = output if output else "merged.pdf"
95
+ if compress:
96
+ try:
97
+ for p in writer.pages:
98
+ try:
99
+ # PageObject.compress_content_streams exists in pypdf
100
+ p.compress_content_streams()
101
+ except Exception:
102
+ # best-effort: ignore per-page compression failures
103
+ continue
104
+ except Exception:
105
+ pass
106
+ try:
107
+ writer.compress_identical_objects()
108
+ except Exception:
109
+ # non-fatal if this fails
110
+ pass
111
+ writer.write(output_path)
112
+ print(f"✅ Merged PDF saved to: {output_path}")
113
+ from machineconfig.utils.meta import lambda_to_defstring
114
+ code = lambda_to_defstring(lambda : merge_pdfs_internal(pdf1=pdf1, pdf2=pdf2, output=output, compress=compress), in_global=True)
115
+ import tempfile
116
+ tmp_py_file = Path(tempfile.mkstemp(suffix=".py")[1])
117
+ tmp_py_file.write_text(code, encoding="utf-8")
118
+ from machineconfig.utils.code import run_shell_script
119
+ run_shell_script(f"""uv run --with pypdf {tmp_py_file} """)
120
+
121
+
81
122
  def get_app() -> typer.Typer:
82
123
  app = typer.Typer(help="🛠️ [u] utilities operations", no_args_is_help=True, add_help_option=False, add_completion=False)
83
124
  app.command(name="download", no_args_is_help=True, help="[d] Download a file from a URL and optionally decompress it.")(download)
84
125
  app.command(name="d", no_args_is_help=True, hidden=True)(download)
126
+ app.command(name="merge-pdfs", no_args_is_help=True, help="[m] Merge two PDF files into one.")(merge_pdfs)
127
+ app.command(name="m", no_args_is_help=True, hidden=True)(merge_pdfs)
85
128
  return app
@@ -6,7 +6,7 @@ import typer
6
6
  from machineconfig.utils.path_extended import PathExtended
7
7
  from machineconfig.utils.terminal import Response
8
8
  from machineconfig.utils.source_of_truth import CONFIG_ROOT, DEFAULTS_PATH
9
- from machineconfig.utils.code import get_shell_file_executing_python_script, write_shell_script_to_file
9
+ from machineconfig.utils.code import get_shell_file_executing_python_script
10
10
  from pathlib import Path
11
11
  import platform
12
12
  import subprocess
@@ -76,10 +76,17 @@ git pull originEnc master
76
76
 
77
77
  """
78
78
 
79
- if Path.home().joinpath("code/machineconfig").exists(): executable = f"""uv run --project "{str(Path.home().joinpath("code/machineconfig"))}" """
80
- else: executable = """uv run --with "machineconfig>=6.52" """
79
+ if Path.home().joinpath("code/machineconfig").exists():
80
+ uv_project_dir = f"""{str(Path.home().joinpath("code/machineconfig"))}"""
81
+ uv_with = None
82
+ else:
83
+ uv_with = ["machineconfig>=6.52"]
84
+ uv_project_dir = None
85
+
86
+ import tempfile
87
+ shell_path = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
88
+ shell_path.write_text(script, encoding="utf-8")
81
89
 
82
- shell_path = write_shell_script_to_file(shell_script=script)
83
90
  command = f". {shell_path}"
84
91
  if platform.system() == "Windows":
85
92
  completed = subprocess.run(["powershell", "-Command", command], capture_output=True, check=False, text=True)
@@ -100,20 +107,12 @@ git pull originEnc master
100
107
 
101
108
  # ================================================================================
102
109
  option1 = "Delete remote copy and push local:"
103
- from machineconfig.utils.meta import function_to_script
110
+ from machineconfig.utils.meta import lambda_to_defstring
104
111
  def func2(remote_repo: str, local_repo: str, cloud: str):
105
112
  from machineconfig.scripts.python.helpers_repos.sync import delete_remote_repo_copy_and_push_local
106
113
  delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
107
- return "done"
108
- # def func2(remote_repo: str=str(repo_remote_root), local_repo: str=str(repo_local_root), cloud: str=str(cloud_resolved)):
109
- # from machineconfig.scripts.python.helpers_repos.sync import delete_remote_repo_copy_and_push_local
110
- # delete_remote_repo_copy_and_push_local(remote_repo=remote_repo, local_repo=local_repo, cloud=cloud)
111
- # return "done"
112
- # program_1_py = function_to_script(func=func2, call_with_kwargs=None)
113
- program_1_py = function_to_script(func=func2, call_with_kwargs={"remote_repo": str(repo_remote_root), "local_repo": str(repo_local_root), "cloud": cloud_resolved})
114
-
115
-
116
- shell_file_1 = get_shell_file_executing_python_script(python_script=program_1_py, ve_path=None, executable=executable)
114
+ program_1_py = lambda_to_defstring(lambda: func2(remote_repo=str(repo_remote_root), local_repo=str(repo_local_root), cloud=str(cloud_resolved)), in_global=True)
115
+ shell_file_1 = get_shell_file_executing_python_script(python_script=program_1_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
117
116
  # ================================================================================
118
117
  option2 = "Delete local repo and replace it with remote copy:"
119
118
  program_2 = f"""
@@ -126,15 +125,19 @@ sudo chmod 600 $HOME/.ssh/*
126
125
  sudo chmod 700 $HOME/.ssh
127
126
  sudo chmod +x $HOME/dotfiles/scripts/linux -R
128
127
  """
129
- shell_file_2 = write_shell_script_to_file(shell_script=program_2)
128
+ import tempfile
129
+ shell_file_2 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
130
+ shell_file_2.write_text(program_2, encoding="utf-8")
131
+
130
132
  # ================================================================================
131
133
  option3 = "Inspect repos:"
132
134
  def func(repo_local_root: str, repo_remote_root: str):
133
135
  from machineconfig.scripts.python.helpers_repos.sync import inspect_repos
134
136
  inspect_repos(repo_local_root=repo_local_root, repo_remote_root=repo_remote_root)
135
- return "done"
136
- program_3_py = function_to_script(func=func, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
137
- shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
137
+ # program_3_py = function_to_script(func=func, call_with_kwargs={"repo_local_root": str(repo_local_root), "repo_remote_root": str(repo_remote_root)})
138
+ # shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, ve_path=None, executable=executable)
139
+ program_3_py = lambda_to_defstring(lambda: func(repo_local_root=str(repo_local_root), repo_remote_root=str(repo_remote_root)), in_global=True)
140
+ shell_file_3 = get_shell_file_executing_python_script(python_script=program_3_py, uv_with=uv_with, uv_project_dir=uv_project_dir)
138
141
  # ================================================================================
139
142
 
140
143
  option4 = "Remove problematic rclone file from repo and replace with remote:"
@@ -145,7 +148,8 @@ cd $HOME/dotfiles
145
148
  git commit -am "finished merging"
146
149
  . {shell_file_1}
147
150
  """
148
- shell_file_4 = write_shell_script_to_file(shell_script=program_4)
151
+ shell_file_4 = Path(tempfile.mkstemp(suffix=".ps1" if platform.system() == "Windows" else ".sh")[1])
152
+ shell_file_4.write_text(program_4, encoding="utf-8")
149
153
  # ================================================================================
150
154
 
151
155
  console.print(Panel("🔄 RESOLVE MERGE CONFLICT\nChoose an option to resolve the conflict:", title_align="left", border_style="blue"))
@@ -1,5 +1,4 @@
1
1
  from machineconfig.utils.path_extended import PathExtended
2
- from machineconfig.utils.code import write_shell_script_to_file
3
2
  import platform
4
3
  from pathlib import Path
5
4
  from rich.console import Console
@@ -56,11 +55,12 @@ def inspect_repos(repo_local_root: str, repo_remote_root: str):
56
55
 
57
56
  if platform.system() == "Windows":
58
57
  program = get_wt_cmd(wd1=PathExtended(repo_local_root), wd2=PathExtended(repo_local_root))
59
- write_shell_script_to_file(shell_script=program)
60
- return None
61
58
  elif platform.system() in ["Linux", "Darwin"]:
62
59
  program = get_zellij_cmd(wd1=PathExtended(repo_local_root), wd2=PathExtended(repo_remote_root))
63
- write_shell_script_to_file(shell_script=program)
64
- return None
65
60
  else:
66
61
  raise NotImplementedError(f"Platform {platform.system()} not implemented.")
62
+ import tempfile
63
+ with tempfile.NamedTemporaryFile(mode='w', suffix=".sh" if platform.system() != "Windows" else ".ps1", delete=False, encoding='utf-8') as temp_file:
64
+ temp_file.write(program)
65
+ temp_script_path = PathExtended(temp_file.name)
66
+ console.print(Panel(f"🚀 Launching repo inspection tool...\n\n[blue]{temp_script_path}[/blue]", border_style="blue"))
@@ -2,94 +2,16 @@ import atexit
2
2
  import platform
3
3
  from typing import Optional
4
4
  import subprocess
5
- from rich.console import Console
6
- from rich.panel import Panel
7
- from rich.syntax import Syntax
8
-
9
5
  from machineconfig.utils.accessories import randstr
10
- from machineconfig.utils.ve import get_ve_activate_line
11
- from machineconfig.utils.path_extended import PathExtended # type: ignore[import-not-found]
12
-
13
-
14
- def get_shell_script_executing_python_file(python_file: str, func: Optional[str], ve_path: Optional[str], executable: Optional[str], strict_execution: bool = True):
15
- if executable is None: exe_resolved = "python"
16
- else: exe_resolved = executable
17
- if func is None: exec_line = f"""{exe_resolved} {python_file}"""
18
- else: exec_line = f"""{exe_resolved} -m fire {python_file} {func}"""
19
- if ve_path is None: ve_activate_line = ""
20
- else: ve_activate_line = get_ve_activate_line(ve_path)
21
- shell_script = f"""
22
- echo "Executing {exec_line}"
23
- {ve_activate_line}
24
- {exec_line}
25
- deactivate || true
26
- """
27
- if strict_execution:
28
- if platform.system() == "Windows":
29
- shell_script = """$ErrorActionPreference = "Stop" """ + "\n" + shell_script
30
- if platform.system() in ["Linux", "Darwin"]:
31
- shell_script = "set -e" + "\n" + shell_script
32
- if platform.system() in ["Linux", "Darwin"]:
33
- shell_script = "#!/bin/bash" + "\n" + shell_script # vs #!/usr/bin/env bash
34
- return shell_script
6
+ from machineconfig.utils.path_extended import PathExtended
7
+ from pathlib import Path
35
8
 
36
9
 
37
- def get_shell_file_executing_python_script(python_script: str, ve_path: Optional[str], executable: Optional[str], verbose: bool = True):
38
- if verbose:
39
- python_script = f"""
40
- code = r'''{python_script}'''
41
- try:
42
- from machineconfig.utils.utils import print_code
43
- print_code(code=code, lexer="python", desc="Python Script")
44
- except ImportError:
10
+ def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
11
+ import platform
45
12
  from rich.console import Console
46
13
  from rich.panel import Panel
47
- console = Console()
48
- console.print(Panel(f'''📜 PYTHON SCRIPT:\n\n{{code}}''', title="Python Script", expand=False))
49
- """ + python_script
50
- python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
51
- python_file.parent.mkdir(parents=True, exist_ok=True)
52
- python_file.write_text(python_script, encoding="utf-8")
53
- shell_script = get_shell_script_executing_python_file(python_file=str(python_file), func=None, ve_path=ve_path, executable=executable)
54
- shell_file = write_shell_script_to_file(shell_script)
55
- return shell_file
56
-
57
-
58
- def write_shell_script_to_file(shell_script: str):
59
- if platform.system() in ["Linux", "Darwin"]:
60
- suffix = ".sh"
61
- elif platform.system() == "Windows":
62
- suffix = ".ps1"
63
- else:
64
- raise NotImplementedError(f"Platform {platform.system()} not implemented.")
65
- shell_file = PathExtended.tmp().joinpath("tmp_scripts", "shell", randstr() + suffix)
66
- shell_file.parent.mkdir(parents=True, exist_ok=True)
67
- shell_file.write_text(shell_script, encoding="utf-8")
68
- return shell_file
69
-
70
-
71
- def write_shell_script_to_default_program_path(program: str, desc: str, preserve_cwd: bool, display: bool, execute: bool):
72
- if preserve_cwd:
73
- if platform.system() == "Windows":
74
- program = "$orig_path = $pwd\n" + program + "\ncd $orig_path"
75
- else:
76
- program = 'orig_path=$(cd -- "." && pwd)\n' + program + '\ncd "$orig_path" || exit'
77
- if display:
78
- print_code(code=program, lexer="shell", desc=desc, subtitle="PROGRAM")
79
- if execute:
80
- result = subprocess.run(program, shell=True, capture_output=True, text=True)
81
- success = result.returncode == 0 and result.stderr == ""
82
- if not success:
83
- print("❌ 🛠️ EXECUTION | Shell script running failed")
84
- if result.stdout:
85
- print(f"STDOUT: {result.stdout}")
86
- if result.stderr:
87
- print(f"STDERR: {result.stderr}")
88
- print(f"Return code: {result.returncode}")
89
- return None
90
-
91
-
92
- def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
14
+ from rich.syntax import Syntax
93
15
  if lexer == "shell":
94
16
  if platform.system() == "Windows":
95
17
  lexer = "powershell"
@@ -101,8 +23,43 @@ def print_code(code: str, lexer: str, desc: str, subtitle: str = ""):
101
23
  console.print(Panel(Syntax(code=code, lexer=lexer), title=f"📄 {desc}", subtitle=subtitle), style="bold red")
102
24
 
103
25
 
26
+ def get_shell_file_executing_python_script(python_script: str, uv_with: Optional[list[str]], uv_project_dir: Optional[str]) -> Path:
27
+ python_file = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
28
+ python_file.parent.mkdir(parents=True, exist_ok=True)
29
+ python_file.write_text(python_script, encoding="utf-8")
30
+ if uv_with is not None and len(uv_with) > 0:
31
+ uv_with_arg = "--with " + '"' + ",".join(uv_with) + '"'
32
+ else:
33
+ uv_with_arg = ""
34
+ if uv_project_dir is not None:
35
+ uv_project_dir_arg = "--project" + f' "{uv_project_dir}"'
36
+ else:
37
+ uv_project_dir_arg = ""
38
+
39
+ from machineconfig.utils.meta import lambda_to_defstring
40
+ print_code_string = lambda_to_defstring(lambda: print_code(code=python_script, lexer="python", desc="Temporary Python Script", subtitle="Executing via shell script"), in_global=True)
41
+ python_file_tmp = PathExtended.tmp().joinpath("tmp_scripts", "python", randstr() + ".py")
42
+ python_file_tmp.parent.mkdir(parents=True, exist_ok=True)
43
+ python_file_tmp.write_text(print_code_string, encoding="utf-8")
44
+
45
+ shell_script = f"""
46
+ uv run --with rich {python_file_tmp}
47
+ uv run {uv_with_arg} {uv_project_dir_arg} {str(python_file)}
48
+ """
49
+
50
+ shell_path = PathExtended.tmp().joinpath("tmp_scripts", "shell", randstr() + (".ps1" if platform.system() == "Windows" else ".sh"))
51
+ shell_path.parent.mkdir(parents=True, exist_ok=True)
52
+ shell_path.write_text(shell_script, encoding="utf-8")
53
+ return shell_path
54
+
55
+
104
56
  def run_shell_script(script: str, display_script: bool = True, clean_env: bool = False):
105
57
  import tempfile
58
+ import platform
59
+ from rich.console import Console
60
+ from rich.panel import Panel
61
+ from rich.syntax import Syntax
62
+
106
63
  if platform.system() == "Windows":
107
64
  suffix = ".ps1"
108
65
  lexer = "powershell"
@@ -112,6 +69,7 @@ def run_shell_script(script: str, display_script: bool = True, clean_env: bool =
112
69
  with tempfile.NamedTemporaryFile(mode='w', suffix=suffix, delete=False, encoding='utf-8') as temp_file:
113
70
  temp_file.write(script)
114
71
  temp_script_path = PathExtended(temp_file.name)
72
+
115
73
  console = Console()
116
74
  if display_script:
117
75
  from rich.syntax import Syntax
@@ -138,8 +96,12 @@ def run_shell_script(script: str, display_script: bool = True, clean_env: bool =
138
96
 
139
97
 
140
98
  def run_shell_script_after_exit(script: str, display_script: bool = True) -> None:
99
+ import platform
100
+ from rich.console import Console
101
+ from rich.panel import Panel
102
+ from rich.syntax import Syntax
103
+
141
104
  console = Console()
142
-
143
105
  def execute_script_at_exit() -> None:
144
106
  if platform.system() == "Windows":
145
107
  suffix = ".ps1"
@@ -5,7 +5,7 @@ from machineconfig.utils.installer_utils.installer_class import Installer
5
5
  from machineconfig.utils.schemas.installer.installer_types import InstallerData, InstallerDataFiles, get_normalized_arch, get_os_name, OPERATING_SYSTEMS, CPU_ARCHITECTURES
6
6
  from machineconfig.jobs.installer.package_groups import PACKAGE_GROUPS, PACKAGE_GROUP2NAMES
7
7
  from machineconfig.utils.path_extended import PathExtended
8
- from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT, LINUX_INSTALL_PATH, LIBRARY_ROOT
8
+ from machineconfig.utils.source_of_truth import INSTALL_VERSION_ROOT, LINUX_INSTALL_PATH
9
9
  from machineconfig.utils.io import read_json
10
10
 
11
11
  from rich.console import Console
@@ -1,252 +1,14 @@
1
1
  """Metaprogramming utilities for analyzing and serializing Python functions."""
2
2
 
3
- import ast
4
- import inspect
5
- import textwrap
6
- from collections.abc import Callable, Mapping
7
- from types import FunctionType, ModuleType
8
- from typing import Any, ParamSpec
9
-
10
- P = ParamSpec("P")
11
-
12
-
13
- def function_to_script(func: Callable[P, object], call_with_kwargs: Mapping[str, object] | None) -> str:
14
- """Convert a function to a standalone executable Python script.
15
-
16
- This function analyzes a given function and generates a complete Python script
17
- that includes all necessary imports, global variables, the function definition,
18
- and optionally a function call.
19
-
20
- Args:
21
- func: The function to convert to a script
22
- call_with_kwargs: Optional dict of keyword arguments to call the function with
23
-
24
- Returns:
25
- A complete Python script as a string that can be executed independently
26
-
27
- Raises:
28
- ValueError: If the function cannot be inspected or analyzed
29
- """
30
- if not isinstance(func, FunctionType):
31
- raise ValueError(f"""Expected a Python function, got {type(func)}""")
32
-
33
- python_func = func
34
-
35
- imports = _extract_imports(python_func)
36
- globals_needed = _extract_globals(python_func)
37
- source_code = _get_function_source(python_func).rstrip()
38
- validated_kwargs = _prepare_call_kwargs(python_func, call_with_kwargs)
39
- call_statement = _generate_call_statement(python_func, validated_kwargs) if validated_kwargs is not None else None
40
-
41
- script_parts: list[str] = []
42
-
43
- if imports:
44
- script_parts.append(imports)
45
-
46
- if globals_needed:
47
- if script_parts:
48
- script_parts.append("")
49
- script_parts.append(globals_needed)
50
-
51
- if script_parts:
52
- script_parts.append("")
53
-
54
- script_parts.append(source_code)
55
-
56
- if call_statement is not None:
57
- script_parts.append("")
58
- script_parts.append("if __name__ == '__main__':")
59
- script_parts.append(f" {call_statement}")
60
-
61
- return "\n".join(script_parts)
62
-
63
-
64
- def _get_function_source(func: FunctionType) -> str:
65
- """Extract the source code of a function."""
66
- try:
67
- source = inspect.getsource(func)
68
- return textwrap.dedent(source)
69
- except (OSError, TypeError) as e:
70
- raise ValueError(f"Cannot get source code for function {func.__name__}: {e}") from e
71
-
72
-
73
- def _extract_imports(func: FunctionType) -> str:
74
- """Extract all import statements needed by the function."""
75
- import_statements: set[str] = set()
76
-
77
- source = _get_function_source(func)
78
- func_globals = func.__globals__
79
-
80
- try:
81
- tree = ast.parse(source)
82
- except SyntaxError as e:
83
- raise ValueError(f"Failed to parse function source: {e}") from e
84
-
85
- used_names: set[str] = set()
86
- for node in ast.walk(tree):
87
- if isinstance(node, ast.Name):
88
- used_names.add(node.id)
89
- elif isinstance(node, ast.Attribute):
90
- if isinstance(node.value, ast.Name):
91
- used_names.add(node.value.id)
92
-
93
- for node in ast.walk(tree):
94
- if isinstance(node, ast.FunctionDef):
95
- for default in node.args.defaults + node.args.kw_defaults:
96
- if default is not None:
97
- for subnode in ast.walk(default):
98
- if isinstance(subnode, ast.Name):
99
- used_names.add(subnode.id)
100
- elif isinstance(subnode, ast.Attribute):
101
- if isinstance(subnode.value, ast.Name):
102
- used_names.add(subnode.value.id)
103
-
104
- for name in used_names:
105
- if name in func_globals:
106
- obj = func_globals[name]
107
-
108
- if isinstance(obj, ModuleType):
109
- module_name = obj.__name__
110
- if name == module_name.split('.')[-1]:
111
- import_statements.add(f"import {module_name}")
112
- else:
113
- import_statements.add(f"import {module_name} as {name}")
114
-
115
- elif isinstance(obj, type) and hasattr(obj, '__module__') and obj.__module__ != '__main__':
116
- try:
117
- module_name = obj.__module__
118
- obj_name = obj.__name__ if hasattr(obj, '__name__') else name
119
-
120
- if module_name and module_name != 'builtins':
121
- if obj_name == name:
122
- import_statements.add(f"from {module_name} import {obj_name}")
123
- else:
124
- import_statements.add(f"from {module_name} import {obj_name} as {name}")
125
- except AttributeError:
126
- pass
127
-
128
- elif callable(obj) and not isinstance(obj, type) and hasattr(obj, '__module__') and obj.__module__ != '__main__':
129
- try:
130
- module_name = obj.__module__
131
- obj_name = obj.__name__ if hasattr(obj, '__name__') else name
132
-
133
- if module_name and module_name != 'builtins':
134
- if obj_name == name:
135
- import_statements.add(f"from {module_name} import {obj_name}")
136
- else:
137
- import_statements.add(f"from {module_name} import {obj_name} as {name}")
138
- except AttributeError:
139
- pass
140
-
141
- return "\n".join(sorted(import_statements))
142
-
143
-
144
- def _extract_globals(func: FunctionType) -> str:
145
- """Extract global variables needed by the function."""
146
- global_assignments: list[str] = []
147
- needed_types: set[type] = set()
148
-
149
- source = _get_function_source(func)
150
- func_globals = func.__globals__
151
-
152
- try:
153
- tree = ast.parse(source)
154
- except SyntaxError as e:
155
- raise ValueError(f"Failed to parse function source: {e}") from e
156
-
157
- used_names: set[str] = set()
158
- for node in ast.walk(tree):
159
- if isinstance(node, ast.Name):
160
- used_names.add(node.id)
161
- elif isinstance(node, ast.Attribute):
162
- if isinstance(node.value, ast.Name):
163
- used_names.add(node.value.id)
164
-
165
- for node in ast.walk(tree):
166
- if isinstance(node, ast.FunctionDef):
167
- for default in node.args.defaults + node.args.kw_defaults:
168
- if default is not None:
169
- for subnode in ast.walk(default):
170
- if isinstance(subnode, ast.Name):
171
- used_names.add(subnode.id)
172
- elif isinstance(subnode, ast.Attribute):
173
- if isinstance(subnode.value, ast.Name):
174
- used_names.add(subnode.value.id)
175
-
176
- for name in used_names:
177
- if name in func_globals:
178
- obj = func_globals[name]
179
-
180
- if not isinstance(obj, (ModuleType, FunctionType, type)):
181
- if not (hasattr(obj, '__module__') and hasattr(obj, '__name__')):
182
- try:
183
- obj_type = type(obj)
184
-
185
- if obj_type.__name__ == 'PathExtended' and obj_type.__module__ == 'machineconfig.utils.path_extended':
186
- global_assignments.append(f"{name} = PathExtended('{str(obj)}')")
187
- if obj_type.__module__ not in ['builtins', '__main__']:
188
- needed_types.add(obj_type)
189
- else:
190
- repr_str = repr(obj)
191
- if len(repr_str) < 1000 and '\n' not in repr_str and all(ord(c) < 128 or c in [' ', '\n', '\t'] for c in repr_str):
192
- global_assignments.append(f"{name} = {repr_str}")
193
- if obj_type.__module__ not in ['builtins', '__main__']:
194
- needed_types.add(obj_type)
195
- else:
196
- global_assignments.append(f"# Warning: Could not serialize global variable '{name}' (repr too complex or contains non-ASCII)")
197
- except Exception as e:
198
- global_assignments.append(f"# Warning: Could not serialize global variable '{name}': {e}")
199
-
200
- result_parts: list[str] = []
201
-
202
- if needed_types:
203
- for obj_type in sorted(needed_types, key=lambda t: (t.__module__, t.__name__)):
204
- module_name = obj_type.__module__
205
- type_name = obj_type.__name__
206
- result_parts.append(f"from {module_name} import {type_name}")
207
- result_parts.append("")
208
-
209
- result_parts.extend(global_assignments)
210
-
211
- return "\n".join(result_parts)
212
-
213
-
214
- def _prepare_call_kwargs(func: FunctionType, call_with_kwargs: Mapping[str, object] | None) -> dict[str, object] | None:
215
- if call_with_kwargs is None:
216
- return None
217
-
218
- normalized_kwargs = dict(call_with_kwargs)
219
-
220
- if not normalized_kwargs:
221
- return {}
222
-
223
- signature = inspect.signature(func)
224
- positional_only = [parameter.name for parameter in signature.parameters.values() if parameter.kind is inspect.Parameter.POSITIONAL_ONLY]
225
-
226
- if positional_only:
227
- joined = ", ".join(positional_only)
228
- raise ValueError(f"""Cannot call {func.__name__} with positional-only parameters: {joined}""")
229
-
230
- try:
231
- signature.bind(**normalized_kwargs)
232
- except TypeError as error:
233
- raise ValueError(f"""Invalid call_with_kwargs for {func.__name__}: {error}""") from error
234
-
235
- return normalized_kwargs
236
-
237
-
238
- def _generate_call_statement(func: FunctionType, kwargs: dict[str, object]) -> str:
239
- """Generate a function call statement with the given keyword arguments."""
240
- if not kwargs:
241
- return f"{func.__name__}()"
242
-
243
- arg_parts: list[str] = [f"{key}={repr(value)}" for key, value in kwargs.items()]
244
- args_str = ", ".join(arg_parts)
245
- return f"{func.__name__}({args_str})"
3
+ from collections.abc import Callable
4
+ from typing import Any
246
5
 
247
6
 
248
7
  def lambda_to_defstring(lmb: Callable[[], Any], in_global: bool = False) -> str:
249
8
  """
9
+ caveats: always use keyword arguments in the lambda call for best results.
10
+ return statement not allowed in the wrapped function (otherwise it can be put in the global space)
11
+
250
12
  Given a no-arg lambda like `lambda: func(a=var1, b=var2)`,
251
13
  return a string containing the full function definition of `func`
252
14
  but with the defaults for the parameters provided in the call replaced
@@ -423,12 +185,4 @@ def lambda_to_defstring(lmb: Callable[[], Any], in_global: bool = False) -> str:
423
185
 
424
186
 
425
187
  if __name__ == "__main__":
426
- # Example usage
427
- a = True
428
- b = 3
429
- def func(no_copy_assets: bool = a):
430
- from machineconfig.scripts.python.helpers_devops.cli_self import update
431
- update(no_copy_assets=no_copy_assets)
432
- script = function_to_script(func, call_with_kwargs=None)
433
- print(script)
434
188
  pass
@@ -1,7 +1,6 @@
1
1
  # """Task scheduler
2
2
  # """
3
3
 
4
- # from machineconfig.utils.utils import get_shell_script_executing_python_file
5
4
  # from machineconfig.utils.utils2 import read_ini
6
5
  # from dataclasses import dataclass
7
6
  # from datetime import datetime, timedelta
@@ -1,11 +1,12 @@
1
1
  from typing import Callable, Optional, Any, Union
2
2
  import os
3
3
  from pathlib import Path
4
+ import platform
4
5
  import rich.console
5
6
  from machineconfig.utils.terminal import Response, MACHINE
6
7
  from machineconfig.utils.accessories import pprint
7
8
 
8
- UV_RUN_CMD = "$HOME/.local/bin/uv run"
9
+ UV_RUN_CMD = "$HOME/.local/bin/uv run" if platform.system() != "Windows" else """& "$env:USERPROFILE/.local/bin/uv" run"""
9
10
  MACHINECONFIG_VERSION = "machineconfig>=6.52"
10
11
  DEFAULT_PICKLE_SUBDIR = "tmp_results/tmp_scripts/ssh"
11
12
 
@@ -176,7 +177,6 @@ class SSH:
176
177
  res.output.returncode = os.system(command)
177
178
  return res
178
179
 
179
-
180
180
  def run_shell(self, command: str, verbose_output: bool, description: str, strict_stderr: bool, strict_return_code: bool) -> Response:
181
181
  raw = self.ssh.exec_command(command)
182
182
  res = Response(stdin=raw[0], stdout=raw[1], stderr=raw[2], cmd=command, desc=description) # type: ignore
@@ -186,31 +186,30 @@ class SSH:
186
186
  res.capture().print_if_unsuccessful(desc=description, strict_err=strict_stderr, strict_returncode=strict_return_code, assert_success=False)
187
187
  self.terminal_responses.append(res)
188
188
  return res
189
- def run_py(self, python_code: str, dependencies: list[str], venv_path: Optional[str],
189
+ def run_py(self, python_code: str, uv_with: Optional[list[str]], uv_project_dir: Optional[str],
190
190
  description: str, verbose_output: bool, strict_stderr: bool, strict_return_code: bool) -> Response:
191
191
  from machineconfig.utils.accessories import randstr
192
192
  cmd_path = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/runpy_{randstr()}.py")
193
193
  cmd_path.parent.mkdir(parents=True, exist_ok=True)
194
194
  cmd_path.write_text(python_code, encoding="utf-8")
195
195
  self.copy_from_here(source_path=cmd_path, target_path=None, compress_with_zip=False, recursive=False, overwrite_existing=False)
196
- if len(dependencies) > 0:
197
- with_clause = " --with " + '"', ",".join(dependencies) + '"'
196
+ if uv_with is not None and len(uv_with) > 0:
197
+ with_clause = " --with " + '"' + ",".join(uv_with) + '"'
198
198
  else:
199
199
  with_clause = ""
200
+ if uv_project_dir is not None:
201
+ with_clause += f" --project {uv_project_dir}"
202
+ else:
203
+ with_clause += ""
200
204
  uv_cmd = f"""{UV_RUN_CMD} {with_clause} python {cmd_path.relative_to(Path.home())}"""
201
- if venv_path is not None:
202
- if self.get_remote_machine() == "Windows":
203
- venv_export = f"$env:VIRTUAL_ENV='{venv_path}';"
204
- uv_cmd = venv_export + uv_cmd
205
- else:
206
- venv_export = f"VIRTUAL_ENV={venv_path}"
207
- uv_cmd = venv_export + " " + uv_cmd
208
205
  return self.run_shell(command=uv_cmd, verbose_output=verbose_output, description=description or f"run_py on {self.get_remote_repr(add_machine=False)}", strict_stderr=strict_stderr, strict_return_code=strict_return_code)
209
206
 
210
- def run_py_func(self, func: Callable[..., Any], dependencies: list[str], venv_path: Optional[str]) -> Response:
211
- from machineconfig.utils.meta import function_to_script
212
- command = function_to_script(func=func, call_with_kwargs={})
213
- return self.run_py(python_code=command, dependencies=dependencies, venv_path=venv_path, description=f"run_py_func {func.__name__} on {self.get_remote_repr(add_machine=False)}", verbose_output=True, strict_stderr=True, strict_return_code=True)
207
+ def run_py_func(self, func: Callable[..., Any], uv_with: Optional[list[str]], uv_project_dir: Optional[str]) -> Response:
208
+ from machineconfig.utils.meta import lambda_to_defstring
209
+ command = lambda_to_defstring(lmb=lambda: func, in_global=True)
210
+ return self.run_py(python_code=command, uv_with=uv_with, uv_project_dir=uv_project_dir,
211
+ description=f"run_py_func {func.__name__} on {self.get_remote_repr(add_machine=False)}",
212
+ verbose_output=True, strict_stderr=True, strict_return_code=True)
214
213
 
215
214
  def _simple_sftp_get(self, remote_path: str, local_path: Path) -> None:
216
215
  """Simple SFTP get without any recursion or path expansion - for internal use only."""
@@ -238,11 +237,14 @@ class SSH:
238
237
  json_result_path.write_text(json.dumps(result_path_posix, indent=2), encoding="utf-8")
239
238
  print(json_result_path.as_posix())
240
239
  return result_path_posix
241
- from machineconfig.utils.meta import function_to_script
240
+ from machineconfig.utils.meta import lambda_to_defstring
242
241
  from machineconfig.utils.accessories import randstr
243
242
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
244
- command = function_to_script(func=create_target_dir, call_with_kwargs={"target_dir_path": Path(target_path).as_posix(), "overwrite": overwrite_existing, "json_output_path": remote_json_output})
245
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description=f"Creating target directory `{Path(target_path).parent.as_posix()}` @ {self.get_remote_repr(add_machine=False)}", verbose_output=False, strict_stderr=False, strict_return_code=False)
243
+ # command = function_to_script(func=create_target_dir, call_with_kwargs={"target_dir_path": Path(target_path).as_posix(), "overwrite": overwrite_existing, "json_output_path": remote_json_output})
244
+ command = lambda_to_defstring(lmb=lambda: create_target_dir(target_dir_path=str(target_path), overwrite=overwrite_existing, json_output_path=remote_json_output), in_global=True)
245
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None,
246
+ description=f"Creating target directory `{Path(target_path).parent.as_posix()}` @ {self.get_remote_repr(add_machine=False)}",
247
+ verbose_output=False, strict_stderr=False, strict_return_code=False)
246
248
  remote_json_path = response.op.strip()
247
249
  if not remote_json_path:
248
250
  raise RuntimeError(f"Failed to create target directory {target_path} - no response from remote")
@@ -323,11 +325,10 @@ class SSH:
323
325
  with zipfile.ZipFile(archive_path, "r") as archive_handle:
324
326
  archive_handle.extractall(extraction_directory)
325
327
  archive_path.unlink()
326
- from machineconfig.utils.meta import function_to_script
327
- command = function_to_script(func=unzip_archive, call_with_kwargs={"zip_file_path": remotepath.as_posix(), "overwrite_flag": overwrite_existing})
328
- _resp = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description=f"UNZIPPING {remotepath.as_posix()}", verbose_output=False, strict_stderr=True, strict_return_code=True)
328
+ from machineconfig.utils.meta import lambda_to_defstring
329
+ command = lambda_to_defstring(lmb=lambda: unzip_archive(zip_file_path=remotepath.as_posix(), overwrite_flag=overwrite_existing), in_global=True)
330
+ _resp = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"UNZIPPING {remotepath.as_posix()}", verbose_output=False, strict_stderr=True, strict_return_code=True)
329
331
  source_obj.unlink()
330
- print("\n")
331
332
  return source_obj
332
333
 
333
334
  def _check_remote_is_dir(self, source_path: Union[str, Path]) -> bool:
@@ -342,11 +343,11 @@ class SSH:
342
343
  print(json_result_path.as_posix())
343
344
  return is_directory
344
345
 
345
- from machineconfig.utils.meta import function_to_script
346
+ from machineconfig.utils.meta import lambda_to_defstring
346
347
  from machineconfig.utils.accessories import randstr
347
348
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
348
- command = function_to_script(func=check_is_dir, call_with_kwargs={"path_to_check": str(source_path), "json_output_path": remote_json_output})
349
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description=f"Check if source `{source_path}` is a dir", verbose_output=False, strict_stderr=False, strict_return_code=False)
349
+ command = lambda_to_defstring(lmb=lambda: check_is_dir(path_to_check=str(source_path), json_output_path=remote_json_output), in_global=True)
350
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"Check if source `{source_path}` is a dir", verbose_output=False, strict_stderr=False, strict_return_code=False)
350
351
  remote_json_path = response.op.strip()
351
352
  if not remote_json_path:
352
353
  raise RuntimeError(f"Failed to check if {source_path} is directory - no response from remote")
@@ -376,11 +377,11 @@ class SSH:
376
377
  print(json_result_path.as_posix())
377
378
  return expanded_path_posix
378
379
 
379
- from machineconfig.utils.meta import function_to_script
380
+ from machineconfig.utils.meta import lambda_to_defstring
380
381
  from machineconfig.utils.accessories import randstr
381
382
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
382
- command = function_to_script(func=expand_source, call_with_kwargs={"path_to_expand": str(source_path), "json_output_path": remote_json_output})
383
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description="Resolving source path by expanding user", verbose_output=False, strict_stderr=False, strict_return_code=False)
383
+ command = lambda_to_defstring(lmb=lambda: expand_source(path_to_expand=str(source_path), json_output_path=remote_json_output), in_global=True)
384
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Resolving source path by expanding user", verbose_output=False, strict_stderr=False, strict_return_code=False)
384
385
  remote_json_path = response.op.strip()
385
386
  if not remote_json_path:
386
387
  raise RuntimeError(f"Could not resolve source path {source_path} - no response from remote")
@@ -425,11 +426,11 @@ class SSH:
425
426
  print(json_result_path.as_posix())
426
427
  return file_paths_list
427
428
 
428
- from machineconfig.utils.meta import function_to_script
429
+ from machineconfig.utils.meta import lambda_to_defstring
429
430
  from machineconfig.utils.accessories import randstr
430
431
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
431
- command = function_to_script(func=search_files, call_with_kwargs={"directory_path": expanded_source, "json_output_path": remote_json_output})
432
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description="Searching for files in source", verbose_output=False, strict_stderr=False, strict_return_code=False)
432
+ command = lambda_to_defstring(lmb=lambda: search_files(directory_path=expanded_source, json_output_path=remote_json_output), in_global=True)
433
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Searching for files in source", verbose_output=False, strict_stderr=False, strict_return_code=False)
433
434
  remote_json_path = response.op.strip()
434
435
  if not remote_json_path:
435
436
  raise RuntimeError(f"Could not resolve source path {source} - no response from remote")
@@ -463,11 +464,11 @@ class SSH:
463
464
  except ValueError:
464
465
  raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
465
466
 
466
- from machineconfig.utils.meta import function_to_script
467
+ from machineconfig.utils.meta import lambda_to_defstring
467
468
  from machineconfig.utils.accessories import randstr
468
469
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
469
- command = function_to_script(func=collapse_to_home_dir, call_with_kwargs={"absolute_path": expanded_source, "json_output_path": remote_json_output})
470
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
470
+ command = lambda_to_defstring(lmb=lambda: collapse_to_home_dir(absolute_path=expanded_source, json_output_path=remote_json_output), in_global=True)
471
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
471
472
  remote_json_path_dir = response.op.strip()
472
473
  if not remote_json_path_dir:
473
474
  raise RuntimeError("Could not resolve target path - no response from remote")
@@ -515,11 +516,11 @@ class SSH:
515
516
  print(json_result_path.as_posix())
516
517
  return zip_file_path
517
518
 
518
- from machineconfig.utils.meta import function_to_script
519
+ from machineconfig.utils.meta import lambda_to_defstring
519
520
  from machineconfig.utils.accessories import randstr
520
521
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
521
- command = function_to_script(func=zip_source, call_with_kwargs={"path_to_zip": expanded_source, "json_output_path": remote_json_output})
522
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description=f"Zipping source file {source}", verbose_output=False, strict_stderr=False, strict_return_code=False)
522
+ command = lambda_to_defstring(lmb=lambda: zip_source(path_to_zip=expanded_source, json_output_path=remote_json_output), in_global=True)
523
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description=f"Zipping source file {source}", verbose_output=False, strict_stderr=False, strict_return_code=False)
523
524
  remote_json_path = response.op.strip()
524
525
  if not remote_json_path:
525
526
  raise RuntimeError(f"Could not zip {source} - no response from remote")
@@ -554,11 +555,11 @@ class SSH:
554
555
  except ValueError:
555
556
  raise RuntimeError(f"Source path must be relative to home directory: {source_absolute_path}")
556
557
 
557
- from machineconfig.utils.meta import function_to_script
558
+ from machineconfig.utils.meta import lambda_to_defstring
558
559
  from machineconfig.utils.accessories import randstr
559
560
  remote_json_output = Path.home().joinpath(f"{DEFAULT_PICKLE_SUBDIR}/return_{randstr()}.json").as_posix()
560
- command = function_to_script(func=collapse_to_home, call_with_kwargs={"absolute_path": expanded_source, "json_output_path": remote_json_output})
561
- response = self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
561
+ command = lambda_to_defstring(lmb=lambda: collapse_to_home(absolute_path=expanded_source, json_output_path=remote_json_output), in_global=True)
562
+ response = self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Finding default target via relative source path", verbose_output=False, strict_stderr=False, strict_return_code=False)
562
563
  remote_json_path = response.op.strip()
563
564
  if not remote_json_path:
564
565
  raise RuntimeError("Could not resolve target path - no response from remote")
@@ -612,9 +613,9 @@ class SSH:
612
613
  else:
613
614
  file_or_dir_path.unlink()
614
615
 
615
- from machineconfig.utils.meta import function_to_script
616
- command = function_to_script(func=delete_temp_zip, call_with_kwargs={"path_to_delete": expanded_source})
617
- self.run_py(python_code=command, dependencies=[MACHINECONFIG_VERSION], venv_path=None, description="Cleaning temp zip files @ remote.", verbose_output=False, strict_stderr=True, strict_return_code=True)
616
+ from machineconfig.utils.meta import lambda_to_defstring
617
+ command = lambda_to_defstring(lmb=lambda: delete_temp_zip(path_to_delete=expanded_source), in_global=True)
618
+ self.run_py(python_code=command, uv_with=[MACHINECONFIG_VERSION], uv_project_dir=None, description="Cleaning temp zip files @ remote.", verbose_output=False, strict_stderr=True, strict_return_code=True)
618
619
 
619
620
  print("\n")
620
621
  return target_obj
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 6.52
3
+ Version: 6.53
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0
@@ -25,7 +25,7 @@ machineconfig/cluster/sessions_managers/zellij_remote_manager.py,sha256=xzih0y8_
25
25
  machineconfig/cluster/sessions_managers/helpers/enhanced_command_runner.py,sha256=3vcQVg-HHa_WTxBGPtKMAdoSqJVa2EO5KAtrY8a6I3c,5264
26
26
  machineconfig/cluster/sessions_managers/helpers/load_balancer_helper.py,sha256=i5TRittC1IWTgMZNyG8AR5qq-3WrGp3xgIx2m5ktT7g,7526
27
27
  machineconfig/cluster/sessions_managers/utils/load_balancer.py,sha256=Y4RQmhROY6o7JXSJXRrBTkoAuEmu1gvmvN_7JKPw5sc,3178
28
- machineconfig/cluster/sessions_managers/utils/maker.py,sha256=kUJLOctqRR_jumdDIssxBI65pBhBEHxDOOq_RohnoeU,2133
28
+ machineconfig/cluster/sessions_managers/utils/maker.py,sha256=_Af8kCmWfE_17tQFjb7jBpjAclCku7SME-5Y26j_wHQ,2123
29
29
  machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py,sha256=OA50j16uUS9ZTjL38TLuR3jufIOln_EszMZpbWyejTo,6972
30
30
  machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py,sha256=Mitm7mKiKl5lT0OiEUHAqVg2Q21RjsKO1-hpJTHJ5lM,15196
31
31
  machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py,sha256=lApUy67_WhfaBXqt0meZSx_QvwiXjN0YLdyE3c7kP_s,6744
@@ -186,7 +186,7 @@ machineconfig/scripts/python/helpers_devops/cli_repos.py,sha256=Xwkv1adqHZvTfRSP
186
186
  machineconfig/scripts/python/helpers_devops/cli_self.py,sha256=-IyJpuw8Wnttls8y2vcNNkxtI9jUveROMPT-eudOoC4,6171
187
187
  machineconfig/scripts/python/helpers_devops/cli_share_server.py,sha256=q9pFJ6AxPuygMr3onMNOKEuuQHbVE_6Qoyo7xRT5FX0,4196
188
188
  machineconfig/scripts/python/helpers_devops/cli_terminal.py,sha256=k_PzXaiGyE0vXr0Ii1XcJz2A7UvyPJrR31TRWt4RKRI,6019
189
- machineconfig/scripts/python/helpers_devops/cli_utils.py,sha256=G2RHnOvNfEWjxETZjXVu688xyLL-c0Zq22p24kXLLQ8,3487
189
+ machineconfig/scripts/python/helpers_devops/cli_utils.py,sha256=FcvC_795dKxZQM7hL4uRzmhysKi9YV-v9qu2Gb_Fun8,5622
190
190
  machineconfig/scripts/python/helpers_devops/devops_backup_retrieve.py,sha256=Dn8luB6QJzxKiiFSC-NMqiYddWZoca3A8eOjMYZDzTc,5598
191
191
  machineconfig/scripts/python/helpers_devops/devops_status.py,sha256=PJVPhfhXq8der6Xd-_fjZfnizfM-RGfJApkRGhGBmNo,20525
192
192
  machineconfig/scripts/python/helpers_devops/devops_update_repos.py,sha256=kSln8_-Wn7Qu0NaKdt-QTN_bBVyTIAWHH8xVYKK-vCM,10133
@@ -222,14 +222,14 @@ machineconfig/scripts/python/helpers_navigator/main_app.py,sha256=R1vOBMUKaiFHOg
222
222
  machineconfig/scripts/python/helpers_navigator/search_bar.py,sha256=kDi8Jhxap8wdm7YpDBtfhwcPnSqDPFrV2LqbcSBWMT4,414
223
223
  machineconfig/scripts/python/helpers_repos/action.py,sha256=9AxWy8mB9HFeV5t11-qD_l-KA5jkUmm0pXVKT1L6-Qk,14894
224
224
  machineconfig/scripts/python/helpers_repos/clone.py,sha256=UULEG5xJuXlPGU0nqXH6U45jA9DOFqLw8B4iPytCwOQ,5471
225
- machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=fLWZN1ZRlfFvKQHBLyFNHayYZAYQTZqBerRcpb7XBII,10412
225
+ machineconfig/scripts/python/helpers_repos/cloud_repo_sync.py,sha256=vVJZjZW2rrNRyIwZJ8O2W4QR9aY2faCinK9eu5Ijuz4,10526
226
226
  machineconfig/scripts/python/helpers_repos/count_lines.py,sha256=Q5c7b-DxvTlQmljoic7niTuiAVyFlwYvkVQ7uRJHiTo,16009
227
227
  machineconfig/scripts/python/helpers_repos/count_lines_frontend.py,sha256=epbXDwuXe_9jXaX3KA2JlG1sPXybdGq1NX4dRljHpF8,607
228
228
  machineconfig/scripts/python/helpers_repos/entrypoint.py,sha256=WYEFGUJp9HWImlFjbs_hiFZrUqM_KEYm5VvSUjWd04I,2810
229
229
  machineconfig/scripts/python/helpers_repos/grource.py,sha256=oJj1-gqlkV3Z_BrIOXRmtzoXcuBl0xTYfulJ5D0srOc,14656
230
230
  machineconfig/scripts/python/helpers_repos/record.py,sha256=FQo0swuJZOp0I2XGK-t1OQU4zJHmQ2z9zTpDD30Tmg4,11001
231
231
  machineconfig/scripts/python/helpers_repos/secure_repo.py,sha256=fW_GyHqWrpnf7nexHojfWHv4eLBa71IhVL_LSVMyGnE,1115
232
- machineconfig/scripts/python/helpers_repos/sync.py,sha256=CLLWy2n2gY9beXPF-mblOQ6R7cKoenkJjMiX7tHQsBk,3091
232
+ machineconfig/scripts/python/helpers_repos/sync.py,sha256=P0P7Dog2uFDvwxcLP3YHPwm6AtvCm6QOz1BLqw53xOo,3259
233
233
  machineconfig/scripts/python/helpers_repos/update.py,sha256=cUIMUMm-50HrY6fzxSMZnFplhToVjVPZMm1j_otTha4,11060
234
234
  machineconfig/scripts/python/helpers_sessions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
235
235
  machineconfig/scripts/python/helpers_sessions/sessions_multiprocess.py,sha256=zLssrCT3WRReiK0AFwctELN_o_svKypagUwJj0nT6i4,3122
@@ -390,20 +390,20 @@ machineconfig/setup_windows/wt_and_pwsh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5J
390
390
  machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py,sha256=ogxJnwpdcpH7N6dFJu95UCNoGYirZKQho_3X0F_hmXs,6791
391
391
  machineconfig/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
392
392
  machineconfig/utils/accessories.py,sha256=W_9dLzjwNTW5JQk_pe3B2ijQ1nA2-8Kdg2r7VBtzgQs,4340
393
- machineconfig/utils/code.py,sha256=W0JFDF1ynJJIYtrAP6IqCcmrhvS-_zyDz43etnWW7_4,7543
394
- machineconfig/utils/installer.py,sha256=afQgxDGsiS6HM0UQzQ85cPT4EcoXX2H0QOH5mQ18wtM,10391
393
+ machineconfig/utils/code.py,sha256=h6g7cvmUG0AQ_hUiMPZZ3rDtN1_0N1aLhRHI2dJVze8,5774
394
+ machineconfig/utils/installer.py,sha256=UzI_DtTcKbgvkAkWkNLAPUtx-RVqITHCpvZyLiCpD9g,10377
395
395
  machineconfig/utils/io.py,sha256=4dSieoqZO8Vvi4vW8lLoITDHBvmFp4dtl3kyeZHQ6Co,2528
396
396
  machineconfig/utils/links.py,sha256=KM6vIn3hag9FYEzLSHP5MAM9tU_RStw2mCq2_OvmmZA,23672
397
- machineconfig/utils/meta.py,sha256=r557UPqgNLXzQpk8Umeujj9RnRBeIz3RwOwjZ7hWsw0,17309
397
+ machineconfig/utils/meta.py,sha256=-ki5JxPZoPhg5omM2YChUNExNx5mOoX-a2w0rx51NBE,7453
398
398
  machineconfig/utils/notifications.py,sha256=tuXIudcip0tEioG-bm8BbLr3FMDve4f6BktlznBhKxM,9013
399
399
  machineconfig/utils/options.py,sha256=vUO4Kej-vDOv64wHr2HNDyu6PATURpjd7xp6N8OOoJg,7083
400
400
  machineconfig/utils/path_extended.py,sha256=WyJwoHnXdvSQQJ-yrxTX78FpqYmgVeKDYpNEB9UsRck,53223
401
401
  machineconfig/utils/path_helper.py,sha256=0e3Xh3BAEv27oqcezNeVLHJllGmLEgLH4T1l90m-650,8014
402
402
  machineconfig/utils/procs.py,sha256=YPA_vEYQGwPd_o_Lc6nOTBo5BrB1tSs8PJ42XiGpenM,10957
403
403
  machineconfig/utils/scheduler.py,sha256=44CASABJg3epccxhAwv2CX7TVgZh6zVy3K4vqHKTuf4,14228
404
- machineconfig/utils/scheduling.py,sha256=RF1iXJpqf4Dg18jdZWtBixz97KAHC6VKYqTFSpdLWuc,11188
404
+ machineconfig/utils/scheduling.py,sha256=6x5zLA7sY5gohrEtN6zGrXIqNFasMoyBfwLcOjrjiME,11109
405
405
  machineconfig/utils/source_of_truth.py,sha256=ZAnCRltiM07ig--P6g9_6nEAvNFC4X4ERFTVcvpIYsE,764
406
- machineconfig/utils/ssh.py,sha256=pBGZPmai5x_9zhIsmd66xiZvHZLDVUbeOn8pBZibKp4,39079
406
+ machineconfig/utils/ssh.py,sha256=x3JZGbUVexn_OvsIIRGC7CafOOpu-M9H-LkK9nYyL_k,39315
407
407
  machineconfig/utils/terminal.py,sha256=IlmOByfQG-vjhaFFxxzU5rWzP5_qUzmalRfuey3PAmc,11801
408
408
  machineconfig/utils/tst.py,sha256=6u1GI49NdcpxH2BYGAusNfY5q9G_ytCGVzFM5b6HYpM,674
409
409
  machineconfig/utils/upgrade_packages.py,sha256=mSFyKvB3JhHte_x1dtmEgrJZCAXgTUQoaJUSx1OXQ3Y,4145
@@ -432,8 +432,8 @@ machineconfig/utils/schemas/installer/installer_types.py,sha256=QClRY61QaduBPJoS
432
432
  machineconfig/utils/schemas/layouts/layout_types.py,sha256=TcqlZdGVoH8htG5fHn1KWXhRdPueAcoyApppZsPAPto,2020
433
433
  machineconfig/utils/schemas/repos/repos_types.py,sha256=ECVr-3IVIo8yjmYmVXX2mnDDN1SLSwvQIhx4KDDQHBQ,405
434
434
  machineconfig/utils/ssh_utils/utils.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
435
- machineconfig-6.52.dist-info/METADATA,sha256=Utdnwcdeihed2hrfWbWheAB2vgB30EKxqNlPxUk6OSI,2928
436
- machineconfig-6.52.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
437
- machineconfig-6.52.dist-info/entry_points.txt,sha256=M0jwN_brZdXWhmNVeXLvdKxfkv8WhhXFZYcuKBA9qnk,418
438
- machineconfig-6.52.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
439
- machineconfig-6.52.dist-info/RECORD,,
435
+ machineconfig-6.53.dist-info/METADATA,sha256=JtRwcaUo25t5Th849tT7K2ZBOUMP-FM5FRRckm4auYE,2928
436
+ machineconfig-6.53.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
437
+ machineconfig-6.53.dist-info/entry_points.txt,sha256=M0jwN_brZdXWhmNVeXLvdKxfkv8WhhXFZYcuKBA9qnk,418
438
+ machineconfig-6.53.dist-info/top_level.txt,sha256=porRtB8qms8fOIUJgK-tO83_FeH6Bpe12oUVC670teA,14
439
+ machineconfig-6.53.dist-info/RECORD,,