machineconfig 1.8__py3-none-any.whl → 1.91__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.
- machineconfig/__init__.py +4 -2
- machineconfig/jobs/python/check_installations.py +8 -6
- machineconfig/jobs/python/checkout_version.py +27 -32
- machineconfig/jobs/python/create_bootable_media.py +1 -1
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/tasks.py +2 -2
- machineconfig/jobs/python_custom_installers/gh.py +53 -0
- machineconfig/jobs/python_custom_installers/hx.py +55 -0
- machineconfig/profile/create.py +26 -21
- machineconfig/profile/create_hardlinks.py +101 -0
- machineconfig/profile/shell.py +5 -5
- machineconfig/scripts/python/choose_wezterm_theme.py +96 -0
- machineconfig/scripts/python/cloud_copy.py +24 -17
- machineconfig/scripts/python/cloud_mount.py +20 -10
- machineconfig/scripts/python/cloud_repo_sync.py +109 -56
- machineconfig/scripts/python/cloud_sync.py +73 -68
- machineconfig/scripts/python/croshell.py +23 -14
- machineconfig/scripts/python/devops.py +19 -20
- machineconfig/scripts/python/devops_backup_retrieve.py +19 -10
- machineconfig/scripts/python/devops_devapps_install.py +81 -57
- machineconfig/scripts/python/devops_update_repos.py +5 -5
- machineconfig/scripts/python/dotfile.py +4 -4
- machineconfig/scripts/python/fire_jobs.py +139 -66
- machineconfig/scripts/python/ftpx.py +17 -7
- machineconfig/scripts/python/gh_models.py +53 -0
- machineconfig/scripts/python/mount_nfs.py +1 -1
- machineconfig/scripts/python/mount_nw_drive.py +3 -3
- machineconfig/scripts/python/mount_ssh.py +2 -3
- machineconfig/scripts/python/pomodoro.py +1 -1
- machineconfig/scripts/python/repos.py +26 -23
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +10 -4
- machineconfig/scripts/python/start_terminals.py +6 -5
- machineconfig/scripts/python/wifi_conn.py +34 -42
- machineconfig/scripts/python/wsl_windows_transfer.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +3 -2
- machineconfig/utils/installer.py +167 -60
- machineconfig/utils/procs.py +2 -2
- machineconfig/utils/scheduling.py +3 -3
- machineconfig/utils/utils.py +137 -56
- machineconfig/utils/ve.py +171 -100
- machineconfig-1.91.dist-info/LICENSE +201 -0
- {machineconfig-1.8.dist-info → machineconfig-1.91.dist-info}/METADATA +31 -11
- machineconfig-1.91.dist-info/RECORD +69 -0
- {machineconfig-1.8.dist-info → machineconfig-1.91.dist-info}/WHEEL +1 -1
- machineconfig/jobs/script_installer/azure_data_studio.py +0 -22
- machineconfig/jobs/script_installer/bypass_paywall.py +0 -23
- machineconfig/jobs/script_installer/code.py +0 -34
- machineconfig/jobs/script_installer/docker_desktop.py +0 -41
- machineconfig/jobs/script_installer/ngrok.py +0 -29
- machineconfig/jobs/script_installer/skim.py +0 -21
- machineconfig/jobs/script_installer/wezterm.py +0 -34
- machineconfig-1.8.dist-info/RECORD +0 -70
- /machineconfig/jobs/{script_installer → python_custom_installers}/__init__.py +0 -0
- {machineconfig-1.8.dist-info → machineconfig-1.91.dist-info}/top_level.txt +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
"""
|
|
3
3
|
fire
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
4
|
|
|
7
|
-
from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
8
|
-
# from crocodile.run import *
|
|
9
5
|
# https://github.com/pallets/click combine with fire. Consider
|
|
10
6
|
# https://github.com/ceccopierangiolieugenio/pyTermTk for display_options build TUI
|
|
11
7
|
# https://github.com/chriskiehl/Gooey build commandline interface
|
|
12
|
-
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
from machineconfig.utils.utils import display_options, choose_one_option, PROGRAM_PATH, choose_ssh_host, match_file_name, sanitize_path
|
|
13
|
+
from crocodile.file_management import P, install_n_import, Read
|
|
13
14
|
from crocodile.core import Display, randstr
|
|
14
15
|
import inspect
|
|
15
16
|
import platform
|
|
@@ -18,49 +19,64 @@ from typing import Callable, Any, Optional
|
|
|
18
19
|
import argparse
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
def search_for_files_of_interest(path_obj: P):
|
|
23
|
+
if path_obj.joinpath(".venv").exists():
|
|
24
|
+
path_objects = path_obj.search("*", not_in=[".venv"]).list
|
|
25
|
+
files: list[P] = []
|
|
26
|
+
for a_path_obj in path_objects:
|
|
27
|
+
files += search_for_files_of_interest(path_obj=a_path_obj)
|
|
28
|
+
return files
|
|
29
|
+
py_files = path_obj.search(pattern="*.py", not_in=["__init__.py"], r=True).list
|
|
30
|
+
ps_files = path_obj.search(pattern="*.ps1", r=True).list
|
|
31
|
+
sh_files = path_obj.search(pattern="*.sh", r=True).list
|
|
32
|
+
files = py_files + ps_files + sh_files
|
|
33
|
+
return files
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
str2obj = {"True": True, "False": False, "None": None}
|
|
37
|
+
|
|
38
|
+
|
|
21
39
|
def main() -> None:
|
|
22
40
|
parser = argparse.ArgumentParser()
|
|
23
|
-
parser.add_argument("path",
|
|
41
|
+
parser.add_argument("path", nargs='?', type=str, help="The directory containing the jobs", default=".")
|
|
24
42
|
parser.add_argument("function", nargs='?', type=str, help="Fuction to run", default=None)
|
|
25
43
|
# parser.add_argument("--function", "-f", type=str, help="The function to run", default="")
|
|
26
|
-
parser.add_argument("--ve",
|
|
27
|
-
parser.add_argument("--cmd",
|
|
28
|
-
parser.add_argument("--interactive",
|
|
29
|
-
parser.add_argument("--debug",
|
|
44
|
+
parser.add_argument("--ve", "-v", type=str, help="virtual enviroment name", default="")
|
|
45
|
+
parser.add_argument("--cmd", "-B", action="store_true", help="Create a cmd fire command to launch the the job asynchronously.")
|
|
46
|
+
parser.add_argument("--interactive", "-i", action="store_true", help="Whether to run the job interactively using IPython")
|
|
47
|
+
parser.add_argument("--debug", "-d", action="store_true", help="debug")
|
|
30
48
|
parser.add_argument("--choose_function", "-c", action="store_true", help="debug")
|
|
31
|
-
parser.add_argument("--loop",
|
|
32
|
-
parser.add_argument("--jupyter",
|
|
49
|
+
parser.add_argument("--loop", "-l", action="store_true", help="infinite recusion (runs again after completion)")
|
|
50
|
+
parser.add_argument("--jupyter", "-j", action="store_true", help="open in a jupyter notebook")
|
|
33
51
|
parser.add_argument("--submit_to_cloud", "-C", action="store_true", help="submit to cloud compute")
|
|
34
|
-
parser.add_argument("--remote",
|
|
35
|
-
parser.add_argument("--module",
|
|
36
|
-
parser.add_argument("--streamlit",
|
|
37
|
-
parser.add_argument("--history",
|
|
52
|
+
parser.add_argument("--remote", "-r", action="store_true", help="launch on a remote machine")
|
|
53
|
+
parser.add_argument("--module", "-m", action="store_true", help="launch the main file")
|
|
54
|
+
parser.add_argument("--streamlit", "-S", action="store_true", help="run as streamlit app")
|
|
55
|
+
parser.add_argument("--history", "-H", action="store_true", help="choose from history")
|
|
56
|
+
# parser.add_argument("--git_pull", "-g", action="store_true", help="Start by pulling the git repo")
|
|
57
|
+
parser.add_argument("--optimized", "-O", action="store_true", help="Run the optimized version of the function")
|
|
58
|
+
parser.add_argument("--Nprocess", "-p", type=int, help="Number of processes to use", default=1)
|
|
38
59
|
parser.add_argument("--kw", nargs="*", default=None, help="keyword arguments to pass to the function in the form of k1 v1 k2 v2 ...")
|
|
39
60
|
|
|
40
61
|
args = parser.parse_args()
|
|
41
62
|
if args.kw is not None:
|
|
42
63
|
assert len(args.kw) % 2 == 0, f"args.kw must be a list of even length. Got {len(args.kw)}"
|
|
43
64
|
kwargs = dict(zip(args.kw[::2], args.kw[1::2]))
|
|
65
|
+
for key, value in kwargs.items():
|
|
66
|
+
if value in str2obj:
|
|
67
|
+
kwargs[key] = str2obj[value]
|
|
44
68
|
# print(f"kwargs = {kwargs}")
|
|
45
69
|
else:
|
|
46
70
|
kwargs = {}
|
|
47
71
|
|
|
48
72
|
path_obj = sanitize_path(P(args.path))
|
|
49
73
|
if not path_obj.exists():
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
print(path_obj)
|
|
53
|
-
else:
|
|
54
|
-
print("This directory")
|
|
55
|
-
print(path_obj)
|
|
74
|
+
path_obj = match_file_name(sub_string=args.path)
|
|
75
|
+
else: pass
|
|
56
76
|
|
|
57
77
|
if path_obj.is_dir():
|
|
58
78
|
print(f"Seaching recursively for all python file in directory `{path_obj}`")
|
|
59
|
-
|
|
60
|
-
ps_files = path_obj.search(pattern="*.ps1", r=True).list
|
|
61
|
-
sh_files = path_obj.search(pattern="*.sh", r=True).list
|
|
62
|
-
files = py_files + ps_files + sh_files
|
|
63
|
-
|
|
79
|
+
files = search_for_files_of_interest(path_obj)
|
|
64
80
|
choice_file = choose_one_option(options=files, fzf=True)
|
|
65
81
|
choice_file = P(choice_file)
|
|
66
82
|
else:
|
|
@@ -68,10 +84,9 @@ def main() -> None:
|
|
|
68
84
|
|
|
69
85
|
if choice_file.suffix in [".ps1", ".sh"]:
|
|
70
86
|
PROGRAM_PATH.write_text(f". {choice_file}")
|
|
71
|
-
return
|
|
87
|
+
return None
|
|
72
88
|
|
|
73
89
|
if args.choose_function or args.submit_to_cloud:
|
|
74
|
-
|
|
75
90
|
options, func_args = parse_pyfile(file_path=str(choice_file))
|
|
76
91
|
choice_function_tmp = display_options(msg="Choose a function to run", options=options, fzf=True, multi=False)
|
|
77
92
|
assert isinstance(choice_function_tmp, str), f"choice_function must be a string. Got {type(choice_function_tmp)}"
|
|
@@ -83,13 +98,28 @@ def main() -> None:
|
|
|
83
98
|
if len(choice_function_args) > 0 and len(kwargs) == 0:
|
|
84
99
|
for item in choice_function_args:
|
|
85
100
|
kwargs[item.name] = input(f"Please enter a value for argument `{item.name}` (type = {item.type}) (default = {item.default}) : ") or item.default
|
|
86
|
-
else:
|
|
101
|
+
else:
|
|
102
|
+
choice_function = args.function
|
|
87
103
|
|
|
88
104
|
if args.ve == "":
|
|
89
105
|
from machineconfig.utils.ve import get_ve_profile # if file name is passed explicitly, then, user probably launched it from cwd different to repo root, so activate_ve can't infer ve from .ve_path, so we attempt to do that manually here
|
|
90
106
|
args.ve = get_ve_profile(choice_file)
|
|
91
107
|
|
|
92
|
-
if args.streamlit:
|
|
108
|
+
if args.streamlit:
|
|
109
|
+
from crocodile.environment import get_network_addresses
|
|
110
|
+
local_ip_v4 = get_network_addresses()["local_ip_v4"]
|
|
111
|
+
computer_name = platform.node()
|
|
112
|
+
port = 8501
|
|
113
|
+
if choice_file.parent.joinpath(".streamlit/config.toml").exists():
|
|
114
|
+
config = Read.toml(choice_file.parent.joinpath(".streamlit/config.toml"))
|
|
115
|
+
if "server" in config:
|
|
116
|
+
if "port" in config["server"]:
|
|
117
|
+
port = config["server"]["port"]
|
|
118
|
+
message = f"🚀 Streamlit app is running @:\n1- http://{local_ip_v4}:{port}\n2- http://{computer_name}:{port}\n3- http://localhost:{port}"
|
|
119
|
+
from rich.panel import Panel
|
|
120
|
+
from rich import print as rprint
|
|
121
|
+
rprint(Panel(message))
|
|
122
|
+
exe = "streamlit run --server.address 0.0.0.0 --server.headless true"
|
|
93
123
|
elif args.interactive is False: exe = "python"
|
|
94
124
|
elif args.jupyter: exe = "jupyter-lab"
|
|
95
125
|
else:
|
|
@@ -97,12 +127,13 @@ def main() -> None:
|
|
|
97
127
|
exe = f"ipython -i --no-banner --profile {get_ipython_profile(choice_file)} "
|
|
98
128
|
|
|
99
129
|
if args.module or (args.debug and args.choose_function): # because debugging tools do not support choosing functions and don't interplay with fire module. So the only way to have debugging and choose function options is to import the file as a module into a new script and run the function of interest there and debug the new script.
|
|
100
|
-
|
|
130
|
+
import_line = get_import_module_code(str(choice_file))
|
|
131
|
+
txt: str=f"""
|
|
101
132
|
try:
|
|
102
|
-
{
|
|
133
|
+
{import_line}
|
|
103
134
|
except (ImportError, ModuleNotFoundError) as ex:
|
|
104
|
-
print(fr"Failed to import {choice_file} the proper way. {{ex}} ")
|
|
105
|
-
print(fr"
|
|
135
|
+
print(fr"Failed to import `{choice_file}` the proper way. {{ex}} ")
|
|
136
|
+
print(fr"Importing with an ad-hoc `$PATH` manipulation. DO NOT pickle any files in this session as there is no gaurantee of correct deserialization.")
|
|
106
137
|
import sys
|
|
107
138
|
sys.path.append(r'{P(choice_file).parent}')
|
|
108
139
|
from {P(choice_file).stem} import *
|
|
@@ -110,11 +141,17 @@ except (ImportError, ModuleNotFoundError) as ex:
|
|
|
110
141
|
"""
|
|
111
142
|
if choice_function is not None:
|
|
112
143
|
txt = txt + f"""
|
|
113
|
-
{choice_function}({('**' + str(kwargs)) if kwargs else ''})
|
|
144
|
+
res = {choice_function}({('**' + str(kwargs)) if kwargs else ''})
|
|
114
145
|
"""
|
|
115
146
|
txt = f"""
|
|
116
|
-
|
|
117
|
-
|
|
147
|
+
try:
|
|
148
|
+
from rich.panel import Panel
|
|
149
|
+
from rich.console import Console
|
|
150
|
+
from rich.syntax import Syntax
|
|
151
|
+
console = Console()
|
|
152
|
+
console.print(Panel(Syntax(code=r'''{txt}''', lexer='python'), title='Import Script'), style="bold red")
|
|
153
|
+
except ImportError as _ex:
|
|
154
|
+
print(r'''{txt}''')
|
|
118
155
|
""" + txt
|
|
119
156
|
choice_file = P.tmp().joinpath(f'tmp_scripts/python/{P(choice_file).parent.name}_{P(choice_file).stem}_{randstr()}.py').create(parents_only=True).write_text(txt)
|
|
120
157
|
|
|
@@ -131,15 +168,19 @@ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
|
131
168
|
if not kwargs: # empty dict
|
|
132
169
|
kwargs_str = ''
|
|
133
170
|
else:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
171
|
+
if len(kwargs) == 1:
|
|
172
|
+
kwargs_str = f""" --{list(kwargs.keys())[0]} {list(kwargs.values())[0]} """
|
|
173
|
+
else:
|
|
174
|
+
# print(f"len(kwargs) = {len(kwargs)}")
|
|
175
|
+
tmp_list: list[str] = []
|
|
176
|
+
for k, v in kwargs.items():
|
|
177
|
+
if v is not None:
|
|
178
|
+
item = f'"{k}": "{v}"'
|
|
179
|
+
else:
|
|
180
|
+
item = f'"{k}": None'
|
|
181
|
+
tmp_list.append(item)
|
|
182
|
+
tmp__ = ", ".join(tmp_list)
|
|
183
|
+
kwargs_str = "'{" + tmp__ + "}'"
|
|
143
184
|
command = f"{exe} -m fire {choice_file} {choice_function} {kwargs_str}"
|
|
144
185
|
# else:
|
|
145
186
|
# print(f"{kwargs=}")
|
|
@@ -152,19 +193,22 @@ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
|
152
193
|
else:
|
|
153
194
|
if not args.cmd:
|
|
154
195
|
# for .streamlit config to work, it needs to be in the current directory.
|
|
155
|
-
command = f"cd {choice_file.parent}
|
|
196
|
+
command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
|
|
156
197
|
else:
|
|
157
198
|
command = rf""" cd /d {choice_file.parent} & {exe} {choice_file.name} """
|
|
158
|
-
# command = f"cd {choice_file.parent}
|
|
199
|
+
# command = f"cd {choice_file.parent}\n\n{exe} {choice_file.name}\n\ncd {P.cwd()}"
|
|
159
200
|
|
|
160
201
|
# this installs in ve env, which is not execution env
|
|
161
202
|
# if "ipdb" in command: install_n_import("ipdb")
|
|
162
203
|
# if "pudb" in command: install_n_import("pudb")
|
|
163
204
|
|
|
164
205
|
if not args.cmd:
|
|
165
|
-
if "ipdb" in command: command = f"pip install ipdb
|
|
166
|
-
if "pudb" in command: command = f"pip install pudb
|
|
167
|
-
|
|
206
|
+
if "ipdb" in command: command = f"pip install ipdb\n\n{command}"
|
|
207
|
+
if "pudb" in command: command = f"pip install pudb\n\n{command}"
|
|
208
|
+
if platform.system() == "Windows":
|
|
209
|
+
command = f". $HOME/scripts/activate_ve {args.ve}\n\n{command}"
|
|
210
|
+
else:
|
|
211
|
+
command = f". $HOME/scripts/activate_ve {args.ve}\n\n{command}"
|
|
168
212
|
else:
|
|
169
213
|
# CMD equivalent
|
|
170
214
|
if "ipdb" in command: command = f"pip install ipdb & {command}"
|
|
@@ -174,19 +218,40 @@ print_code(code=r'''{txt}''', lexer='python', desc='Import Script')
|
|
|
174
218
|
|
|
175
219
|
if args.submit_to_cloud:
|
|
176
220
|
command = f"""
|
|
177
|
-
. activate_ve {args.ve}
|
|
221
|
+
. $HOME/scripts/activate_ve {args.ve}
|
|
178
222
|
python -m crocodile.cluster.templates.cli_click --file {choice_file} """
|
|
179
223
|
if choice_function is not None: command += f"--function {choice_function} "
|
|
180
224
|
try: install_n_import("clipboard").copy(command)
|
|
181
225
|
except Exception as ex: print(f"Failed to copy command to clipboard. {ex}")
|
|
182
226
|
|
|
183
227
|
if args.loop:
|
|
184
|
-
command = command +
|
|
228
|
+
command = command + "\n" + f". {PROGRAM_PATH}"
|
|
229
|
+
|
|
230
|
+
if args.Nprocess > 1:
|
|
231
|
+
lines = [f""" zellij action new-tab --name nProcess{randstr(2)}"""]
|
|
232
|
+
command = command.replace(". activate_ve", ". $HOME/scripts/activate_ve")
|
|
233
|
+
for an_arg in range(args.Nprocess):
|
|
234
|
+
sub_command = f"{command} --idx={an_arg} --idx_max={args.Nprocess}"
|
|
235
|
+
if args.optimized:
|
|
236
|
+
sub_command = sub_command.replace("python ", "python -OO ")
|
|
237
|
+
sub_command_path = P.tmpfile(suffix=".sh").write_text(sub_command)
|
|
238
|
+
lines.append(f"""zellij action new-pane -- bash {sub_command_path} """)
|
|
239
|
+
lines.append("sleep 1") # python tends to freeze if you launch instances within 1 microsecond of each other
|
|
240
|
+
command = "\n".join(lines)
|
|
185
241
|
|
|
186
242
|
# TODO: send this command to terminal history. In powershell & bash there is no way to do it with a command other than goiing to history file. In Mcfly there is a way but its linux only tool. # if platform.system() == "Windows": command = f" ({command}) | Add-History -PassThru "
|
|
187
|
-
|
|
243
|
+
# mcfly add --exit 0 command
|
|
244
|
+
if args.optimized:
|
|
245
|
+
# note that in ipython, optimization is meaningless.
|
|
246
|
+
command = command.replace("python ", "python -OO ")
|
|
188
247
|
# if platform.system() == "Linux":
|
|
189
248
|
# command = "timeout 1s aafire -driver slang\nclear\n" + command
|
|
249
|
+
|
|
250
|
+
from rich.panel import Panel
|
|
251
|
+
from rich.console import Console
|
|
252
|
+
from rich.syntax import Syntax
|
|
253
|
+
console = Console()
|
|
254
|
+
console.print(Panel(Syntax(command, lexer="shell"), title=f"🔥 fire command @ {PROGRAM_PATH}: "), style="bold red")
|
|
190
255
|
PROGRAM_PATH.write_text(command)
|
|
191
256
|
|
|
192
257
|
|
|
@@ -235,11 +300,11 @@ def parse_pyfile(file_path: str):
|
|
|
235
300
|
return options, func_args
|
|
236
301
|
|
|
237
302
|
|
|
238
|
-
def
|
|
303
|
+
def get_attrs_recursively(obj: Any):
|
|
239
304
|
if hasattr(obj, '__dict__'):
|
|
240
305
|
res = {}
|
|
241
306
|
for k, v in obj.__dict__.items():
|
|
242
|
-
res[k] =
|
|
307
|
+
res[k] = get_attrs_recursively(v)
|
|
243
308
|
return res
|
|
244
309
|
return obj
|
|
245
310
|
|
|
@@ -258,7 +323,8 @@ def interactively_run_function(func: Callable[[Any], Any]):
|
|
|
258
323
|
if value == "": value = default
|
|
259
324
|
else: value = input(f"Please enter a value for argument `{param.name}` (type = {hint}) : ")
|
|
260
325
|
try:
|
|
261
|
-
if param.annotation is not inspect.Parameter.empty:
|
|
326
|
+
if param.annotation is not inspect.Parameter.empty:
|
|
327
|
+
value = param.annotation
|
|
262
328
|
except (TypeError, ValueError) as err:
|
|
263
329
|
raise ValueError(f"Invalid input: {value} is not of type {param.annotation}") from err
|
|
264
330
|
if param.kind == inspect.Parameter.KEYWORD_ONLY: kwargs[param.name] = value
|
|
@@ -281,25 +347,32 @@ def run_on_remote(func_file: str, args: argparse.Namespace):
|
|
|
281
347
|
m.run()
|
|
282
348
|
|
|
283
349
|
|
|
284
|
-
def
|
|
350
|
+
def find_repo_root_path(start_path: str) -> Optional[str]:
|
|
285
351
|
root_files = ['setup.py', 'pyproject.toml', '.git']
|
|
286
|
-
path =
|
|
287
|
-
|
|
352
|
+
path: str=start_path
|
|
353
|
+
trials = 0
|
|
354
|
+
root_path = os.path.abspath(os.sep)
|
|
355
|
+
while path != root_path and trials < 20:
|
|
288
356
|
for root_file in root_files:
|
|
289
357
|
if os.path.exists(os.path.join(path, root_file)):
|
|
358
|
+
print(f"Found repo root path: {path}")
|
|
290
359
|
return path
|
|
291
360
|
path = os.path.dirname(path)
|
|
361
|
+
trials += 1
|
|
292
362
|
return None
|
|
293
363
|
|
|
294
364
|
|
|
295
365
|
def get_import_module_code(module_path: str):
|
|
296
|
-
root_path =
|
|
366
|
+
root_path = find_repo_root_path(module_path)
|
|
297
367
|
if root_path is None: # just make a desperate attempt to import it
|
|
298
368
|
module_name = module_path.lstrip(os.sep).replace(os.sep, '.').replace('.py', '')
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
369
|
+
else:
|
|
370
|
+
relative_path = module_path.replace(root_path, '')
|
|
371
|
+
module_name = relative_path.lstrip(os.sep).replace(os.sep, '.').replace('.py', '')
|
|
372
|
+
module_name = module_name.replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("myresources.", "").replace("resources.", "").replace("source.", "").replace("src.", "").replace("resources.", "").replace("source.", "")
|
|
373
|
+
if any(char in module_name for char in "- :/\\"):
|
|
374
|
+
module_name = "IncorrectModuleName"
|
|
375
|
+
# TODO: use py_compile to check if the statement is valid code to avoid syntax errors that can't be caught.
|
|
303
376
|
return f"from {module_name} import *"
|
|
304
377
|
|
|
305
378
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
TODO: add support for cases in which source or target has non 22 default port number and is defineda as user@host:port:path which makes 2 colons in the string.
|
|
5
5
|
Currently, the only way to work around this is to predifine the host in ~/.ssh/config and use the alias in the source or target which is inconvenient when dealing with newly setup machines.
|
|
6
|
+
|
|
6
7
|
"""
|
|
7
8
|
|
|
8
9
|
import argparse
|
|
@@ -19,6 +20,7 @@ def main():
|
|
|
19
20
|
# FLAGS
|
|
20
21
|
parser.add_argument("--recursive", "-r", help="Send recursively.", action="store_true") # default is False
|
|
21
22
|
parser.add_argument("--zipFirst", "-z", help="Zip before sending.", action="store_true") # default is False
|
|
23
|
+
parser.add_argument("--cloud", "-c", help="Transfer through the cloud.", action="store_true") # default is False
|
|
22
24
|
|
|
23
25
|
args = parser.parse_args()
|
|
24
26
|
|
|
@@ -54,6 +56,7 @@ def main():
|
|
|
54
56
|
raise ValueError("Either source or target must be a remote path (i.e. machine:path)")
|
|
55
57
|
|
|
56
58
|
Struct({"source": str(source), "target": str(target), "machine": machine}).print(as_config=True, title="CLI Resolution")
|
|
59
|
+
|
|
57
60
|
from paramiko.ssh_exception import AuthenticationException # type: ignore
|
|
58
61
|
try:
|
|
59
62
|
ssh = SSH(rf'{machine}')
|
|
@@ -64,14 +67,21 @@ def main():
|
|
|
64
67
|
pwd = getpass.getpass()
|
|
65
68
|
ssh = SSH(rf'{machine}', pwd=pwd)
|
|
66
69
|
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
if args.cloud:
|
|
71
|
+
print("Uploading from remote to cloud ...")
|
|
72
|
+
ssh.run(f"cloud_copy {source} :^", desc="Uploading from remote to the cloud.").print()
|
|
73
|
+
print("Downloading from cloud to local ...")
|
|
74
|
+
ssh.run_locally(f"cloud_copy :^ {target}").print()
|
|
75
|
+
received_file = P(target) # type: ignore
|
|
71
76
|
else:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
if source_is_remote:
|
|
78
|
+
assert source is not None, "source must be a remote path (i.e. machine:path)"
|
|
79
|
+
print(f"Running: received_file = ssh.copy_to_here(source=r'{source}', target=r'{target}', z={args.zipFirst}, r={args.recursive})")
|
|
80
|
+
received_file = ssh.copy_to_here(source=source, target=target, z=args.zipFirst, r=args.recursive)
|
|
81
|
+
else:
|
|
82
|
+
assert source is not None, "target must be a remote path (i.e. machine:path)"
|
|
83
|
+
print(f"Running: received_file = ssh.copy_from_here(source=r'{source}', target=r'{target}', z={args.zipFirst}, r={args.recursive})")
|
|
84
|
+
received_file = ssh.copy_from_here(source=source, target=target, z=args.zipFirst, r=args.recursive)
|
|
75
85
|
# ssh.print_summary()
|
|
76
86
|
# if P(args.file).is_dir(): print(f"Use: cd {repr(P(args.file).expanduser())}")
|
|
77
87
|
if source_is_remote and isinstance(received_file, P):
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
# as per https://github.com/marketplace/models/azure-openai/o1-preview
|
|
3
|
+
from openai import OpenAI
|
|
4
|
+
from crocodile.file_management import Read, P
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
gh_token = Read.ini(P.home().joinpath("dotfiles/creds/git/git_host_tokens.ini"))['thisismygitrepo']['newLongterm']
|
|
8
|
+
endpoint = "https://models.inference.ai.azure.com"
|
|
9
|
+
model_name_preferences = ["o1-preview", "o1-mini", "GPT-4o", "GPT-4-o-mini"]
|
|
10
|
+
client__ = OpenAI(
|
|
11
|
+
base_url=endpoint,
|
|
12
|
+
api_key=gh_token,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def get_response(client, model_name, messages):
|
|
16
|
+
try:
|
|
17
|
+
response = client.chat.completions.create(
|
|
18
|
+
messages=messages,
|
|
19
|
+
model=model_name
|
|
20
|
+
)
|
|
21
|
+
return response.choices
|
|
22
|
+
except Exception as e:
|
|
23
|
+
print(f"Error with model {model_name}: {e}")
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def interactive_chat():
|
|
28
|
+
conversation_history = []
|
|
29
|
+
model_index = 0
|
|
30
|
+
model_name = model_name_preferences[model_index]
|
|
31
|
+
while True:
|
|
32
|
+
print(f"Using model {model_name}".center(80, "="))
|
|
33
|
+
while True:
|
|
34
|
+
user_input = input("You: ")
|
|
35
|
+
conversation_history.append({"role": "user", "content": user_input})
|
|
36
|
+
|
|
37
|
+
while True:
|
|
38
|
+
choices = get_response(client__, model_name, conversation_history)
|
|
39
|
+
if choices is None:
|
|
40
|
+
model_index += 1
|
|
41
|
+
model_name = model_name_preferences[model_index % len(model_name_preferences)]
|
|
42
|
+
print(f"Switching to model {model_name}".center(80, "="))
|
|
43
|
+
continue
|
|
44
|
+
else:
|
|
45
|
+
break
|
|
46
|
+
|
|
47
|
+
for a_choice in choices:
|
|
48
|
+
response_content = a_choice.message.content
|
|
49
|
+
print("\n" * 5)
|
|
50
|
+
print(f"AI: {response_content}")
|
|
51
|
+
conversation_history.append({"role": "assistant", "content": response_content})
|
|
52
|
+
|
|
53
|
+
interactive_chat()
|
|
@@ -11,7 +11,7 @@ import platform
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def main():
|
|
14
|
-
print(
|
|
14
|
+
print("Mounting NFS Share ... ")
|
|
15
15
|
share_info = input("share path? (e.g. machine:~/data/share_nfs) [press enter for interactive choice] = ")
|
|
16
16
|
if share_info == "":
|
|
17
17
|
tmp = choose_ssh_host(multi=False)
|
|
@@ -6,15 +6,15 @@ import platform
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
def main():
|
|
9
|
-
print(
|
|
9
|
+
print("Welcome to the WindowsNetworkDrive Mounting Wizard")
|
|
10
10
|
drive_location = input("Enter the network drive location (ex: //192.168.1.100/Share): ")
|
|
11
11
|
machine_name = drive_location.split("//")[1].split("/")[0]
|
|
12
12
|
mount_point = input(f"Enter the mount point directory (ex: /mnt/network) [default: ~/data/mount_nw/{machine_name}]: ")
|
|
13
13
|
if mount_point == "": mount_point = P.home().joinpath(fr"data/mount_nw/{machine_name}")
|
|
14
14
|
else: mount_point = P(mount_point).expanduser()
|
|
15
15
|
|
|
16
|
-
username = input(
|
|
17
|
-
password = input(
|
|
16
|
+
username = input("Enter the username: ")
|
|
17
|
+
password = input("Enter the password: ")
|
|
18
18
|
if platform.system() == "Linux":
|
|
19
19
|
PROGRAM_PATH.write_text(f"""
|
|
20
20
|
drive_location='{drive_location}'
|
|
@@ -11,8 +11,7 @@ from machineconfig.utils.utils import PROGRAM_PATH, choose_ssh_host
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def main():
|
|
14
|
-
|
|
15
|
-
print(f"Mounting SSHFS ... ")
|
|
14
|
+
print("Mounting SSHFS ... ")
|
|
16
15
|
share_info = input("share path? (e.g. user@host:/path) [press enter for interactive choice] = ")
|
|
17
16
|
if share_info == "":
|
|
18
17
|
tmp = choose_ssh_host(multi=False)
|
|
@@ -28,7 +27,7 @@ def main():
|
|
|
28
27
|
if mount_point == "": mount_point = P.home().joinpath(fr"data/mount_ssh/{ssh.hostname}")
|
|
29
28
|
|
|
30
29
|
if system() == "Linux":
|
|
31
|
-
txt =
|
|
30
|
+
txt = """
|
|
32
31
|
sshfs alex@:/media/dbhdd /media/dbhdd\
|
|
33
32
|
"""
|
|
34
33
|
elif system() == "Windows":
|
|
@@ -16,7 +16,7 @@ def pomodoro(work: int = 25, rest: int = 5, repeats: int = 4):
|
|
|
16
16
|
while (diff := rest - ((datetime.now() - start).seconds / 60)) > 0: logger.critical(f"Keep Resting. Time Left: {round(diff)} minutes"); time.sleep(60 * 1)
|
|
17
17
|
def speak(txt: str):
|
|
18
18
|
install_n_import("gtts").gTTS(txt, lang='en', tld='com.au').save(tmp := P.tmpfile(suffix=".mp3")); time.sleep(0.5)
|
|
19
|
-
pyglet = install_n_import("pyglet"); pyglet.resource.path = [tmp.parent.
|
|
19
|
+
pyglet = install_n_import("pyglet"); pyglet.resource.path = [tmp.parent.to_str()]; pyglet.resource.reindex(); pyglet.resource.media(tmp.name).play()
|
|
20
20
|
def beep(duration: int = 1, frequency: int = 3000):
|
|
21
21
|
try: import winsound
|
|
22
22
|
except ImportError: __import__("os").system(f'beep -f {frequency} -l {1000 * duration}')
|