QuLab 2.7.16__cp311-cp311-macosx_10_9_universal2.whl → 2.7.18__cp311-cp311-macosx_10_9_universal2.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.
- qulab/executor/load.py +13 -0
- qulab/executor/schedule.py +4 -17
- qulab/fun.cpython-311-darwin.so +0 -0
- qulab/utils.py +86 -22
- qulab/version.py +1 -1
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/METADATA +1 -1
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/RECORD +11 -11
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/WHEEL +1 -1
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/LICENSE +0 -0
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/entry_points.txt +0 -0
- {qulab-2.7.16.dist-info → qulab-2.7.18.dist-info}/top_level.txt +0 -0
qulab/executor/load.py
CHANGED
@@ -17,6 +17,7 @@ from .template import (TemplateKeyError, TemplateTypeError, decode_mapping,
|
|
17
17
|
class SetConfigWorkflow():
|
18
18
|
__timeout__ = None
|
19
19
|
__mtime__ = 0
|
20
|
+
__source__ = ''
|
20
21
|
|
21
22
|
def __init__(self, key):
|
22
23
|
self.key = key
|
@@ -80,6 +81,16 @@ class SetConfigWorkflow():
|
|
80
81
|
WorkflowType = ModuleType | SetConfigWorkflow
|
81
82
|
|
82
83
|
|
84
|
+
def get_source(workflow: WorkflowType, code_path: str | Path) -> str:
|
85
|
+
if isinstance(code_path, str):
|
86
|
+
code_path = Path(code_path)
|
87
|
+
try:
|
88
|
+
with open(code_path / workflow.__workflow_id__, 'r') as f:
|
89
|
+
return f.read()
|
90
|
+
except:
|
91
|
+
return ''
|
92
|
+
|
93
|
+
|
83
94
|
def can_call_without_args(func):
|
84
95
|
if not callable(func):
|
85
96
|
return False
|
@@ -411,6 +422,8 @@ def load_workflow(workflow: str | tuple[str, dict],
|
|
411
422
|
w.__workflow_id__ = str(Path(w.__file__).relative_to(base_path))
|
412
423
|
else:
|
413
424
|
raise TypeError(f"Invalid workflow: {workflow}")
|
425
|
+
|
426
|
+
w.__source__ = get_source(w, base_path)
|
414
427
|
|
415
428
|
return w
|
416
429
|
|
qulab/executor/schedule.py
CHANGED
@@ -38,7 +38,7 @@ def get_cache(session_id, key) -> Report:
|
|
38
38
|
return None
|
39
39
|
if isinstance(index, tuple):
|
40
40
|
base_path, path = index
|
41
|
-
return load_report(
|
41
|
+
return load_report(path, base_path)
|
42
42
|
elif isinstance(index, Report):
|
43
43
|
return index
|
44
44
|
else:
|
@@ -70,16 +70,6 @@ def veryfy_analyzed_report(report: Report, script: str, method: str):
|
|
70
70
|
)
|
71
71
|
|
72
72
|
|
73
|
-
def get_source(workflow: WorkflowType, code_path: str | Path) -> str:
|
74
|
-
if isinstance(code_path, str):
|
75
|
-
code_path = Path(code_path)
|
76
|
-
try:
|
77
|
-
with open(code_path / workflow.__workflow_id__, 'r') as f:
|
78
|
-
return f.read()
|
79
|
-
except:
|
80
|
-
return ''
|
81
|
-
|
82
|
-
|
83
73
|
def check_state(workflow: WorkflowType, code_path: str | Path,
|
84
74
|
state_path: str | Path) -> bool:
|
85
75
|
"""
|
@@ -160,8 +150,7 @@ def call_check(workflow: WorkflowType, session_id: str, state_path: Path):
|
|
160
150
|
heads=get_heads(state_path),
|
161
151
|
previous_path=get_head(workflow.__workflow_id__,
|
162
152
|
state_path),
|
163
|
-
script_path=save_item(
|
164
|
-
state_path))
|
153
|
+
script_path=save_item(workflow.__source__, state_path))
|
165
154
|
|
166
155
|
save_report(workflow.__workflow_id__, report, state_path)
|
167
156
|
|
@@ -187,8 +176,7 @@ def call_calibrate(workflow: WorkflowType, session_id: str, state_path: Path):
|
|
187
176
|
heads=get_heads(state_path),
|
188
177
|
previous_path=get_head(workflow.__workflow_id__,
|
189
178
|
state_path),
|
190
|
-
script_path=save_item(
|
191
|
-
state_path))
|
179
|
+
script_path=save_item(workflow.__source__, state_path))
|
192
180
|
|
193
181
|
save_report(workflow.__workflow_id__, report, state_path)
|
194
182
|
|
@@ -286,8 +274,7 @@ def check_data(workflow: WorkflowType, state_path: str | Path, plot: bool,
|
|
286
274
|
heads=get_heads(state_path),
|
287
275
|
previous_path=get_head(workflow.__workflow_id__,
|
288
276
|
state_path),
|
289
|
-
script_path=save_item(
|
290
|
-
state_path))
|
277
|
+
script_path=save_item(workflow.__source__, state_path))
|
291
278
|
report.in_spec = False
|
292
279
|
report.bad_data = False
|
293
280
|
return report
|
qulab/fun.cpython-311-darwin.so
CHANGED
Binary file
|
qulab/utils.py
CHANGED
@@ -1,31 +1,95 @@
|
|
1
|
+
import shlex
|
1
2
|
import subprocess
|
2
3
|
import sys
|
4
|
+
import time
|
3
5
|
|
6
|
+
import click
|
4
7
|
|
5
|
-
|
8
|
+
|
9
|
+
def run_detached(executable_path):
|
6
10
|
"""
|
7
|
-
|
8
|
-
|
11
|
+
启动可执行文件并完全分离(优先用 tmux/screen),无需额外终端窗口
|
12
|
+
支持 Windows、Linux 和 macOS
|
9
13
|
"""
|
10
14
|
try:
|
11
|
-
if sys.platform == 'win32'
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# macOS:通过AppleScript在Terminal中执行命令
|
17
|
-
escaped_path = executable_path.replace('"', r'\"')
|
18
|
-
script = f'tell application "Terminal" to do script "{escaped_path}"'
|
19
|
-
subprocess.Popen(['osascript', '-e', script],
|
20
|
-
start_new_session=True)
|
21
|
-
else:
|
22
|
-
# Linux:尝试gnome-terminal或xterm
|
23
|
-
try:
|
24
|
-
subprocess.Popen(['gnome-terminal', '--', executable_path],
|
25
|
-
start_new_session=True)
|
26
|
-
except FileNotFoundError:
|
27
|
-
subprocess.Popen(['xterm', '-e', executable_path],
|
28
|
-
start_new_session=True)
|
15
|
+
if sys.platform == 'win32' or not _unix_detach_with_tmux_or_screen(
|
16
|
+
executable_path):
|
17
|
+
# 回退到带终端窗口的方案
|
18
|
+
run_detached_with_terminal(executable_path)
|
19
|
+
|
29
20
|
except Exception as e:
|
30
|
-
|
21
|
+
click.echo(f"启动失败: {e}")
|
31
22
|
sys.exit(1)
|
23
|
+
|
24
|
+
|
25
|
+
def _windows_start(executable_path):
|
26
|
+
"""Windows 弹窗启动方案"""
|
27
|
+
subprocess.Popen(f'start cmd /k "{executable_path}"',
|
28
|
+
shell=True,
|
29
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
|
30
|
+
|
31
|
+
|
32
|
+
def _unix_detach_with_tmux_or_screen(executable_path):
|
33
|
+
"""Unix 后台分离方案(无窗口)"""
|
34
|
+
safe_path = shlex.quote(executable_path)
|
35
|
+
session_name = f"qulab_{int(time.time())}"
|
36
|
+
|
37
|
+
# 尝试 tmux
|
38
|
+
if _check_command_exists("tmux"):
|
39
|
+
command = [
|
40
|
+
"tmux",
|
41
|
+
"new-session",
|
42
|
+
"-d",
|
43
|
+
"-s",
|
44
|
+
session_name,
|
45
|
+
safe_path + " ; tmux wait-for -S finished", # 等待命令结束
|
46
|
+
";",
|
47
|
+
"tmux",
|
48
|
+
"wait-for",
|
49
|
+
"finished" # 防止进程立即退出
|
50
|
+
]
|
51
|
+
subprocess.Popen(" ".join(command), shell=True, start_new_session=True)
|
52
|
+
click.echo(f"已启动 tmux 会话: {session_name}")
|
53
|
+
click.echo(f"你可以使用 `tmux attach -t {session_name}` 来查看输出")
|
54
|
+
return True
|
55
|
+
|
56
|
+
# 尝试 screen
|
57
|
+
elif _check_command_exists("screen"):
|
58
|
+
command = ["screen", "-dmS", session_name, safe_path]
|
59
|
+
subprocess.Popen(command, start_new_session=True)
|
60
|
+
click.echo(f"已启动 screen 会话: {session_name}")
|
61
|
+
click.echo(f"你可以使用 `screen -r {session_name}` 来查看输出")
|
62
|
+
return True
|
63
|
+
|
64
|
+
return False
|
65
|
+
|
66
|
+
|
67
|
+
def run_detached_with_terminal(executable_path):
|
68
|
+
"""回退到带终端窗口的方案"""
|
69
|
+
safe_path = shlex.quote(executable_path)
|
70
|
+
if sys.platform == 'win32':
|
71
|
+
_windows_start(executable_path)
|
72
|
+
elif sys.platform == 'darwin':
|
73
|
+
script = f'tell app "Terminal" to do script "{safe_path}"'
|
74
|
+
subprocess.Popen(["osascript", "-e", script], start_new_session=True)
|
75
|
+
else:
|
76
|
+
try:
|
77
|
+
subprocess.Popen(["gnome-terminal", "--", "sh", "-c", safe_path],
|
78
|
+
start_new_session=True)
|
79
|
+
except FileNotFoundError:
|
80
|
+
subprocess.Popen(["xterm", "-e", safe_path],
|
81
|
+
start_new_session=True)
|
82
|
+
|
83
|
+
|
84
|
+
def _check_command_exists(cmd):
|
85
|
+
"""检查命令行工具是否存在"""
|
86
|
+
try:
|
87
|
+
subprocess.check_output(["which", cmd], stderr=subprocess.DEVNULL)
|
88
|
+
return True
|
89
|
+
except:
|
90
|
+
return False
|
91
|
+
|
92
|
+
|
93
|
+
# 示例用法
|
94
|
+
if __name__ == '__main__':
|
95
|
+
run_detached("/path/to/your/program")
|
qulab/version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "2.7.
|
1
|
+
__version__ = "2.7.18"
|
@@ -1,17 +1,17 @@
|
|
1
1
|
qulab/__init__.py,sha256=KJcUcZ5qXY6wlAoirzK_B-dgtDjsLmOE671v3gcXO_c,286
|
2
2
|
qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
|
3
3
|
qulab/dicttree.py,sha256=tRRMpGZYVOLw0TEByE3_2Ss8FdOmzuGL9e1DWbs8qoY,13684
|
4
|
-
qulab/fun.cpython-311-darwin.so,sha256=
|
4
|
+
qulab/fun.cpython-311-darwin.so,sha256=Rsl184j7u3zHHDK_068KUZjr9o-xUAh521kwLtSMK0g,126848
|
5
5
|
qulab/typing.py,sha256=vg62sGqxuD9CI5677ejlzAmf2fVdAESZCQjAE_xSxPg,69
|
6
|
-
qulab/utils.py,sha256=
|
7
|
-
qulab/version.py,sha256=
|
6
|
+
qulab/utils.py,sha256=_0gm0sHwwIhk0tYRCLu4oNaS6Tt8meGWt6byu7Kk95Y,2993
|
7
|
+
qulab/version.py,sha256=xLneP_cqIForMj5AICyQrp13un8yGC7zOY4cjyKywXk,22
|
8
8
|
qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
qulab/cli/commands.py,sha256=tgDIkkeIoasQXAifJZ6NU8jDgpNgb2a-B0C4nF0evrE,559
|
10
10
|
qulab/cli/config.py,sha256=Ei7eSYnbwPPlluDnm8YmWONYiI4g7WtvlZGQdr1Z6vo,3688
|
11
11
|
qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
|
12
12
|
qulab/executor/cli.py,sha256=z8W1RivKdABQSOGy2viNUvG73QvOBpE9gSKjw45vSVA,9794
|
13
|
-
qulab/executor/load.py,sha256=
|
14
|
-
qulab/executor/schedule.py,sha256=
|
13
|
+
qulab/executor/load.py,sha256=omD2aklKZnHOosahI-Vs6sQkGdn4U9PgnDIAbrEOhi0,17786
|
14
|
+
qulab/executor/schedule.py,sha256=0BV5LGxhqdIlGwW6-o5_5mljAtdtL1La8EDNBFi8pzU,18585
|
15
15
|
qulab/executor/storage.py,sha256=gI6g28BmKKEZ_Pl-hFwvpiOj3mF8Su-yjj3hfMXs1VY,11630
|
16
16
|
qulab/executor/template.py,sha256=1c7xd0U82fLaqb8O0NQIVVd7aRLuCZNT11-heFw2n9Q,7540
|
17
17
|
qulab/executor/transform.py,sha256=BDx0c4nqTHMAOLVqju0Ydd91uxNm6EpVIfssjZse0bI,2284
|
@@ -97,9 +97,9 @@ qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2ca
|
|
97
97
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
98
98
|
qulab/visualization/rot3d.py,sha256=lMrEJlRLwYe6NMBlGkKYpp_V9CTipOAuDy6QW_cQK00,734
|
99
99
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
100
|
-
qulab-2.7.
|
101
|
-
qulab-2.7.
|
102
|
-
qulab-2.7.
|
103
|
-
qulab-2.7.
|
104
|
-
qulab-2.7.
|
105
|
-
qulab-2.7.
|
100
|
+
qulab-2.7.18.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
101
|
+
qulab-2.7.18.dist-info/METADATA,sha256=rp74Kor5oIm4kmZLnVjpvrmHiNu5K113K9vjiSBmkPU,3699
|
102
|
+
qulab-2.7.18.dist-info/WHEEL,sha256=HdQtkse3c2zEdjkI-KgXULFWgn0ui7rmMwJpV_Mja6w,114
|
103
|
+
qulab-2.7.18.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
|
104
|
+
qulab-2.7.18.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
105
|
+
qulab-2.7.18.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|