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

Files changed (30) hide show
  1. machineconfig/cluster/sessions_managers/zellij_local.py +2 -2
  2. machineconfig/cluster/sessions_managers/zellij_remote.py +2 -2
  3. machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +2 -2
  4. machineconfig/jobs/python/vscode/api.py +8 -7
  5. machineconfig/scripts/python/ai/initai.py +1 -11
  6. machineconfig/scripts/python/cloud_copy.py +33 -27
  7. machineconfig/scripts/python/cloud_manager.py +0 -2
  8. machineconfig/scripts/python/cloud_mount.py +13 -10
  9. machineconfig/scripts/python/cloud_sync.py +30 -28
  10. machineconfig/scripts/python/croshell.py +46 -53
  11. machineconfig/scripts/python/dotfile.py +16 -16
  12. machineconfig/scripts/python/fire_jobs.py +30 -14
  13. machineconfig/scripts/python/fire_jobs_args_helper.py +43 -15
  14. machineconfig/scripts/python/helpers/helpers4.py +0 -2
  15. machineconfig/scripts/python/scheduler.py +0 -1
  16. machineconfig/scripts/python/share_terminal.py +41 -0
  17. machineconfig/scripts/python/start_slidev.py +15 -13
  18. machineconfig/scripts/python/start_terminals.py +19 -19
  19. machineconfig/scripts/python/t4.py +16 -0
  20. machineconfig/scripts/python/wifi_conn.py +16 -14
  21. machineconfig/scripts/python/wsl_windows_transfer.py +23 -29
  22. machineconfig/utils/ai/generate_file_checklist.py +17 -17
  23. {machineconfig-3.83.dist-info → machineconfig-3.85.dist-info}/METADATA +1 -1
  24. {machineconfig-3.83.dist-info → machineconfig-3.85.dist-info}/RECORD +27 -28
  25. {machineconfig-3.83.dist-info → machineconfig-3.85.dist-info}/entry_points.txt +5 -5
  26. machineconfig/cluster/templates/cli_gooey.py +0 -115
  27. machineconfig/jobs/python/vscode/link_ve.py +0 -63
  28. machineconfig/jobs/python/vscode/select_interpreter.py +0 -87
  29. {machineconfig-3.83.dist-info → machineconfig-3.85.dist-info}/WHEEL +0 -0
  30. {machineconfig-3.83.dist-info → machineconfig-3.85.dist-info}/top_level.txt +0 -0
