ladyrick 0.5.3__py3-none-any.whl → 0.5.5__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.
- ladyrick/cli/calc.py +9 -9
- ladyrick/cli/multi_ssh.py +36 -16
- ladyrick/cli/test_signal.py +2 -2
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/METADATA +1 -1
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/RECORD +9 -9
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/WHEEL +0 -0
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/entry_points.txt +0 -0
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/licenses/LICENSE +0 -0
- {ladyrick-0.5.3.dist-info → ladyrick-0.5.5.dist-info}/top_level.txt +0 -0
ladyrick/cli/calc.py
CHANGED
@@ -5,15 +5,15 @@ import sys
|
|
5
5
|
def initialize(interactive_mode: bool):
|
6
6
|
imports = {}
|
7
7
|
exec("import ladyrick.patch.rich_print")
|
8
|
-
exec("import math; from math import *",
|
9
|
-
exec("import itertools; from itertools import *",
|
10
|
-
exec("import functools; from functools import cache, lru_cache, partial, reduce",
|
11
|
-
exec("import os, sys, time, re, random",
|
12
|
-
exec("from pathlib import Path",
|
13
|
-
exec("from time import sleep",
|
14
|
-
exec("from subprocess import check_output",
|
15
|
-
exec("from random import randint, choice, random as rand",
|
16
|
-
exec("import ladyrick",
|
8
|
+
exec("import math; from math import *", None, imports)
|
9
|
+
exec("import itertools; from itertools import *", None, imports)
|
10
|
+
exec("import functools; from functools import cache, lru_cache, partial, reduce", None, imports)
|
11
|
+
exec("import os, sys, time, re, random", None, imports)
|
12
|
+
exec("from pathlib import Path", None, imports)
|
13
|
+
exec("from time import sleep", None, imports)
|
14
|
+
exec("from subprocess import check_output", None, imports)
|
15
|
+
exec("from random import randint, choice, random as rand", None, imports)
|
16
|
+
exec("import ladyrick", None, imports)
|
17
17
|
if interactive_mode:
|
18
18
|
imports["ladyrick"].pprint.reg_ipython_cmd()
|
19
19
|
globals().update(imports)
|
ladyrick/cli/multi_ssh.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
|
+
import re
|
3
4
|
import select
|
4
5
|
import signal
|
5
6
|
import subprocess
|
@@ -21,7 +22,7 @@ def force_kill(child: subprocess.Popen, child_pgid):
|
|
21
22
|
child.kill() # kill -9
|
22
23
|
|
23
24
|
|
24
|
-
REMOTE_HEAD_PROG_NAME = "ladyrick-remote-head"
|
25
|
+
REMOTE_HEAD_PROG_NAME = "ladyrick/multi-ssh/remote-head"
|
25
26
|
|
26
27
|
|
27
28
|
def remote_head():
|
@@ -51,14 +52,14 @@ def remote_head():
|
|
51
52
|
def handle_signal(sig, frame=None):
|
52
53
|
if sig == signal.SIGUSR2:
|
53
54
|
# SIGUSR2 trigger force_kill manually
|
54
|
-
|
55
|
+
print("SIGUSR2 received. force kill")
|
55
56
|
force_kill(child, child_pgid)
|
56
57
|
else:
|
57
|
-
|
58
|
+
print(f"forward signal {sig} to {child.pid}")
|
58
59
|
try:
|
59
60
|
os.kill(child.pid, sig)
|
60
61
|
except ProcessLookupError as e:
|
61
|
-
|
62
|
+
print(str(e))
|
62
63
|
|
63
64
|
for sig in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1, signal.SIGUSR2]:
|
64
65
|
signal.signal(sig, handle_signal)
|
@@ -110,15 +111,20 @@ class Host:
|
|
110
111
|
|
111
112
|
|
112
113
|
class RemoteExecutor:
|
113
|
-
def __init__(self, host: Host, command: list[str]):
|
114
|
+
def __init__(self, host: Host, command: list[str], envs: dict | None = None):
|
114
115
|
self.host = host
|
115
116
|
self.command = command
|
116
117
|
self.envs = {}
|
118
|
+
if envs:
|
119
|
+
for k, v in envs.items():
|
120
|
+
if not re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", k):
|
121
|
+
raise ValueError(f"invalid env name: {k!r}")
|
122
|
+
self.envs[k] = v
|
117
123
|
self.process = None
|
118
124
|
|
119
125
|
@classmethod
|
120
126
|
def make_ssh_cmd(cls, host: Host, cmd: str):
|
121
|
-
opts = ["/usr/bin/env", "ssh", "-
|
127
|
+
opts = ["/usr/bin/env", "ssh", "-T", "-oStrictHostKeyChecking=no"]
|
122
128
|
if host.config_file is not None:
|
123
129
|
opts.append(f"-F{host.config_file}")
|
124
130
|
if host.User is not None:
|
@@ -134,6 +140,7 @@ class RemoteExecutor:
|
|
134
140
|
return opts
|
135
141
|
|
136
142
|
def start(self):
|
143
|
+
assert self.process is None
|
137
144
|
code = pathlib.Path(__file__).read_text().split("# ----- remote_head end ----- #")[0].strip()
|
138
145
|
remote_cmd = shlex.join(
|
139
146
|
[
|
@@ -185,15 +192,19 @@ class RemoteExecutor:
|
|
185
192
|
e.envs["RANK"] = str(i)
|
186
193
|
|
187
194
|
def send_signal(self, sig):
|
188
|
-
|
195
|
+
assert self.process is not None
|
196
|
+
if self.process.poll() is None and self.process.stdin and not self.process.stdin.closed:
|
189
197
|
sig_name = signal.Signals(sig).name
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
198
|
+
log(f"writing to stdin: SIGNAL {sig_name}")
|
199
|
+
try:
|
200
|
+
self.process.stdin.write(f"SIGNAL {sig_name}\n".encode())
|
201
|
+
self.process.stdin.flush()
|
202
|
+
except (BrokenPipeError, OSError) as e:
|
203
|
+
log(e)
|
204
|
+
|
205
|
+
def poll(self):
|
206
|
+
assert self.process is not None
|
207
|
+
return self.process.poll()
|
197
208
|
|
198
209
|
|
199
210
|
def signal_repeat_checker(sig_to_check, count, duration):
|
@@ -223,6 +234,7 @@ def main():
|
|
223
234
|
parser.add_argument("-l", type=str, help="ssh login User")
|
224
235
|
parser.add_argument("-o", type=str, action="append", help="ssh options")
|
225
236
|
parser.add_argument("-F", type=str, help="ssh config file")
|
237
|
+
parser.add_argument("-e", "--env", type=str, action="append", help="extra envs")
|
226
238
|
parser.add_argument("--hosts-config", type=str, action="append", help="hosts config string. order is 2")
|
227
239
|
parser.add_argument("--hosts-config-file", type=str, action="append", help="hosts config file. order is 3")
|
228
240
|
parser.add_argument("--help", action="help", default=argparse.SUPPRESS, help="show this help message and exit")
|
@@ -263,7 +275,15 @@ def main():
|
|
263
275
|
parser.print_help()
|
264
276
|
sys.exit(1)
|
265
277
|
|
266
|
-
|
278
|
+
envs = {}
|
279
|
+
if args.env:
|
280
|
+
for e in args.env:
|
281
|
+
p = e.split("=", 1)
|
282
|
+
if len(p) == 1:
|
283
|
+
p.append("")
|
284
|
+
envs[p[0]] = p[1]
|
285
|
+
|
286
|
+
executors = [RemoteExecutor(host, args.cmd, envs) for host in hosts]
|
267
287
|
|
268
288
|
RemoteExecutor.set_envs(executors)
|
269
289
|
|
@@ -284,7 +304,7 @@ def main():
|
|
284
304
|
for sig in [signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1, signal.SIGUSR2]:
|
285
305
|
signal.signal(sig, handle_signal)
|
286
306
|
|
287
|
-
while any(e.
|
307
|
+
while any([e.poll() is None for e in executors if e.process]):
|
288
308
|
time.sleep(0.5)
|
289
309
|
log("finished")
|
290
310
|
|
ladyrick/cli/test_signal.py
CHANGED
@@ -5,8 +5,8 @@ import time
|
|
5
5
|
|
6
6
|
def handle_signal(sig, frame):
|
7
7
|
print(f"received signal {sig}, {signal.Signals(sig).name}", flush=True)
|
8
|
-
if sig in {signal.SIGTERM, signal.SIGINT, signal.SIGHUP}:
|
9
|
-
sys.exit(0)
|
8
|
+
# if sig in {signal.SIGTERM, signal.SIGINT, signal.SIGHUP}:
|
9
|
+
# sys.exit(0)
|
10
10
|
|
11
11
|
|
12
12
|
for sig in [s for s in vars(signal).values() if isinstance(s, signal.Signals)]:
|
@@ -9,21 +9,21 @@ ladyrick/torch.py,sha256=CEdHYaOZ00StZettf4MoIB3tMF0fbzSIH-3pOqOMIZM,1977
|
|
9
9
|
ladyrick/typing.py,sha256=YQeApe63dk7yL4NS5ytlR6v3dLCii2-qsXNlUvjK-zw,203
|
10
10
|
ladyrick/utils.py,sha256=jRRaqC6kNbCJPGeE0YisFgis-wiuINLik1mcUQtytow,608
|
11
11
|
ladyrick/vars.py,sha256=VbFh2u7XybUaBuiYEXBa4sOmoS99vc2AIXdYLBh8vjk,3763
|
12
|
-
ladyrick/cli/calc.py,sha256=
|
13
|
-
ladyrick/cli/multi_ssh.py,sha256=
|
12
|
+
ladyrick/cli/calc.py,sha256=5_UhSSaL_K9FBCHg3zuCk41CHJXy3QAh__qCabbffQY,1438
|
13
|
+
ladyrick/cli/multi_ssh.py,sha256=02DmcotlKGlaAEIgIi5KsnjBxkNnf60OiimpH20JfYU,9903
|
14
14
|
ladyrick/cli/psf.py,sha256=JLk3gbPn7E3uuPBbzGvLgJmFQlilA6zg_Xlg7xW5jik,1146
|
15
15
|
ladyrick/cli/tee.py,sha256=UMJxSJLOEfbV43auVKRTIJ5ZAMAkAfj8byiFLk5PUHE,3579
|
16
16
|
ladyrick/cli/test_args.py,sha256=f5sUPDlcf6nbNf6UfLwZQI5g5LN8wlFBQZ10GLw22cg,212
|
17
|
-
ladyrick/cli/test_signal.py,sha256=
|
17
|
+
ladyrick/cli/test_signal.py,sha256=zGPGMR81j1_vNyGEAcRtO2WjhDXiCj2xHMDATk-Z33M,494
|
18
18
|
ladyrick/patch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
ladyrick/patch/print.py,sha256=Ks_ONpeLOyC9pFKLmAiNliwGPbJyt9qz-cnRUPVto34,845
|
20
20
|
ladyrick/patch/rich_print.py,sha256=z3Ea1VCunXZvNvEDFHpoyWc8ydINmh-gOIJ1ssscs6s,841
|
21
21
|
ladyrick/patch/python/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
ladyrick/patch/python/__main__.py,sha256=BAGy1phd26WWcGM9TKHbqIpeZliVofopBndtMIPtDQ0,651
|
23
23
|
ladyrick/patch/python/usercustomize.py,sha256=8mYpcZ8p-l41fiSJue727n8cAmcEmUktObDYZDdLJfs,218
|
24
|
-
ladyrick-0.5.
|
25
|
-
ladyrick-0.5.
|
26
|
-
ladyrick-0.5.
|
27
|
-
ladyrick-0.5.
|
28
|
-
ladyrick-0.5.
|
29
|
-
ladyrick-0.5.
|
24
|
+
ladyrick-0.5.5.dist-info/licenses/LICENSE,sha256=EeNAFxYAOYEmo2YEM7Zk5Oknq4RI0XMAbk4Rgoem6fs,1065
|
25
|
+
ladyrick-0.5.5.dist-info/METADATA,sha256=5F-dTbYGPoApk--A2gPS5cS_Ev4f3WRRRLKbPrYq4S8,883
|
26
|
+
ladyrick-0.5.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
27
|
+
ladyrick-0.5.5.dist-info/entry_points.txt,sha256=28kidI1OCOAi7S1aHBr8veak49VNZ0tWFvf-Ty8UmSU,225
|
28
|
+
ladyrick-0.5.5.dist-info/top_level.txt,sha256=RIC3-Jty2qzLYXSOr7fOu1loTwlMU9cF6MFeGIROxWU,9
|
29
|
+
ladyrick-0.5.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|