machineconfig 1.97__py3-none-any.whl → 2.1__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/cluster/cloud_manager.py +22 -29
- machineconfig/cluster/data_transfer.py +2 -3
- machineconfig/cluster/distribute.py +0 -2
- machineconfig/cluster/file_manager.py +4 -5
- machineconfig/cluster/job_params.py +1 -4
- machineconfig/cluster/loader_runner.py +8 -11
- machineconfig/cluster/remote_machine.py +4 -5
- machineconfig/cluster/script_execution.py +2 -2
- machineconfig/cluster/script_notify_upon_completion.py +0 -1
- machineconfig/cluster/sessions_managers/archive/create_zellij_template.py +4 -6
- machineconfig/cluster/sessions_managers/archive/session_managers.py +0 -1
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +35 -75
- machineconfig/cluster/sessions_managers/wt_local.py +113 -185
- machineconfig/cluster/sessions_managers/wt_local_manager.py +127 -197
- machineconfig/cluster/sessions_managers/wt_remote.py +60 -67
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +110 -149
- machineconfig/cluster/sessions_managers/wt_utils/layout_generator.py +61 -64
- machineconfig/cluster/sessions_managers/wt_utils/process_monitor.py +72 -172
- machineconfig/cluster/sessions_managers/wt_utils/remote_executor.py +27 -60
- machineconfig/cluster/sessions_managers/wt_utils/session_manager.py +58 -137
- machineconfig/cluster/sessions_managers/wt_utils/status_reporter.py +46 -74
- machineconfig/cluster/sessions_managers/zellij_local.py +91 -147
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +165 -190
- machineconfig/cluster/sessions_managers/zellij_remote.py +51 -58
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +40 -46
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +19 -17
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +30 -31
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +64 -134
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +7 -11
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +27 -55
- machineconfig/cluster/sessions_managers/zellij_utils/status_reporter.py +14 -13
- machineconfig/cluster/templates/cli_click.py +0 -1
- machineconfig/cluster/templates/cli_gooey.py +0 -2
- machineconfig/cluster/templates/cli_trogon.py +0 -1
- machineconfig/cluster/templates/run_cloud.py +0 -1
- machineconfig/cluster/templates/run_cluster.py +0 -1
- machineconfig/cluster/templates/run_remote.py +0 -1
- machineconfig/cluster/templates/utils.py +27 -11
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/linux/msc/cli_agents.sh +16 -0
- machineconfig/jobs/python/check_installations.py +9 -9
- machineconfig/jobs/python/create_bootable_media.py +0 -2
- machineconfig/jobs/python/python_cargo_build_share.py +2 -2
- machineconfig/jobs/python/python_ve_symlink.py +9 -11
- machineconfig/jobs/python/tasks.py +0 -1
- machineconfig/jobs/python/vscode/api.py +5 -5
- machineconfig/jobs/python/vscode/link_ve.py +20 -21
- machineconfig/jobs/python/vscode/select_interpreter.py +28 -29
- machineconfig/jobs/python/vscode/sync_code.py +14 -18
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_custom_installers/archive/ngrok.py +15 -15
- machineconfig/jobs/python_custom_installers/dev/aider.py +10 -18
- machineconfig/jobs/python_custom_installers/dev/alacritty.py +12 -21
- machineconfig/jobs/python_custom_installers/dev/brave.py +13 -22
- machineconfig/jobs/python_custom_installers/dev/bypass_paywall.py +13 -20
- machineconfig/jobs/python_custom_installers/dev/code.py +17 -24
- machineconfig/jobs/python_custom_installers/dev/cursor.py +10 -21
- machineconfig/jobs/python_custom_installers/dev/docker_desktop.py +12 -11
- machineconfig/jobs/python_custom_installers/dev/espanso.py +19 -23
- machineconfig/jobs/python_custom_installers/dev/goes.py +9 -16
- machineconfig/jobs/python_custom_installers/dev/lvim.py +13 -21
- machineconfig/jobs/python_custom_installers/dev/nerdfont.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/redis.py +15 -23
- machineconfig/jobs/python_custom_installers/dev/wezterm.py +15 -22
- machineconfig/jobs/python_custom_installers/dev/winget.py +32 -50
- machineconfig/jobs/python_custom_installers/docker.py +15 -24
- machineconfig/jobs/python_custom_installers/gh.py +18 -26
- machineconfig/jobs/python_custom_installers/hx.py +33 -17
- machineconfig/jobs/python_custom_installers/warp-cli.py +15 -23
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/config.json +412 -389
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_windows_installers/dev/config.json +1 -1
- machineconfig/jobs/windows/archive/archive_pygraphviz.ps1 +1 -1
- machineconfig/jobs/windows/msc/cli_agents.bat +0 -0
- machineconfig/jobs/windows/msc/cli_agents.ps1 +0 -0
- machineconfig/jobs/windows/start_terminal.ps1 +1 -1
- machineconfig/logger.py +50 -0
- machineconfig/profile/create.py +50 -36
- machineconfig/profile/create_hardlinks.py +33 -26
- machineconfig/profile/shell.py +87 -60
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/cloud/init.sh +2 -2
- machineconfig/scripts/linux/checkout_versions +1 -1
- machineconfig/scripts/linux/choose_wezterm_theme +1 -1
- machineconfig/scripts/linux/cloud_copy +1 -1
- machineconfig/scripts/linux/cloud_manager +1 -1
- machineconfig/scripts/linux/cloud_mount +1 -1
- machineconfig/scripts/linux/cloud_repo_sync +1 -1
- machineconfig/scripts/linux/cloud_sync +1 -1
- machineconfig/scripts/linux/croshell +1 -1
- machineconfig/scripts/linux/devops +3 -5
- machineconfig/scripts/linux/fire +2 -1
- machineconfig/scripts/linux/fire_agents +3 -3
- machineconfig/scripts/linux/ftpx +1 -1
- machineconfig/scripts/linux/gh_models +1 -1
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/linux/mcinit +2 -2
- machineconfig/scripts/linux/repos +1 -1
- machineconfig/scripts/linux/scheduler +1 -1
- machineconfig/scripts/linux/start_slidev +1 -1
- machineconfig/scripts/linux/start_terminals +1 -1
- machineconfig/scripts/linux/url2md +1 -1
- machineconfig/scripts/linux/warp-cli.sh +122 -0
- machineconfig/scripts/linux/wifi_conn +1 -1
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__init__.py +0 -0
- machineconfig/scripts/python/ai/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/generate_files.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/mcinit.cpython-313.pyc +0 -0
- machineconfig/scripts/python/ai/chatmodes/Thinking-Beast-Mode.chatmode.md +337 -0
- machineconfig/scripts/python/ai/chatmodes/Ultimate-Transparent-Thinking-Beast-Mode.chatmode.md +644 -0
- machineconfig/scripts/python/ai/chatmodes/deepResearch.chatmode.md +81 -0
- machineconfig/scripts/python/ai/configs/.gemini/settings.json +81 -0
- machineconfig/scripts/python/ai/generate_files.py +84 -0
- machineconfig/scripts/python/ai/instructions/python/dev.instructions.md +45 -0
- machineconfig/scripts/python/ai/mcinit.py +107 -0
- machineconfig/scripts/python/ai/prompts/allLintersAndTypeCheckers.prompt.md +5 -0
- machineconfig/scripts/python/ai/prompts/research-report-skeleton.prompt.md +38 -0
- machineconfig/scripts/python/ai/scripts/lint_and_type_check.sh +52 -0
- machineconfig/scripts/python/archive/tmate_conn.py +5 -5
- machineconfig/scripts/python/archive/tmate_start.py +3 -3
- machineconfig/scripts/python/choose_wezterm_theme.py +2 -2
- machineconfig/scripts/python/cloud_copy.py +20 -19
- machineconfig/scripts/python/cloud_mount.py +10 -8
- machineconfig/scripts/python/cloud_repo_sync.py +15 -15
- machineconfig/scripts/python/cloud_sync.py +1 -1
- machineconfig/scripts/python/croshell.py +18 -16
- machineconfig/scripts/python/devops.py +6 -6
- machineconfig/scripts/python/devops_add_identity.py +9 -7
- machineconfig/scripts/python/devops_add_ssh_key.py +19 -19
- machineconfig/scripts/python/devops_backup_retrieve.py +14 -14
- machineconfig/scripts/python/devops_devapps_install.py +3 -3
- machineconfig/scripts/python/devops_update_repos.py +141 -53
- machineconfig/scripts/python/dotfile.py +3 -3
- machineconfig/scripts/python/fire_agents.py +202 -41
- machineconfig/scripts/python/fire_jobs.py +20 -21
- machineconfig/scripts/python/ftpx.py +4 -3
- machineconfig/scripts/python/gh_models.py +94 -94
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +3 -3
- machineconfig/scripts/python/helpers/helpers2.py +3 -3
- machineconfig/scripts/python/helpers/helpers4.py +8 -7
- machineconfig/scripts/python/helpers/helpers5.py +7 -7
- machineconfig/scripts/python/helpers/repo_sync_helpers.py +2 -2
- machineconfig/scripts/python/mount_nfs.py +4 -3
- machineconfig/scripts/python/mount_nw_drive.py +4 -4
- machineconfig/scripts/python/mount_ssh.py +4 -3
- machineconfig/scripts/python/repos.py +9 -9
- machineconfig/scripts/python/scheduler.py +1 -1
- machineconfig/scripts/python/start_slidev.py +9 -8
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/scripts/python/viewer.py +40 -40
- machineconfig/scripts/python/wifi_conn.py +65 -66
- machineconfig/scripts/python/wsl_windows_transfer.py +2 -2
- machineconfig/scripts/windows/checkout_version.ps1 +1 -3
- machineconfig/scripts/windows/choose_wezterm_theme.ps1 +1 -3
- machineconfig/scripts/windows/cloud_copy.ps1 +2 -6
- machineconfig/scripts/windows/cloud_manager.ps1 +1 -1
- machineconfig/scripts/windows/cloud_repo_sync.ps1 +1 -2
- machineconfig/scripts/windows/cloud_sync.ps1 +2 -2
- machineconfig/scripts/windows/croshell.ps1 +2 -2
- machineconfig/scripts/windows/devops.ps1 +1 -4
- machineconfig/scripts/windows/dotfile.ps1 +1 -3
- machineconfig/scripts/windows/fire.ps1 +1 -1
- machineconfig/scripts/windows/ftpx.ps1 +2 -2
- machineconfig/scripts/windows/gpt.ps1 +1 -1
- machineconfig/scripts/windows/kill_process.ps1 +1 -2
- machineconfig/scripts/windows/mcinit.ps1 +2 -2
- machineconfig/scripts/windows/mount_nfs.ps1 +1 -1
- machineconfig/scripts/windows/mount_ssh.ps1 +1 -1
- machineconfig/scripts/windows/pomodoro.ps1 +1 -1
- machineconfig/scripts/windows/py2exe.ps1 +1 -3
- machineconfig/scripts/windows/repos.ps1 +1 -1
- machineconfig/scripts/windows/scheduler.ps1 +1 -1
- machineconfig/scripts/windows/snapshot.ps1 +2 -2
- machineconfig/scripts/windows/start_slidev.ps1 +1 -1
- machineconfig/scripts/windows/start_terminals.ps1 +1 -1
- machineconfig/scripts/windows/wifi_conn.ps1 +1 -1
- machineconfig/scripts/windows/wsl_windows_transfer.ps1 +1 -3
- machineconfig/settings/lf/linux/lfrc +1 -1
- machineconfig/settings/linters/.ruff.toml +2 -2
- machineconfig/settings/linters/.ruff_cache/.gitignore +2 -0
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +1 -0
- machineconfig/settings/lvim/windows/archive/config_additional.lua +1 -1
- machineconfig/settings/shells/ipy/profiles/default/startup/playext.py +71 -71
- machineconfig/settings/shells/wt/settings.json +8 -8
- machineconfig/settings/svim/linux/init.toml +1 -1
- machineconfig/settings/svim/windows/init.toml +1 -1
- machineconfig/setup_linux/web_shortcuts/croshell.sh +0 -54
- machineconfig/setup_linux/web_shortcuts/interactive.sh +6 -6
- machineconfig/setup_linux/web_shortcuts/tmp.sh +2 -0
- machineconfig/setup_windows/web_shortcuts/all.ps1 +2 -2
- machineconfig/setup_windows/web_shortcuts/ascii_art.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/croshell.ps1 +1 -1
- machineconfig/setup_windows/web_shortcuts/interactive.ps1 +5 -5
- machineconfig/setup_windows/wt_and_pwsh/install_fonts.ps1 +51 -15
- machineconfig/setup_windows/wt_and_pwsh/set_pwsh_theme.py +75 -18
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +52 -42
- machineconfig/utils/ai/browser_user_wrapper.py +5 -5
- machineconfig/utils/ai/generate_file_checklist.py +19 -22
- machineconfig/utils/ai/url2md.py +5 -3
- machineconfig/utils/cloud/onedrive/setup_oauth.py +5 -4
- machineconfig/utils/cloud/onedrive/transaction.py +192 -227
- machineconfig/utils/code.py +71 -43
- machineconfig/utils/installer.py +77 -85
- machineconfig/utils/installer_utils/installer_abc.py +29 -17
- machineconfig/utils/installer_utils/installer_class.py +188 -83
- machineconfig/utils/io_save.py +3 -15
- machineconfig/utils/links.py +22 -11
- machineconfig/utils/notifications.py +197 -0
- machineconfig/utils/options.py +38 -25
- machineconfig/utils/path.py +18 -6
- machineconfig/utils/path_reduced.py +637 -316
- machineconfig/utils/procs.py +69 -63
- machineconfig/utils/scheduling.py +11 -13
- machineconfig/utils/ssh.py +351 -0
- machineconfig/utils/terminal.py +225 -0
- machineconfig/utils/utils.py +13 -12
- machineconfig/utils/utils2.py +43 -10
- machineconfig/utils/utils5.py +242 -46
- machineconfig/utils/ve.py +11 -6
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/METADATA +15 -9
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/RECORD +232 -235
- machineconfig/cluster/self_ssh.py +0 -57
- machineconfig/jobs/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python/archive/python_tools.txt +0 -12
- machineconfig/jobs/python/vscode/__pycache__/select_interpreter.cpython-311.pyc +0 -0
- machineconfig/jobs/python_custom_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/jobs/python_generic_installers/update.py +0 -3
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/create.cpython-311.pyc +0 -0
- machineconfig/profile/__pycache__/shell.cpython-311.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/linux/activate_ve +0 -87
- machineconfig/scripts/python/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_copy.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_mount.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_sync.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/croshell.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_backup_retrieve.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_jobs.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-311.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/__pycache__/init.cpython-311.pyc +0 -0
- machineconfig/scripts/python/ai/init.py +0 -56
- machineconfig/scripts/python/ai/rules/python/dev.md +0 -31
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/cloud_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers2.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/helpers4.cpython-311.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-311.pyc +0 -0
- machineconfig/scripts/windows/activate_ve.ps1 +0 -54
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/WHEEL +0 -0
- {machineconfig-1.97.dist-info → machineconfig-2.1.dist-info}/top_level.txt +0 -0
machineconfig/utils/utils2.py
CHANGED
|
@@ -1,42 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
from pathlib import Path
|
|
4
2
|
from typing import Optional, Any
|
|
3
|
+
# import time
|
|
4
|
+
# from typing import Callable, Literal, TypeVar, ParamSpec
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
def randstr(length: int = 10, lower: bool = True, upper: bool = True, digits: bool = True, punctuation: bool = False, safe: bool = False, noun: bool = False) -> str:
|
|
7
8
|
if safe:
|
|
8
9
|
import secrets
|
|
10
|
+
|
|
9
11
|
return secrets.token_urlsafe(length) # interannly, it uses: random.SystemRandom or os.urandom which is hardware-based, not pseudo
|
|
10
12
|
if noun:
|
|
11
13
|
import randomname
|
|
14
|
+
|
|
12
15
|
return randomname.get_name()
|
|
13
16
|
import string
|
|
14
17
|
import random
|
|
18
|
+
|
|
15
19
|
population = (string.ascii_lowercase if lower else "") + (string.ascii_uppercase if upper else "") + (string.digits if digits else "") + (string.punctuation if punctuation else "")
|
|
16
|
-
return
|
|
20
|
+
return "".join(random.choices(population, k=length))
|
|
17
21
|
|
|
18
22
|
|
|
19
|
-
def read_ini(path:
|
|
20
|
-
if not Path(path).exists() or Path(path).is_dir():
|
|
23
|
+
def read_ini(path: "Path", encoding: Optional[str] = None):
|
|
24
|
+
if not Path(path).exists() or Path(path).is_dir():
|
|
25
|
+
raise FileNotFoundError(f"File not found or is a directory: {path}")
|
|
21
26
|
import configparser
|
|
27
|
+
|
|
22
28
|
res = configparser.ConfigParser()
|
|
23
29
|
res.read(filenames=[str(path)], encoding=encoding)
|
|
24
30
|
return res
|
|
25
|
-
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def read_json(path: "Path", r: bool = False, **kwargs: Any) -> Any: # return could be list or dict etc
|
|
26
34
|
import json
|
|
35
|
+
|
|
27
36
|
try:
|
|
28
|
-
mydict = json.loads(Path(path).read_text(encoding=
|
|
37
|
+
mydict = json.loads(Path(path).read_text(encoding="utf-8"), **kwargs)
|
|
29
38
|
except Exception:
|
|
30
39
|
import pyjson5
|
|
31
|
-
|
|
40
|
+
|
|
41
|
+
mydict = pyjson5.loads(Path(path).read_text(encoding="utf-8"), **kwargs) # file has C-style comments.
|
|
32
42
|
_ = r
|
|
33
43
|
return mydict
|
|
34
|
-
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def read_toml(path: "Path"):
|
|
35
47
|
import tomli
|
|
36
|
-
|
|
48
|
+
|
|
49
|
+
return tomli.loads(path.read_text(encoding="utf-8"))
|
|
50
|
+
|
|
37
51
|
|
|
38
52
|
def pprint(obj: dict[Any, Any], title: str) -> None:
|
|
39
53
|
from rich import inspect
|
|
40
54
|
inspect(type("TempStruct", (object,), obj)(), value=False, title=title, docs=False, dunder=False, sort=False)
|
|
55
|
+
|
|
56
|
+
|
|
41
57
|
def get_repr(obj: dict[Any, Any], sep: str = "\n", justify: int = 15, quotes: bool = False):
|
|
42
58
|
return sep.join([f"{key:>{justify}} = {repr(val) if quotes else val}" for key, val in obj.items()])
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def human_friendly_dict(d: dict[str, Any]) -> dict[str, Any]:
|
|
62
|
+
from datetime import datetime
|
|
63
|
+
|
|
64
|
+
result = {}
|
|
65
|
+
for k, v in d.items():
|
|
66
|
+
if isinstance(v, float):
|
|
67
|
+
result[k] = f"{v:.2f}"
|
|
68
|
+
elif isinstance(v, bool):
|
|
69
|
+
result[k] = "✓" if v else "✗"
|
|
70
|
+
elif isinstance(v, int) and len(str(v)) == 13 and v > 0: # assuming ms timestamp
|
|
71
|
+
dt = datetime.fromtimestamp(v / 1000)
|
|
72
|
+
result[k] = dt.strftime("%Y-%m-%d %H:%M")
|
|
73
|
+
else:
|
|
74
|
+
result[k] = v
|
|
75
|
+
return result
|
machineconfig/utils/utils5.py
CHANGED
|
@@ -1,39 +1,68 @@
|
|
|
1
|
-
|
|
2
|
-
from typing import Callable, Optional, Union, Any
|
|
3
|
-
|
|
4
|
-
from machineconfig.utils.utils2 import randstr, get_repr
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Callable, Optional, Union, Any, NoReturn, TypeVar, Protocol, List, Generic
|
|
3
|
+
import logging
|
|
5
4
|
import time
|
|
6
|
-
from datetime import datetime, timezone
|
|
5
|
+
from datetime import datetime, timezone, timedelta
|
|
6
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LoggerTemplate(Protocol):
|
|
10
|
+
handlers: List[logging.Handler]
|
|
11
|
+
|
|
12
|
+
def debug(self, msg: str) -> None:
|
|
13
|
+
pass # 10
|
|
14
|
+
|
|
15
|
+
def info(self, msg: str) -> None:
|
|
16
|
+
pass # 20
|
|
17
|
+
|
|
18
|
+
def warning(self, msg: str) -> None:
|
|
19
|
+
pass # 30
|
|
20
|
+
|
|
21
|
+
def error(self, msg: str) -> None:
|
|
22
|
+
pass # 40
|
|
23
|
+
|
|
24
|
+
def critical(self, msg: str) -> None:
|
|
25
|
+
pass # 50
|
|
26
|
+
|
|
27
|
+
def fatal(self, msg: str) -> None:
|
|
28
|
+
pass # 50
|
|
7
29
|
|
|
8
30
|
|
|
9
31
|
class Scheduler:
|
|
10
|
-
def __init__(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
routine: Callable[["Scheduler"], Any],
|
|
35
|
+
wait_ms: int,
|
|
36
|
+
logger: LoggerTemplate,
|
|
37
|
+
sess_stats: Optional[Callable[["Scheduler"], dict[str, Any]]] = None,
|
|
38
|
+
exception_handler: Optional[Callable[[Union[Exception, KeyboardInterrupt], str, "Scheduler"], Any]] = None,
|
|
39
|
+
max_cycles: int = 1_000_000_000,
|
|
40
|
+
records: Optional[list[list[Any]]] = None,
|
|
41
|
+
):
|
|
17
42
|
self.routine = routine # main routine to be repeated every `wait` time period
|
|
18
|
-
self.logger = logger
|
|
43
|
+
self.logger = logger
|
|
19
44
|
self.exception_handler = exception_handler if exception_handler is not None else self.default_exception_handler
|
|
20
45
|
self.records: list[list[Any]] = records if records is not None else []
|
|
21
46
|
self.wait_ms = wait_ms # wait period between routine cycles.
|
|
22
47
|
self.cycle: int = 0
|
|
23
48
|
self.max_cycles: int = max_cycles
|
|
24
|
-
self.
|
|
49
|
+
self.sess_start_utc_ms: int
|
|
25
50
|
self.sess_stats = sess_stats or (lambda _sched: {})
|
|
26
|
-
|
|
27
|
-
def
|
|
51
|
+
|
|
52
|
+
def __repr__(self):
|
|
53
|
+
return f"Scheduler with {self.cycle} cycles ran so far. Last cycle was at {self.sess_start_utc_ms}."
|
|
54
|
+
|
|
55
|
+
def run(self, max_cycles: Optional[int] = None, until_ms: Optional[int] = None):
|
|
28
56
|
if max_cycles is not None:
|
|
29
57
|
self.max_cycles = max_cycles
|
|
30
58
|
if until_ms is None:
|
|
31
|
-
until_ms =
|
|
32
|
-
self.
|
|
59
|
+
until_ms = 1_000_000_000_000_000
|
|
60
|
+
self.sess_start_utc_ms = time.time_ns() // 1_000_000
|
|
33
61
|
while (time.time_ns() // 1_000_000) < until_ms and self.cycle < self.max_cycles:
|
|
34
62
|
# 1- Time before Ops, and Opening Message
|
|
35
63
|
time1_ms = time.time_ns() // 1_000_000
|
|
36
|
-
|
|
64
|
+
duration = timedelta(milliseconds=time1_ms - self.sess_start_utc_ms)
|
|
65
|
+
self.logger.info(f"Starting Cycle {str(self.cycle).zfill(5)}. Total Run Time = {str(duration).split('.', maxsplit=1)[0]}. UTC🕜 {datetime.now(tz=timezone.utc).strftime('%d %H:%M:%S')}")
|
|
37
66
|
try:
|
|
38
67
|
self.routine(self)
|
|
39
68
|
except Exception as ex:
|
|
@@ -41,44 +70,211 @@ class Scheduler:
|
|
|
41
70
|
time2_ms = time.time_ns() // 1_000_000
|
|
42
71
|
time_left_ms = int(self.wait_ms - (time2_ms - time1_ms)) # 4- Conclude Message
|
|
43
72
|
self.cycle += 1
|
|
44
|
-
self.logger.info(f"Finishing Cycle {str(self.cycle - 1).zfill(5)} in {str((time2_ms - time1_ms)*0.001).split('.', maxsplit=1)[0]}s. Sleeping for {self.wait_ms*0.001:0.1f}s ({time_left_ms*0.001:0.
|
|
45
|
-
try:
|
|
73
|
+
self.logger.info(f"Finishing Cycle {str(self.cycle - 1).zfill(5)} in {str((time2_ms - time1_ms) * 0.001).split('.', maxsplit=1)[0]}s. Sleeping for {self.wait_ms * 0.001:0.1f}s ({time_left_ms * 0.001:0.1f}s left)\n" + "-" * 100)
|
|
74
|
+
try:
|
|
75
|
+
time.sleep(time_left_ms * 0.001 if time_left_ms > 0 else 0.0) # # 5- Sleep. consider replacing by Asyncio.sleep
|
|
46
76
|
except KeyboardInterrupt as ex:
|
|
47
77
|
self.exception_handler(ex, "sleep", self)
|
|
48
78
|
return # that's probably the only kind of exception that can rise during sleep.
|
|
49
79
|
self.record_session_end(reason=f"Reached maximum number of cycles ({self.max_cycles})" if self.cycle >= self.max_cycles else f"Reached due stop time ({until_ms})")
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
columns = ["start", "finish", "duration", "cycles", "termination reason"
|
|
53
|
-
return
|
|
80
|
+
|
|
81
|
+
def get_records_df(self) -> List[dict[str, Any]]:
|
|
82
|
+
columns = ["start", "finish", "duration", "cycles", "termination reason"] + list(self.sess_stats(self).keys())
|
|
83
|
+
return [dict(zip(columns, row)) for row in self.records]
|
|
84
|
+
|
|
54
85
|
def record_session_end(self, reason: str):
|
|
55
|
-
import polars as pl
|
|
56
86
|
end_time_ms = time.time_ns() // 1_000_000
|
|
57
|
-
duration_ms = end_time_ms - self.
|
|
87
|
+
duration_ms = end_time_ms - self.sess_start_utc_ms
|
|
58
88
|
sess_stats = self.sess_stats(self)
|
|
59
|
-
self.records.append(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
89
|
+
self.records.append(
|
|
90
|
+
[
|
|
91
|
+
self.sess_start_utc_ms,
|
|
92
|
+
end_time_ms,
|
|
93
|
+
duration_ms,
|
|
94
|
+
self.cycle,
|
|
95
|
+
reason,
|
|
96
|
+
# self.logger.file_path
|
|
97
|
+
]
|
|
98
|
+
+ list(sess_stats.values())
|
|
99
|
+
)
|
|
100
|
+
records_df = self.get_records_df()
|
|
101
|
+
total_cycles = sum(row["cycles"] for row in records_df)
|
|
102
|
+
summ = {
|
|
103
|
+
"start time": f"{str(self.sess_start_utc_ms)}",
|
|
104
|
+
"finish time": f"{str(end_time_ms)}.",
|
|
105
|
+
"duration": f"{str(duration_ms)} | wait time {self.wait_ms / 1_000: 0.1f}s",
|
|
106
|
+
"cycles ran": f"{self.cycle} | Lifetime cycles = {total_cycles}",
|
|
107
|
+
"termination reason": reason,
|
|
108
|
+
# "logfile": self.logger.file_path
|
|
109
|
+
}
|
|
69
110
|
summ.update(sess_stats)
|
|
111
|
+
from machineconfig.utils.utils2 import get_repr
|
|
112
|
+
|
|
70
113
|
tmp = get_repr(summ)
|
|
71
114
|
self.logger.critical("\n--> Scheduler has finished running a session. \n" + tmp + "\n" + "-" * 100)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
115
|
+
# Format records as table
|
|
116
|
+
if records_df:
|
|
117
|
+
headers = list(records_df[0].keys())
|
|
118
|
+
# Process start, finish, duration to strings without milliseconds
|
|
119
|
+
processed_records = []
|
|
120
|
+
for row in records_df:
|
|
121
|
+
processed = row.copy()
|
|
122
|
+
processed["start"] = str(row["start"]).split(".", maxsplit=1)[0]
|
|
123
|
+
processed["finish"] = str(row["finish"]).split(".", maxsplit=1)[0]
|
|
124
|
+
processed["duration"] = str(row["duration"]).split(".", maxsplit=1)[0]
|
|
125
|
+
processed_records.append(processed)
|
|
126
|
+
# Simple aligned table formatting
|
|
127
|
+
max_lengths = {col: max(len(str(row.get(col, ""))) for row in processed_records) for col in headers}
|
|
128
|
+
table_lines = ["| " + " | ".join(col.ljust(max_lengths[col]) for col in headers) + " |"]
|
|
129
|
+
table_lines.append("|" + "-+-".join("-" * max_lengths[col] for col in headers) + "|")
|
|
130
|
+
for row in processed_records:
|
|
131
|
+
table_lines.append("| " + " | ".join(str(row.get(col, "")).ljust(max_lengths[col]) for col in headers) + " |")
|
|
132
|
+
table_str = "\n".join(table_lines)
|
|
133
|
+
else:
|
|
134
|
+
table_str = "No records available."
|
|
135
|
+
self.logger.critical("\n--> Logger history.\n" + table_str)
|
|
79
136
|
return self
|
|
80
|
-
|
|
137
|
+
|
|
138
|
+
def default_exception_handler(self, ex: Union[Exception, KeyboardInterrupt], during: str, sched: "Scheduler") -> None: # user decides on handling and continue, terminate, save checkpoint, etc. # Use signal library.
|
|
81
139
|
print(sched)
|
|
82
140
|
self.record_session_end(reason=f"during {during}, " + str(ex))
|
|
83
|
-
self.logger.
|
|
141
|
+
self.logger.fatal(str(ex))
|
|
84
142
|
raise ex
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
T = TypeVar("T")
|
|
146
|
+
T2 = TypeVar("T2")
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class PrintFunc(Protocol):
|
|
150
|
+
def __call__(self, msg: str) -> Union[NoReturn, None]: ...
|
|
151
|
+
|
|
152
|
+
def to_pickle(obj: Any, path: Path) -> None:
|
|
153
|
+
import pickle
|
|
154
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
path.write_bytes(pickle.dumps(obj))
|
|
156
|
+
def from_pickle(path: Path) -> Any:
|
|
157
|
+
import pickle
|
|
158
|
+
return pickle.loads(path.read_bytes())
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class Cache(Generic[T]): # This class helps to accelrate access to latest data coming from expensive function. The class has two flavours, memory-based and disk-based variants."""
|
|
162
|
+
# source_func: Callable[[], T]
|
|
163
|
+
def __init__(self, source_func: Callable[[], T],
|
|
164
|
+
expire: timedelta, logger: Optional[PrintFunc] = None, path: Optional[Path] = None,
|
|
165
|
+
saver: Callable[[T, Path], Any] = to_pickle, reader: Callable[[Path], T] = from_pickle, name: Optional[str] = None) -> None:
|
|
166
|
+
self.cache: T
|
|
167
|
+
self.source_func = source_func # function which when called returns a fresh object to be frozen.
|
|
168
|
+
self.path: Optional[PathExtended] = PathExtended(path) if path is not None else None # if path is passed, it will function as disk-based flavour.
|
|
169
|
+
self.time_produced = datetime.now() # if path is None else
|
|
170
|
+
self.save = saver
|
|
171
|
+
self.reader = reader
|
|
172
|
+
self.logger = logger
|
|
173
|
+
self.expire = expire
|
|
174
|
+
self.name = name if isinstance(name, str) else str(self.source_func)
|
|
175
|
+
self.last_call_is_fresh = False
|
|
176
|
+
@property
|
|
177
|
+
def age(self):
|
|
178
|
+
"""Throws AttributeError if called before cache is populated and path doesn't exists"""
|
|
179
|
+
if self.path is None: # memory-based cache.
|
|
180
|
+
return datetime.now() - self.time_produced
|
|
181
|
+
return datetime.now() - datetime.fromtimestamp(self.path.stat().st_mtime)
|
|
182
|
+
# def __setstate__(self, state: dict[str, Any]) -> None:
|
|
183
|
+
# self.__dict__.update(state)
|
|
184
|
+
# self.path = P.home() / self.path if self.path is not None else self.path
|
|
185
|
+
# def __getstate__(self) -> dict[str, Any]:
|
|
186
|
+
# state = self.__dict__.copy()
|
|
187
|
+
# state["path"] = self.path.rel2home() if self.path is not None else state["path"]
|
|
188
|
+
# return state # With this implementation, instances can be pickled and loaded up in different machine and still works.
|
|
189
|
+
def __call__(self, fresh: bool = False) -> T:
|
|
190
|
+
self.last_call_is_fresh = False
|
|
191
|
+
if fresh or not hasattr(self, "cache"): # populate cache for the first time
|
|
192
|
+
if not fresh and self.path is not None and self.path.exists():
|
|
193
|
+
age = datetime.now() - datetime.fromtimestamp(self.path.stat().st_mtime)
|
|
194
|
+
msg1 = f"""
|
|
195
|
+
📦 ════════════════════ CACHE OPERATION ════════════════════
|
|
196
|
+
🔄 {self.name} cache: Reading cached values from `{self.path}`
|
|
197
|
+
⏱️ Lag = {age}
|
|
198
|
+
════════════════════════════════════════════════════════════
|
|
199
|
+
"""
|
|
200
|
+
try:
|
|
201
|
+
self.cache = self.reader(self.path)
|
|
202
|
+
except Exception as ex:
|
|
203
|
+
if self.logger:
|
|
204
|
+
msg2 = f"""
|
|
205
|
+
❌ ════════════════════ CACHE ERROR ════════════════════
|
|
206
|
+
⚠️ {self.name} cache: Cache file is corrupted
|
|
207
|
+
🔍 Error: {ex}
|
|
208
|
+
════════════════════════════════════════════════════════
|
|
209
|
+
"""
|
|
210
|
+
self.logger(msg1 + msg2)
|
|
211
|
+
self.cache = self.source_func()
|
|
212
|
+
self.last_call_is_fresh = True
|
|
213
|
+
self.time_produced = datetime.now()
|
|
214
|
+
# if self.path is not None:
|
|
215
|
+
# self.save(self.cache, self.path)
|
|
216
|
+
return self.cache
|
|
217
|
+
return self(fresh=False) # may be the cache is old ==> check that by passing it through the logic again.
|
|
218
|
+
else:
|
|
219
|
+
if self.logger:
|
|
220
|
+
# Previous cache never existed or there was an explicit fresh order.
|
|
221
|
+
why = "There was an explicit fresh order." if fresh else "Previous cache never existed or is corrupted."
|
|
222
|
+
self.logger(f"""
|
|
223
|
+
🆕 ════════════════════ NEW CACHE ════════════════════
|
|
224
|
+
🔄 {self.name} cache: Populating fresh cache from source func
|
|
225
|
+
ℹ️ Reason: {why}
|
|
226
|
+
════════════════════════════════════════════════════════
|
|
227
|
+
""")
|
|
228
|
+
self.cache = self.source_func() # fresh data.
|
|
229
|
+
self.last_call_is_fresh = True
|
|
230
|
+
self.time_produced = datetime.now()
|
|
231
|
+
if self.path is not None: self.save(self.cache, self.path)
|
|
232
|
+
else: # cache exists
|
|
233
|
+
try: age = self.age
|
|
234
|
+
except AttributeError: # path doesn't exist (may be deleted) ==> need to repopulate cache form source_func.
|
|
235
|
+
return self(fresh=True)
|
|
236
|
+
if age > self.expire:
|
|
237
|
+
if self.logger:
|
|
238
|
+
self.logger(f"""
|
|
239
|
+
🔄 ════════════════════ CACHE UPDATE ════════════════════
|
|
240
|
+
⚠️ {self.name} cache: Updating cache from source func
|
|
241
|
+
⏱️ Age = {age} > {self.expire}
|
|
242
|
+
════════════════════════════════════════════════════════""")
|
|
243
|
+
self.cache = self.source_func()
|
|
244
|
+
self.last_call_is_fresh = True
|
|
245
|
+
self.time_produced = datetime.now()
|
|
246
|
+
if self.path is not None: self.save(self.cache, self.path)
|
|
247
|
+
else:
|
|
248
|
+
if self.logger:
|
|
249
|
+
self.logger(f"""
|
|
250
|
+
✅ ════════════════════ USING CACHE ════════════════════
|
|
251
|
+
📦 {self.name} cache: Using cached values
|
|
252
|
+
⏱️ Lag = {age}
|
|
253
|
+
════════════════════════════════════════════════════════""")
|
|
254
|
+
return self.cache
|
|
255
|
+
@staticmethod
|
|
256
|
+
def as_decorator(expire: timedelta, logger: Optional[PrintFunc] = None, path: Optional[Path] = None,
|
|
257
|
+
saver: Callable[[T2, Path], Any] = to_pickle,
|
|
258
|
+
reader: Callable[[Path], T2] = from_pickle,
|
|
259
|
+
name: Optional[str] = None): # -> Callable[..., 'Cache[T2]']:
|
|
260
|
+
def decorator(source_func: Callable[[], T2]) -> Cache['T2']:
|
|
261
|
+
res = Cache(source_func=source_func, expire=expire, logger=logger, path=path, name=name, reader=reader, saver=saver)
|
|
262
|
+
return res
|
|
263
|
+
return decorator
|
|
264
|
+
def from_cloud(self, cloud: str, rel2home: bool = True, root: Optional[str] = None):
|
|
265
|
+
assert self.path is not None
|
|
266
|
+
exists = self.path.exists()
|
|
267
|
+
exists_but_old = exists and ((datetime.now() - datetime.fromtimestamp(self.path.stat().st_mtime)) > self.expire)
|
|
268
|
+
if not exists or exists_but_old:
|
|
269
|
+
returned_path = self.path.from_cloud(cloud=cloud, rel2home=rel2home, root=root)
|
|
270
|
+
if returned_path is None and not exists:
|
|
271
|
+
raise FileNotFoundError(f"❌ Failed to get @ {self.path}. Build the cache first with signed API.")
|
|
272
|
+
elif returned_path is None and exists and self.logger is not None:
|
|
273
|
+
self.logger(f"""
|
|
274
|
+
⚠️ ════════════════════ CLOUD FETCH WARNING ════════════════════
|
|
275
|
+
🔄 Failed to get fresh data from cloud
|
|
276
|
+
📦 Using old cache @ {self.path}
|
|
277
|
+
════════════════════════════════════════════════════════════════""")
|
|
278
|
+
else:
|
|
279
|
+
pass # maybe we don't need to fetch it from cloud, if its too hot
|
|
280
|
+
return self.reader(self.path)
|
machineconfig/utils/ve.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from machineconfig.utils.path_reduced import
|
|
1
|
+
from machineconfig.utils.path_reduced import PathExtended as PathExtended
|
|
2
2
|
from machineconfig.utils.utils2 import read_ini
|
|
3
3
|
import platform
|
|
4
4
|
from typing import Optional
|
|
@@ -19,10 +19,10 @@ def get_ve_path_and_ipython_profile(init_path: PathExtended) -> tuple[Optional[s
|
|
|
19
19
|
ipy_profile = ini["specs"]["ipy_profile"]
|
|
20
20
|
print(f"✨ Using IPython profile: {ipy_profile}")
|
|
21
21
|
if ipy_profile is None and tmp.joinpath(".ipy_profile").exists():
|
|
22
|
-
ipy_profile = tmp.joinpath(".ipy_profile").read_text().rstrip()
|
|
22
|
+
ipy_profile = tmp.joinpath(".ipy_profile").read_text(encoding="utf-8").rstrip()
|
|
23
23
|
print(f"✨ Using IPython profile: {ipy_profile}. This is based on this file {tmp.joinpath('.ipy_profile')}")
|
|
24
24
|
if ve_path is None and tmp.joinpath(".ve_path").exists():
|
|
25
|
-
ve_path = tmp.joinpath(".ve_path").read_text().rstrip().replace("\n", "")
|
|
25
|
+
ve_path = tmp.joinpath(".ve_path").read_text(encoding="utf-8").rstrip().replace("\n", "")
|
|
26
26
|
print(f"🔮 Using Virtual Environment found @ {tmp}/.ve_path: {ve_path}")
|
|
27
27
|
if ve_path is None and tmp.joinpath(".venv").exists():
|
|
28
28
|
print(f"🔮 Using Virtual Environment found @ {tmp}/.venv")
|
|
@@ -37,6 +37,7 @@ def get_ve_path_and_ipython_profile(init_path: PathExtended) -> tuple[Optional[s
|
|
|
37
37
|
|
|
38
38
|
def get_repo_root(choice_file: str) -> Optional[str]:
|
|
39
39
|
from git import Repo, InvalidGitRepositoryError
|
|
40
|
+
|
|
40
41
|
try:
|
|
41
42
|
repo = Repo(PathExtended(choice_file), search_parent_directories=True)
|
|
42
43
|
repo_root = str(repo.working_tree_dir) if repo.working_tree_dir else None
|
|
@@ -44,8 +45,12 @@ def get_repo_root(choice_file: str) -> Optional[str]:
|
|
|
44
45
|
repo_root = None
|
|
45
46
|
return repo_root
|
|
46
47
|
|
|
48
|
+
|
|
47
49
|
def get_ve_activate_line(ve_root: str):
|
|
48
|
-
if platform.system() == "Windows":
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
if platform.system() == "Windows":
|
|
51
|
+
activate_ve_line = f". {ve_root}/Scripts/activate.ps1"
|
|
52
|
+
elif platform.system() in ["Linux", "Darwin"]:
|
|
53
|
+
activate_ve_line = f". {ve_root}/bin/activate"
|
|
54
|
+
else:
|
|
55
|
+
raise NotImplementedError(f"Platform {platform.system()} not supported.")
|
|
51
56
|
return activate_ve_line
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: machineconfig
|
|
3
|
-
Version: 1
|
|
3
|
+
Version: 2.1
|
|
4
4
|
Summary: Dotfiles management package
|
|
5
5
|
Author-email: Alex Al-Saffar <programmer@usa.com>
|
|
6
6
|
License: Apache 2.0
|
|
@@ -9,22 +9,28 @@ Project-URL: Bug Tracker, https://github.com/thisismygitrepo/machineconfig/issue
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.
|
|
12
|
+
Requires-Python: >=3.13
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
|
-
Requires-Dist: crocodile
|
|
15
14
|
Requires-Dist: rich>=14.0.0
|
|
16
15
|
Requires-Dist: paramiko>=3.5.1
|
|
17
16
|
Requires-Dist: psutil>=7.0.0
|
|
18
|
-
Requires-Dist: openai>=1.75.0
|
|
19
|
-
Requires-Dist: nbformat>=5.10.4
|
|
20
17
|
Requires-Dist: fire>=0.7.0
|
|
21
18
|
Requires-Dist: pydantic>=2.11.3
|
|
22
|
-
Requires-Dist: clipboard>=0.0.4
|
|
23
19
|
Requires-Dist: gitpython>=3.1.44
|
|
24
|
-
Requires-Dist: pudb>=2024.1.3
|
|
25
20
|
Requires-Dist: pyfzf>=0.3.1
|
|
26
|
-
Requires-Dist: call-function-with-timeout>=1.1.1
|
|
27
21
|
Requires-Dist: rclone-python>=0.1.23
|
|
22
|
+
Requires-Dist: pytz>=2025.2
|
|
23
|
+
Requires-Dist: tomli>=2.2.1
|
|
24
|
+
Requires-Dist: toml>=0.10.2
|
|
25
|
+
Requires-Dist: pyyaml>=6.0.2
|
|
26
|
+
Requires-Dist: pyjson5>=1.6.9
|
|
27
|
+
Requires-Dist: requests>=2.32.5
|
|
28
|
+
Requires-Dist: tqdm>=4.67.1
|
|
29
|
+
Requires-Dist: joblib>=1.5.2
|
|
30
|
+
Requires-Dist: randomname>=0.2.1
|
|
31
|
+
Requires-Dist: cryptography>=44.0.2
|
|
32
|
+
Requires-Dist: tenacity>=9.1.2
|
|
33
|
+
Requires-Dist: markdown>=3.9
|
|
28
34
|
Provides-Extra: windows
|
|
29
35
|
Requires-Dist: pywin32; extra == "windows"
|
|
30
36
|
Provides-Extra: docs
|
|
@@ -93,7 +99,7 @@ iwr https://raw.githubusercontent.com/thisismygitrepo/machineconfig/main/src/mac
|
|
|
93
99
|
(iwr bit.ly/cfgwt).Content | iex
|
|
94
100
|
. $HOME/code/machineconfig/src/machineconfig/setup_windows/symlinks.ps1
|
|
95
101
|
|
|
96
|
-
& "$HOME\
|
|
102
|
+
& "$HOME\code\machineconfig\.venv\Scripts\activate.ps1"
|
|
97
103
|
python -m fire machineconfig.profile.create main2 --choice=all
|
|
98
104
|
deactivate
|
|
99
105
|
|