@@ -8,7 +8,6 @@ fire
8
8
  """
9
9
 
10
10
  from machineconfig.scripts.python.helpers.helpers4 import search_for_files_of_interest
11
- from machineconfig.scripts.python.helpers.helpers4 import convert_kwargs_to_fire_kwargs_str
12
11
  from machineconfig.scripts.python.helpers.helpers4 import parse_pyfile
13
12
  from machineconfig.scripts.python.helpers.helpers4 import get_import_module_code
14
13
  from machineconfig.utils.ve import get_ve_activate_line, get_ve_path_and_ipython_profile
@@ -17,7 +16,7 @@ from machineconfig.utils.path_helper import match_file_name, sanitize_path
17
16
 
18
17
  from machineconfig.utils.path_extended import PathExtended as PathExtended
19
18
  from machineconfig.utils.accessories import get_repo_root, randstr
20
- from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs
19
+ from machineconfig.scripts.python.fire_jobs_args_helper import FireJobArgs, extract_kwargs, parse_fire_args_from_context
21
20
  import platform
22
21
  from typing import Optional, Annotated
23
22
  from pathlib import Path
@@ -26,7 +25,7 @@ import typer
26
25
  # import os
27
26
 
28
27
 
29
- def route(args: FireJobArgs) -> None:
28
+ def route(args: FireJobArgs, fire_args: str = "") -> None:
30
29
  if args.layout:
31
30
  from machineconfig.scripts.python.fire_jobs_layout_helper import handle_layout_args
32
31
 
@@ -51,7 +50,7 @@ def route(args: FireJobArgs) -> None:
51
50
  ipy_profile = "default"
52
51
 
53
52
  if choice_file.suffix == ".py":
54
- kwargs = extract_kwargs(args)
53
+ kwargs = extract_kwargs(args) # This now returns empty dict, but kept for compatibility
55
54
  activate_ve_line = get_ve_activate_line(ve_root=args.ve or ve_root_from_file or "$HOME/code/machineconfig/.venv")
56
55
  else:
57
56
  activate_ve_line = ""
@@ -217,8 +216,7 @@ except ImportError as _ex:
217
216
  # both selected function and kwargs are mentioned in the made up script, therefore no need for fire module.
218
217
  command = f"{exe} {choice_file} "
219
218
  elif choice_function is not None:
220
- kwargs_str = convert_kwargs_to_fire_kwargs_str(kwargs)
221
- command = f"{exe} -m fire {choice_file} {choice_function} {kwargs_str}"
219
+ command = f"{exe} -m fire {choice_file} {choice_function} {fire_args}"
222
220
  elif args.streamlit:
223
221
  # for .streamlit config to work, it needs to be in the current directory.
224
222
  if args.holdDirectory:
@@ -230,8 +228,7 @@ except ImportError as _ex:
230
228
  command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
231
229
  else:
232
230
  if choice_file.suffix == "":
233
- kwargs_raw = " ".join(args.kw) if args.kw is not None else ""
234
- command = f"{exe} {choice_file} {kwargs_raw}"
231
+ command = f"{exe} {choice_file} {fire_args}"
235
232
  else:
236
233
  # command = f"cd {choice_file.parent}\n{exe} {choice_file.name}\ncd {PathExtended.cwd()}"
237
234
  command = f"{exe} {choice_file} "
@@ -330,7 +327,8 @@ python -m machineconfig.cluster.templates.cli_click --file {choice_file} """
330
327
 
331
328
 
