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 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
 
@@ -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(base_path, path)
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(get_source(workflow, state_path),
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(get_source(workflow, state_path),
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(get_source(workflow, state_path),
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
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
- def run_detached_with_terminal(executable_path):
8
+
9
+ def run_detached(executable_path):
6
10
  """
7
- 启动可执行文件并在新终端窗口中保持运行,Python退出后进程仍存在。
8
- 适用于Windows、Linux和macOS
11
+ 启动可执行文件并完全分离(优先用 tmux/screen),无需额外终端窗口
12
+ 支持 Windows、Linux macOS
9
13
  """
10
14
  try:
11
- if sys.platform == 'win32':
12
- # Windows:使用start命令启动新cmd窗口
13
- cmd = f'start cmd /k "{executable_path}"'
14
- subprocess.Popen(cmd, shell=True)
15
- elif sys.platform == 'darwin':
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
- print(f"启动失败: {e}")
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.16"
1
+ __version__ = "2.7.18"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: QuLab
3
- Version: 2.7.16
3
+ Version: 2.7.18
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -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=JCQ2rLFk2ELyIg15WQ6Z6a7-hAof91FLK5kLUjoRxzQ,126848
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=JIXMSmZU0uYfKG_tzawpK7vRNPRir_hJE8JlqkVLX2o,1260
7
- qulab/version.py,sha256=FfSt311ISmWzNzgm6bVcGXURtNc74jJ8EU8zuODbm0g,22
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=_Zn4wtGGD8pBZwOfbJaaFVAr8riY2Bkhi67lX9Jy-hA,17427
14
- qulab/executor/schedule.py,sha256=9pTOVWzKiDc7ip8iuB_47poJcYOvoBI9eQwTrDTA3p0,19044
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.16.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
101
- qulab-2.7.16.dist-info/METADATA,sha256=K-ApF5W09-9zYNdNKbUYx9dMa4C1vGko8TEL7FeLu2o,3699
102
- qulab-2.7.16.dist-info/WHEEL,sha256=3QhfJdMl2SQHlMx8m8VZoG83oHO8482SzgXD2zX_lT4,114
103
- qulab-2.7.16.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
104
- qulab-2.7.16.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
105
- qulab-2.7.16.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp311-cp311-macosx_10_9_universal2
5
5