332
329
  def main(
333
- path: Annotated[str, typer.Argument(help="The directory containing the jobs")] = ".",
330
+ ctx: typer.Context,
331
+ path: Annotated[str, typer.Argument(help="Path to the Python file to run")] = ".",
334
332
  function: Annotated[Optional[str], typer.Argument(help="Function to run")] = None,
335
333
  ve: Annotated[str, typer.Option("--ve", "-v", help="Virtual environment name")] = "",
336
334
  cmd: Annotated[bool, typer.Option("--cmd", "-B", help="Create a cmd fire command to launch the job asynchronously")] = False,
@@ -351,10 +349,13 @@ def main(
351
349
  Nprocess: Annotated[int, typer.Option("--Nprocess", "-p", help="Number of processes to use")] = 1,
352
350
  zellij_tab: Annotated[Optional[str], typer.Option("--zellij_tab", "-z", help="Open in a new zellij tab")] = None,
353
351
  watch: Annotated[bool, typer.Option("--watch", "-w", help="Watch the file for changes")] = False,
354
- kw: Annotated[Optional[list[str]], typer.Option("--kw", help="Keyword arguments to pass to the function in the form of k1 v1 k2 v2 ... (meaning k1=v1, k2=v2, etc)")] = None,
355
352
  layout: Annotated[bool, typer.Option("--layout", "-L", help="Use layout configuration (Zellij Or WindowsTerminal)")] = False,
356
353
  ) -> None:
357
354
  """Main function to process fire jobs arguments."""
355
+
356
+ # Get Fire arguments from context
357
+ fire_args = parse_fire_args_from_context(ctx)
358
+
358
359
  args = FireJobArgs(
359
360
  path=path,
360
361
  function=function,
@@ -377,16 +378,31 @@ def main(
377
378
  Nprocess=Nprocess,
378
379
  zellij_tab=zellij_tab,
379
380
  watch=watch,
380
- kw=kw,
381
381
  layout=layout,
382
382
  )
383
- route(args)
383
+ try:
384
+ route(args, fire_args)
385
+ except SystemExit:
386
+ # Re-raise SystemExit to preserve exit codes and allow clean exits
387
+ raise
388
+ except Exception as e:
389
+ # For other exceptions, print clean error message and exit
390
+ import sys
391
+ print(f"❌ Error: {e}", file=sys.stderr)
392
+ sys.exit(1)
384
393
 
385
394
 
386
395
  def main_from_parser():
387
- typer.run(main)
396
+ # from trogon.typer import init_tui
397
+ # from trogon.typer import init_tui
398
+ from typer import Typer
399
+ app = Typer(add_completion=False)
400
+ app.command(context_settings={"allow_extra_args": True, "allow_interspersed_args": False})(main)
401
+ # typer.run(main)
402
+ # init_tui(app)
403
+ app()
388
404
 
389
405
 
390
406
  if __name__ == "__main__":
391
407
  # options, func_args = parse_pyfile(file_path="C:/Users/aalsaf01/code/machineconfig/myresources/crocodile/core.py")
392
- pass
408
+ main_from_parser()
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
2
+ from typing import Optional, Any
3
3
 
4
4
 
5
5
  @dataclass
@@ -27,21 +27,49 @@ class FireJobArgs:
27
27
  Nprocess: int = 1
28
28
  zellij_tab: Optional[str] = None
29
29
  watch: bool = False
30
- kw: Optional[list[str]] = None
31
30
  layout: bool = False
32
31
 
33
32
 
34
33
  def extract_kwargs(args: FireJobArgs) -> dict[str, object]:
35
- str2obj = {"True": True, "False": False, "None": None}
36
- if args.kw is not None:
37
- assert len(args.kw) % 2 == 0, f"args.kw must be a list of even length. Got {len(args.kw)}"
38
- kwargs = dict(zip(args.kw[::2], args.kw[1::2]))
39
- kwargs: dict[str, object]
40
- for key, value in kwargs.items():
41
- if value in str2obj:
42
- kwargs[key] = str2obj[str(value)]
43
- if args.function is None: # if user passed arguments and forgot to pass function, then assume they want to run the main function.
44
- args.choose_function = True
45
- else:
46
- kwargs = {}
47
- return kwargs
34
+ """Extract kwargs from command line using -- separator.
35
+
36
+ Returns empty dict since kwargs are now parsed directly from sys.argv
37
+ using the -- separator pattern in the main function.
38
+ """
39
+ return {}
40
+
41
+
42
+ def parse_fire_args_from_argv() -> str:
43
+ """Parse arguments after -- separator for Fire compatibility.
44
+
45
+ Returns:
46
+ String of Fire-compatible arguments to append to command
47
+ """
48
+ import sys
49
+
50
+ if '--' in sys.argv:
51
+ separator_index = sys.argv.index('--')
52
+ fire_args = sys.argv[separator_index + 1:]
53
+ # Join all Fire arguments - they should already be in Fire format
54
+ return ' '.join(fire_args) if fire_args else ''
55
+
56
+ return ''
57
+
58
+
59
+ def parse_fire_args_from_context(ctx: Any) -> str:
60
+ """Parse Fire arguments from typer context.
61
+
62
+ Args:
63
+ ctx: Typer context containing raw arguments
64
+
65
+ Returns:
66
+ String of Fire-compatible arguments to append to command
67
+ """
68
+ # Get remaining args that weren't consumed by typer
69
+ if hasattr(ctx, 'args') and ctx.args:
70
+ args = ctx.args
71
+ # Filter out the -- separator if present
72
+ if args and args[0] == '--':
73
+ args = args[1:]
74
+ return ' '.join(args)
75
+ return ''
@@ -2,9 +2,7 @@ from typing import Any, Callable, Optional
2
2
  import inspect
3
3
  import os
4
4
 
5
- # import argparse
6
5
  from machineconfig.utils.path_extended import PathExtended as PathExtended
7
- # from machineconfig.utils.utils import choose_ssh_host
8
6
 
9
7
 
10
8
  def search_for_files_of_interest(path_obj: PathExtended):
@@ -4,7 +4,6 @@
4
4
  # from machineconfig.utils.scheduling import PathExtended, Report, DEFAULT_CONFIG, read_task_from_dir, main
5
5
 
6
6
  # def main_parse():
7
- # import argparse
8
7
  # print("\n" + "=" * 50)
9
8
  # print("📅 Welcome to the Scheduler CLI")
10
9
  # print("=" * 50 + "\n")
@@ -0,0 +1,41 @@
1
+
2
+
3
+ from pathlib import Path
4
+ from typing import Optional
5
+ # import typer
6
+
7
+
8
+ """
9
+ reference:
10
+ # https://github.com/tsl0922/ttyd/wiki/Serving-web-fonts
11
+ # -t "fontFamily=CaskaydiaCove" bash
12
+ # --terminal-type xterm-kitty
13
+
14
+ """
15
+
16
+
17
+ def share_terminal(port: int, password: Optional[str]) -> None:
18
+ if password is None:
19
+ pwd_path = Path.home().joinpath("dotfiles/creds/passwords/quick_password")
20
+ if pwd_path.exists():
21
+ password = pwd_path.read_text(encoding="utf-8").strip()
22
+ else:
23
+ raise ValueError("Password not provided and default password file does not exist.")
24
+
25
+ import socket
26
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
27
+ s.connect(('8.8.8.8',80))
28
+ local_ip_v4 = s.getsockname()[0]
29
+ s.close()
30
+
31
+ print(f"\n🌐 Access your terminal at: http://{local_ip_v4}:{port}\n")
32
+
33
+ code = f"""
34
+ #!/bin/bash
35
+ uv run --python 3.13 --with machineconfig install -ttyd
36
+
37
+ ttyd --writable -t enableSixel=true --port {port} --credential "$USER:{password}" -t 'theme={"background": "black"}' bash
38
+
39
+ """
40
+ import subprocess
41
+ subprocess.run(code, shell=True, check=True)
@@ -6,6 +6,8 @@ from machineconfig.utils.source_of_truth import CONFIG_PATH
6
6
  from machineconfig.utils.code import print_code
7
7
  from machineconfig.utils.path_extended import PathExtended as PathExtended
8
8
  from machineconfig.utils.terminal import Terminal
9
+ from typing import Annotated, Optional
10
+ import typer
9
11
  import subprocess
10
12
  import platform
11
13
 
@@ -47,28 +49,24 @@ def jupyter_to_markdown(file: PathExtended):
47
49
  return op_dir
48
50
 
49
51
 
50
- def main() -> None:
51
- import argparse
52
-
52
+ def main(
53
+ directory: Annotated[Optional[str], typer.Option("-d", "--directory", help="📁 Directory of the report.")] = None,
54
+ jupyter_file: Annotated[Optional[str], typer.Option("-j", "--jupyter-file", help="📓 Jupyter notebook file to convert to slides. If not provided, slides.md is used.")] = None,
55
+ ) -> None:
53
56
  print("\n" + "=" * 50)
54
57
  print("🎥 Welcome to the Slidev Presentation Tool")
55
58
  print("=" * 50 + "\n")
56
59
 
57
- parser = argparse.ArgumentParser()
58
- parser.add_argument("-d", "--directory", default=None, help="📁 Directory of the report.")
59
- parser.add_argument("-j", "--jupyter-file", default=None, help="📓 Jupyter notebook file to convert to slides. If not provided, slides.md is used.")
60
- args = parser.parse_args()
61
-
62
60
  port = PORT_DEFAULT
63
61
 
64
- if args.jupyter_file is not None:
62
+ if jupyter_file is not None:
65
63
  print("📓 Jupyter file provided. Converting to markdown...")
66
- report_dir = jupyter_to_markdown(PathExtended(args.jupyter_file))
64
+ report_dir = jupyter_to_markdown(PathExtended(jupyter_file))
67
65
  else:
68
- if args.directory is None:
66
+ if directory is None:
69
67
  report_dir = PathExtended.cwd()
70
68
  else:
71
- report_dir = PathExtended(args.directory)
69
+ report_dir = PathExtended(directory)
72
70
 
73
71
  assert report_dir.exists(), f"❌ Directory {report_dir} does not exist."
74
72
  assert report_dir.is_dir(), f"❌ {report_dir} is not a directory."
@@ -108,5 +106,9 @@ def main() -> None:
108
106
  print_code(code=program, lexer="bash", desc="Run the following command to start the presentation")
109
107
 
110
108
 
109
+ def arg_parser() -> None:
110
+ typer.run(main)
111
+
112
+
111
113
  if __name__ == "__main__":
112
- main()
114
+ arg_parser()
@@ -3,7 +3,8 @@
3
3
  from machineconfig.utils.options import choose_from_options, get_ssh_hosts
4
4
  import platform
5
5
  from itertools import cycle
6
- from typing import Literal
6
+ from typing import Literal, Optional, Annotated
7
+ import typer
7
8
 
8
9
 
9
10
  COLOR_SCHEMES = ["Campbell", "Campbell Powershell", "Solarized Dark", "Ubuntu-ColorScheme", "Retro"]
@@ -70,40 +71,35 @@ wt --window {window} --title {hosts[0]} powershell -Command "ssh {host_linux} {s
70
71
  return cmd
71
72
 
72
73
 
73
- def main():
74
- import argparse
75
-
74
+ def main(
75
+ panes: Annotated[Optional[int], typer.Option("--panes", "-p", help="🔲 The number of panes to open.")] = 4,
76
+ vertical: Annotated[bool, typer.Option("--vertical", "-V", help="↕️ Switch orientation to vertical from default horizontal.")] = False,
77
+ window: Annotated[int, typer.Option("--window", "-w", help="🪟 The window ID to use.")] = 0,
78
+ hosts: Annotated[Optional[list[str]], typer.Option("--hosts", "-H", help="🌐 The hosts to connect to.")] = None,
79
+ ) -> None:
76
80
  print("\n" + "=" * 50)
77
81
  print("🖥️ Welcome to the Terminal Starter Tool")
78
82
  print("=" * 50 + "\n")
79
83
 
80
- parser = argparse.ArgumentParser()
81
- parser.add_argument("--panes", "-p", type=int, help="🔲 The number of panes to open.", default=4)
82
- parser.add_argument("--vertical", "-V", action="store_true", help="↕️ Switch orientation to vertical from default horizontal.")
83
- parser.add_argument("--window", "-w", type=int, help="🪟 The window ID to use.", default=0) # 0 refers to this window.
84
- parser.add_argument("--hosts", "-H", type=str, nargs="*", help="🌐 The hosts to connect to.", default=None)
85
- args = parser.parse_args()
86
-
87
- if args.panes:
84
+ if panes:
88
85
  print("🔲 Configuring panes...")
89
- cmd = f"wt --window {args.window} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
86
+ cmd = f"wt --window {window} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
90
87
  cmd += f" `; new-tab --colorScheme '{next(THEMES_ITER)}' --profile pwsh --title 't2' --tabColor '#f59218' "
91
88
  cmd += f" `; new-tab --colorScheme '{next(THEMES_ITER)}' --profile pwsh --title 't3' --tabColor '#009999' "
92
- for idx in range(args.panes):
89
+ for idx in range(panes):
93
90
  if idx % 2 == 0:
94
91
  cmd += f" `; move-focus down split-pane --horizontal --size {next(SIZE_ITER)} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
95
92
  else:
96
93
  cmd += f" `; move-focus up split-pane --vertical --size {next(SIZE_ITER)} --colorScheme '{next(THEMES_ITER)}' pwsh -NoExit -Command '{next(INIT_COMMANDS_ITER)}' "
97
94
 
98
95
  else:
99
- if args.hosts is None:
96
+ if hosts is None:
100
97
  print("🌐 No hosts provided. Displaying options...")
101
98
  hosts = choose_from_options(msg="Select hosts:", options=get_ssh_hosts() + [THIS_MACHINE], multi=True, fzf=True)
102
99
  else:
103
- print("🌐 Using provided hosts:", args.hosts)
104
- hosts = args.hosts
100
+ print("🌐 Using provided hosts:", hosts)
105
101
  assert isinstance(hosts, list)
106
- cmd = main_windows_and_wsl(window=args.window, hosts=hosts, orientation="vertical" if args.vertical else "horizontal")
102
+ cmd = main_windows_and_wsl(window=window, hosts=hosts, orientation="vertical" if vertical else "horizontal")
107
103
 
108
104
  print("\n📋 Generated Command:")
109
105
  print("-" * 50)
@@ -117,5 +113,9 @@ def main():
117
113
  print("✅ Command saved successfully!\n")
118
114
 
119
115
 
116
+ def arg_parser() -> None:
117
+ typer.run(main)
118
+
119
+
120
120
  if __name__ == "__main__":
121
- main()
121
+ arg_parser()
@@ -0,0 +1,16 @@
1
+
2
+ import typer
3
+
4
+
5
+ def func(name: str):
6
+ print(f"Hello, {name}! from func")
7
+
8
+ def hello(name: str):
9
+ print(f"Hello, {name}!")
10
+
11
+ def main():
12
+ typer.run(hello)
13
+
14
+ if __name__ == "__main__":
15
+ # typer.run(hello)
16
+ pass
@@ -28,7 +28,8 @@ Usage examples:
28
28
 
29
29
  """
30
30
 
31
- import argparse
31
+ from typing import Annotated
32
+ import typer
32
33
  import configparser
33
34
  from pathlib import Path
34
35
  import os
@@ -262,24 +263,21 @@ def manual_network_selection() -> bool:
262
263
  return False
263
264
 
264
265
 
265
- def main():
266
+ def main(
267
+ ssid: Annotated[str, typer.Option("-n", "--ssid", help="🔗 SSID of WiFi (from config)")] = "MyPhoneHotSpot",
268
+ manual: Annotated[bool, typer.Option("-m", "--manual", help="🔍 Manual network selection mode")] = False,
269
+ list_: Annotated[bool, typer.Option("-l", "--list", help="📡 List available networks only")] = False,
270
+ ) -> None:
266
271
  """Main function with fallback network selection"""
267
272
  console.print(Panel("📶 Welcome to the WiFi Connector Tool", title="[bold blue]WiFi Connection[/bold blue]", border_style="blue"))
268
273
 
269
- parser = argparse.ArgumentParser(description="WiFi Connector")
270
- parser.add_argument("-n", "--ssid", help="🔗 SSID of WiFi (from config)", default="MyPhoneHotSpot")
271
- parser.add_argument("-m", "--manual", action="store_true", help="🔍 Manual network selection mode")
272
- parser.add_argument("-l", "--list", action="store_true", help="📡 List available networks only")
273
-
274
- args = parser.parse_args()
275
-
276
274
  # If user just wants to list networks
277
- if args.list:
275
+ if list_:
278
276
  display_available_networks()
279
277
  return
280
278
 
281
279
  # If user wants manual mode, skip config and go straight to selection
282
- if args.manual:
280
+ if manual:
283
281
  console.print("[blue]🔍 Manual network selection mode[/blue]")
284
282
  if manual_network_selection():
285
283
  console.print("[green]🎉 Successfully connected![/green]")
@@ -288,9 +286,9 @@ def main():
288
286
  return
289
287
 
290
288
  # Try to connect using configuration first
291
- console.print(f"[blue]🔍 Attempting to connect to configured network: {args.ssid}[/blue]")
289
+ console.print(f"[blue]🔍 Attempting to connect to configured network: {ssid}[/blue]")
292
290
 
293
- if try_config_connection(args.ssid):
291
+ if try_config_connection(ssid):
294
292
  console.print("[green]🎉 Successfully connected using configuration![/green]")
295
293
  return
296
294
 
@@ -306,6 +304,10 @@ def main():
306
304
  console.print("[blue]👋 Goodbye![/blue]")
307
305
 
308
306
 
307
+ def arg_parser() -> None:
308
+ typer.run(main)
309
+
310
+
309
311
  def get_current_wifi_name() -> str:
310
312
  """Get the name of the currently connected WiFi network"""
311
313
  console.print("\n[blue]🔍 Checking current WiFi connection...[/blue]")
@@ -413,4 +415,4 @@ def create_new_connection(name: str, ssid: str, password: str):
413
415
 
414
416
 
415
417
  if __name__ == "__main__":
416
- main()
418
+ arg_parser()
@@ -1,7 +1,8 @@
1
1
  """TWSL"""
2
2
 
3
3
  from machineconfig.utils.path_extended import PathExtended as PathExtended
4
- import argparse
4
+ from typing import Annotated, Optional
5
+ import typer
5
6
  import platform
6
7
  import getpass
7
8
  from pathlib import Path
@@ -20,53 +21,46 @@ WSL_FROM_WIN = Path(r"\\wsl.localhost\Ubuntu-22.04\home") # PathExtended(rf"\\w
20
21
  WIN_FROM_WSL = Path(r"/mnt/c/Users")
21
22
 
22
23
 
23
- def main():
24
+ def main(
25
+ path: Annotated[str, typer.Argument(help="📁 Path of file/folder to transfer over.")],
26
+ same_file_system: Annotated[bool, typer.Option("--same_file_system", "-s", help="⚠️ Move file across the same file system (not recommended).")] = False,
27
+ destination: Annotated[str, typer.Option("--destination", "-d", help="📍 New path.")] = "",
28
+ pwd: Annotated[Optional[str], typer.Option("--pwd", "-P", help="🔑 Password for encryption.")] = None,
29
+ sshkey: Annotated[Optional[str], typer.Option("--sshkey", "-i", help="🔐 Path to SSH private key.")] = None,
30
+ port: Annotated[Optional[str], typer.Option("--port", "-p", help="🔌 Port number.")] = None,
31
+ zip_first: Annotated[bool, typer.Option("--zip_first", "-z", help="📦 Zip before transferring.")] = False,
32
+ ) -> None:
24
33
  print("\n" + "=" * 50)
25
34
  print("🔄 Welcome to the WSL-Windows File Transfer Tool")
26
35
  print("=" * 50 + "\n")
27
36
 
28
- parser = argparse.ArgumentParser(
29
- description="""📂 Move and copy files across WSL & Windows.
30
- The direction is automatically determined by sensing the execution environment.
31
- Otherwise, a flag must be raised to indicate the direction."""
32
- )
37
+ path_obj = PathExtended(path).expanduser().absolute()
33
38
 
34
- # positional argument
35
- parser.add_argument("path", help="📁 Path of file/folder to transfer over.")
36
- # FLAGS
37
- # this is dangerous and no gaurantee on no corruption.
38
- parser.add_argument("--same_file_system", "-s", help="⚠️ Move file across the same file system (not recommended).", action="store_true") # default is False
39
- # optional argument
40
- parser.add_argument("--destination", "-d", help="📍 New path.", default="")
41
- parser.add_argument("--pwd", "-P", help="🔑 Password for encryption.", default=None)
42
- parser.add_argument("--sshkey", "-i", help="🔐 Path to SSH private key.", default=None)
43
- parser.add_argument("--port", "-p", help="🔌 Port number.", default=None)
44
- parser.add_argument("--zip_first", "-z", help="📦 Zip before transferring.", action="store_true") # default is False
45
-
46
- args = parser.parse_args()
47
- path = PathExtended(args.path).expanduser().absolute()
48
-
49
- if args.same_file_system:
39
+ if same_file_system:
50
40
  print("⚠️ Using a not recommended transfer method! Copying files across the same file system.")
51
41
  if system == "Windows": # move files over to WSL
52
42
  print("📤 Transferring files from Windows to WSL...")
53
- path.copy(folder=WSL_FROM_WIN.joinpath(UserName).joinpath(path.rel2home().parent), overwrite=True) # the following works for files and folders alike.
43
+ path_obj.copy(folder=WSL_FROM_WIN.joinpath(UserName).joinpath(path_obj.rel2home().parent), overwrite=True) # the following works for files and folders alike.
54
44
  else: # move files from WSL to win
55
45
  print("📤 Transferring files from WSL to Windows...")
56
- path.copy(folder=WIN_FROM_WSL.joinpath(UserName).joinpath(path.rel2home().parent), overwrite=True)
46
+ path_obj.copy(folder=WIN_FROM_WSL.joinpath(UserName).joinpath(path_obj.rel2home().parent), overwrite=True)
57
47
  print("✅ Transfer completed successfully!\n")
58
48
  else:
59
49
  from machineconfig.utils.ssh import SSH
60
50
  import platform
61
51
 
62
- port = int(args.port) if args.port else (2222 if system == "Windows" else 22)
52
+ port_int = int(port) if port else (2222 if system == "Windows" else 22)
63
53
  username = UserName
64
54
  hostname = platform.node()
65
- ssh = SSH(hostname=hostname, username=username, port=port, sshkey=args.sshkey)
55
+ ssh = SSH(hostname=hostname, username=username, port=port_int, sshkey=sshkey)
66
56
  print("🌐 Initiating SSH transfer...")
67
- ssh.copy_from_here(source=path, target=args.destination, z=args.zip_first)
57
+ ssh.copy_from_here(source=path_obj, target=destination, z=zip_first)
68
58
  print("✅ SSH transfer completed successfully!\n")
69
59
 
70
60
 
61
+ def arg_parser() -> None:
62
+ typer.run(main)
63
+
64
+
71
65
  if __name__ == "__main__":
72
- main()
66
+ arg_parser()
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env python
2
2
 
3
3
  from pathlib import Path
4
- from typing import List, Optional, Union
4
+ from typing import List, Optional, Union, Annotated
5
5
  from rich.console import Console
6
6
  from rich.panel import Panel
7
7
 
8
+ import typer
8
9
 
9
10
  def generate_file_checklist(repo_root: Union[str, Path], exclude_dirs: Optional[List[str]] = None) -> Path:
10
11
  actual_exclude_dirs: List[str] = [".venv", ".git", "__pycache__", "build", "dist", "*.egg-info"]
@@ -41,28 +42,27 @@ def generate_file_checklist(repo_root: Union[str, Path], exclude_dirs: Optional[
41
42
 
42
43
  print(f"📋 Checklist generated at: {output_path}")
43
44
  return output_path
44
-
45
-
46
- def main() -> None:
47
- import argparse
48
-
49
- parser = argparse.ArgumentParser(description="Generate a markdown file with checkboxes for all .py and .sh files.")
50
- parser.add_argument("--repo", "-r", type=str, default=str(Path.cwd()), help="Repository root path. Defaults to current working directory.")
51
- parser.add_argument("--exclude", "-e", nargs="+", type=str, help="Additional directories to exclude (by default excludes .venv, .git, __pycache__, build, dist, *.egg-info)")
52
-
53
- args = parser.parse_args()
54
-
45
+ def main(
46
+ repo: Annotated[str, typer.Argument(help="Repository root path. Defaults to current working directory.")] = str(Path.cwd()),
47
+ exclude: Annotated[Optional[List[str]], typer.Option("--exclude", "-e", help="Additional directories to exclude (by default excludes .venv, .git, __pycache__, build, dist, *.egg-info)")] = None,
48
+ ) -> None:
55
49
  exclude_dirs: List[str] = [".venv", ".git", "__pycache__", "build", "dist", "*.egg-info"]
56
- if args.exclude:
57
- exclude_dirs.extend(args.exclude)
58
- if args.repo == "":
50
+ if exclude:
51
+ exclude_dirs.extend(exclude)
52
+ if repo == "":
59
53
  print("Error: Repository path cannot be empty.")
60
54
  return
61
55
 
62
- output_path = generate_file_checklist(args.repo, exclude_dirs)
56
+ output_path = generate_file_checklist(repo, exclude_dirs)
63
57
  console = Console()
64
58
  console.print(Panel(f"✅ SUCCESS | Markdown checklist generated successfully!\n📄 File Location: {output_path}", border_style="bold blue", expand=False))
65
59
 
66
60
 
61
+ def main_from_parser():
62
+ typer.run(main)
63
+
64
+
65
+
66
+
67
67
  if __name__ == "__main__":
68
- main()
68
+ main_from_parser()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: machineconfig
3
- Version: 3.83
3
+ Version: 3.85
4
4
  Summary: Dotfiles management package
5
5
  Author-email: Alex Al-Saffar <programmer@usa.com>
6
6
  License: Apache 2.0