QuLab 2.11.16__py3-none-any.whl → 2.12.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.
qulab/cli/commands.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import click
2
2
 
3
- from ..executor.cli import (boot, create, export, get, load, maintain, delete,
4
- reproduce, run, set)
3
+ from ..executor.cli import (boot, create, delete, export, get, load, maintain,
4
+ reboot, reproduce, run, set)
5
5
  from ..monitor.__main__ import main as monitor
6
6
  from ..scan.server import server
7
7
  from ..sys.net.cli import dht
@@ -39,3 +39,4 @@ reg.add_command(delete)
39
39
  reg.add_command(load)
40
40
  reg.add_command(export)
41
41
  cli.add_command(boot)
42
+ cli.add_command(reboot)
qulab/executor/cli.py CHANGED
@@ -24,7 +24,7 @@ from .utils import workflow_template
24
24
 
25
25
 
26
26
  @logger.catch(reraise=True)
27
- def run_script(script_path, extra_paths=None):
27
+ def run_script(script_path, args=(), extra_paths=None):
28
28
  """Run a script in a new process, inheriting current PYTHONPATH plus any extra paths.
29
29
 
30
30
  Args:
@@ -35,7 +35,7 @@ def run_script(script_path, extra_paths=None):
35
35
  import sys
36
36
 
37
37
  # Launch the new process with the modified environment
38
- proc = subprocess.Popen([sys.executable, script_path],
38
+ proc = subprocess.Popen([sys.executable, script_path, *args],
39
39
  env=combined_env(extra_paths))
40
40
  proc.communicate()
41
41
 
@@ -370,6 +370,23 @@ def boot(bootstrap):
370
370
  run_script(bootstrap)
371
371
 
372
372
 
373
+ @click.command()
374
+ @click.option('--bootstrap',
375
+ '-b',
376
+ default=lambda: get_config_value("bootstrap", Path),
377
+ help='The path of the bootstrap.')
378
+ def reboot(bootstrap):
379
+ """Reboot the executor.
380
+
381
+ Reboots the executor to reset the state and start fresh.
382
+
383
+ Args:
384
+ bootstrap: Path to the bootstrap script
385
+ """
386
+ if bootstrap is not None:
387
+ run_script(bootstrap, args=('--reboot',))
388
+
389
+
373
390
  def parse_dynamic_option_value(value):
374
391
  """解析动态参数值"""
375
392
  try:
qulab/utils.py CHANGED
@@ -24,33 +24,36 @@ def combined_env(extra_paths=None):
24
24
  return env
25
25
 
26
26
 
27
- def run_detached(script, env=None):
27
+ def run_detached(script, env=None, cwd=None):
28
28
  """
29
29
  启动可执行文件并完全分离(优先用 tmux/screen),无需额外终端窗口
30
30
  支持 Windows、Linux 和 macOS
31
31
  """
32
32
  if env is None:
33
33
  env = combined_env()
34
+ if cwd is None:
35
+ cwd = os.getcwd()
34
36
  try:
35
37
  if sys.platform == 'win32' or not _unix_detach_with_tmux_or_screen(
36
- script, env):
38
+ script, env, cwd):
37
39
  # 回退到带终端窗口的方案
38
- run_detached_with_terminal(script, env)
40
+ run_detached_with_terminal(script, env, cwd)
39
41
 
40
42
  except Exception as e:
41
43
  click.echo(f"启动失败: {e}")
42
44
  sys.exit(1)
43
45
 
44
46
 
45
- def _windows_start(script, env):
47
+ def _windows_start(script, env, cwd):
46
48
  """Windows 弹窗启动方案"""
47
49
  subprocess.Popen(f'start cmd /k "{script}"',
48
50
  shell=True,
49
51
  env=env,
52
+ cwd=cwd,
50
53
  creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
51
54
 
52
55
 
53
- def _unix_detach_with_tmux_or_screen(script, env):
56
+ def _unix_detach_with_tmux_or_screen(script, env, cwd):
54
57
  """Unix 后台分离方案(无窗口)"""
55
58
  safe_path = shlex.quote(script)
56
59
  session_name = f"qulab_{int(time.time())}"
@@ -63,7 +66,7 @@ def _unix_detach_with_tmux_or_screen(script, env):
63
66
  "-d",
64
67
  "-s",
65
68
  session_name,
66
- script + " ; tmux wait-for -S finished", # 等待命令结束
69
+ f"cd {shlex.quote(cwd)} && {script} ; tmux wait-for -S finished", # 等待命令结束
67
70
  ";",
68
71
  "tmux",
69
72
  "wait-for",
@@ -72,6 +75,7 @@ def _unix_detach_with_tmux_or_screen(script, env):
72
75
  subprocess.Popen(" ".join(command),
73
76
  shell=True,
74
77
  env=env,
78
+ cwd=cwd,
75
79
  start_new_session=True)
76
80
  click.echo(f"已启动 tmux 会话: {session_name}")
77
81
  click.echo(f"你可以使用 `tmux attach -t {session_name}` 来查看输出")
@@ -79,8 +83,11 @@ def _unix_detach_with_tmux_or_screen(script, env):
79
83
 
80
84
  # 尝试 screen
81
85
  elif _check_command_exists("screen", env):
82
- command = ["screen", "-dmS", session_name, script]
83
- subprocess.Popen(command, env=env, start_new_session=True)
86
+ command = [
87
+ "screen", "-dmS", session_name, "sh", "-c",
88
+ f"cd {shlex.quote(cwd)} && {script}"
89
+ ]
90
+ subprocess.Popen(command, env=env, cwd=cwd, start_new_session=True)
84
91
  click.echo(f"已启动 screen 会话: {session_name}")
85
92
  click.echo(f"你可以使用 `screen -r {session_name}` 来查看输出")
86
93
  return True
@@ -88,29 +95,37 @@ def _unix_detach_with_tmux_or_screen(script, env):
88
95
  return False
89
96
 
90
97
 
91
- def run_detached_with_terminal(script, env=None):
98
+ def run_detached_with_terminal(script, env=None, cwd=None):
92
99
  """回退到带终端窗口的方案"""
93
100
  if env is None:
94
101
  env = combined_env()
102
+ if cwd is None:
103
+ cwd = os.getcwd()
95
104
 
96
105
  if sys.platform == 'win32':
97
- _windows_start(script, env)
106
+ _windows_start(script, env, cwd)
98
107
  elif sys.platform == 'darwin':
99
108
  # script=shlex.quote(script)
100
- script = f'tell app "Terminal" to do script "{script}"'
101
- subprocess.Popen(["osascript", "-e", script],
109
+ terminal_script = f'tell app "Terminal" to do script "cd {shlex.quote(cwd)} && {script}"'
110
+ subprocess.Popen(["osascript", "-e", terminal_script],
102
111
  env=env,
112
+ cwd=cwd,
103
113
  start_new_session=True)
104
114
  else:
105
115
  try:
116
+ subprocess.Popen([
117
+ "gnome-terminal", "--", "sh", "-c",
118
+ f"cd {shlex.quote(cwd)} && {script}"
119
+ ],
120
+ env=env,
121
+ cwd=cwd,
122
+ start_new_session=True)
123
+ except FileNotFoundError:
106
124
  subprocess.Popen(
107
- ["gnome-terminal", "--", "sh", "-c", script],
125
+ ["xterm", "-e", f"sh -c 'cd {shlex.quote(cwd)} && {script}'"],
108
126
  env=env,
127
+ cwd=cwd,
109
128
  start_new_session=True)
110
- except FileNotFoundError:
111
- subprocess.Popen(["xterm", "-e", script],
112
- env=env,
113
- start_new_session=True)
114
129
 
115
130
 
116
131
  def _check_command_exists(cmd, env):
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.11.16"
1
+ __version__ = "2.12.1"
@@ -54,6 +54,85 @@ def complete_layout(layout):
54
54
  return layout
55
55
 
56
56
 
57
+ def read_xlsx_to_dict(filepath: str,
58
+ key_col: int = 0,
59
+ value_col: int = 4,
60
+ sheet_name: str = 0) -> dict:
61
+ """
62
+ 读取 .xlsx 文件,将第 key_col 列和第 value_col 列的值分别作为 key、value,返回一个字典。
63
+
64
+ :param filepath: Excel 文件路径
65
+ :param key_col: 用作字典键的列索引(0 表示第一列)
66
+ :param value_col: 用作字典值的列索引(0 表示第一列)
67
+ :param sheet_name: 要读取的 sheet 名称或索引,默认第一个 sheet
68
+ :return: { key: value, ... } 形式的字典
69
+ """
70
+ import pandas as pd
71
+
72
+ # 读取整个表格
73
+ # df = pd.read_excel(filepath, sheet_name=sheet_name, header=None)
74
+ df = pd.read_excel(filepath, sheet_name=sheet_name)
75
+
76
+ # 提取指定列,生成键值对并返回字典
77
+ keys = df.iloc[:, key_col]
78
+ values = df.iloc[:, value_col]
79
+ return dict(zip(keys, values))
80
+
81
+
82
+ def load_layout_from_xlsx(qubit_info, coupler_info, pad_info):
83
+ """
84
+ 从 .xlsx 文件中加载布局信息。
85
+
86
+ :param qubit_info: 量子比特信息文件路径
87
+ :param coupler_info: 耦合器信息文件路径
88
+ :param pad_info: 垫片信息文件路径
89
+ :return: 布局信息
90
+ """
91
+ import pandas as pd
92
+
93
+ _qubits = {}
94
+
95
+ qubit_pad = read_xlsx_to_dict(qubit_info, value_col=4)
96
+ coupler_pad = read_xlsx_to_dict(coupler_info, value_col=3)
97
+ pads = {
98
+ v: k
99
+ for k, v in qubit_pad.items()
100
+ } | {
101
+ v: k
102
+ for k, v in coupler_pad.items()
103
+ }
104
+ pad_info = read_xlsx_to_dict(pad_info, value_col=2)
105
+
106
+ lyt = {'qubits': {}, 'couplers': {}, 'feedlines': {}}
107
+
108
+ for pad, script in pad_info.items():
109
+ info = eval(script)
110
+ match info['style']:
111
+ case 'Q':
112
+ qubit = pads[pad]
113
+ lyt['qubits'][qubit] = {'pos': info['qb'], 'pad': pad}
114
+ _qubits[info['qb']] = qubit
115
+ case 'C':
116
+ coupler = pads[pad]
117
+ if 'cpl' in info:
118
+ pos = tuple(info['cpl'])
119
+ else:
120
+ pos = tuple(info['qb'])
121
+ lyt['couplers'][coupler] = {'qubits': pos, 'pad': pad}
122
+ case 'TL':
123
+ l = info['tl']
124
+ if f"T{l}" in lyt['feedlines']:
125
+ lyt['feedlines'][f"T{l}"]['pads'].append(pad)
126
+ else:
127
+ lyt['feedlines'][f"T{l}"] = {'pads': [pad]}
128
+
129
+ for coupler in lyt['couplers']:
130
+ qubits = lyt['couplers'][coupler]['qubits']
131
+ lyt['couplers'][coupler]['qubits'] = [_qubits[p] for p in qubits]
132
+
133
+ return complete_layout(lyt)
134
+
135
+
57
136
  def get_shared_coupler(layout, q1, q2):
58
137
  for c in layout['qubits'][q1]['couplers']:
59
138
  if q2 in layout['couplers'][c]['qubits']:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuLab
3
- Version: 2.11.16
3
+ Version: 2.12.1
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,15 +1,15 @@
1
1
  qulab/__init__.py,sha256=ijh3NWuSCU_KWRrPfddX4vfPcYPmvKs64vSTl9qd-SU,2178
2
2
  qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
3
3
  qulab/typing.py,sha256=vg62sGqxuD9CI5677ejlzAmf2fVdAESZCQjAE_xSxPg,69
4
- qulab/utils.py,sha256=B_8QdY9OMY7WU-F200v93BDJXJpQcKAHihnOXeEvv_w,3966
5
- qulab/version.py,sha256=z1ogNWpE3sfhj8z_vJdEtWVUcmSF3lOrnReD_efKPwM,23
4
+ qulab/utils.py,sha256=0mOSj6bGMgT5BhPgQQzekx5aVBuidxXE3kLumJJaLgc,4531
5
+ qulab/version.py,sha256=xzXXyb4Cc2u5EWdM4fbKSvettwA_bB9v3W1WNfmB8aI,22
6
6
  qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- qulab/cli/commands.py,sha256=ywKmwbGNBCVASx8OsgrRttaLz9ogwY38ZdKj7I-tdJ4,813
7
+ qulab/cli/commands.py,sha256=dr9vlQaTrsXw2Fqra713XquS4m3am_XNHt0BWC7J3yo,845
8
8
  qulab/cli/config.py,sha256=Z-lePcDMeeQmwFpdfQHqZuaXTPhWUHN5KrlSqrya73Y,6324
9
9
  qulab/cli/decorators.py,sha256=oImteZVnDPPWdyhJ4kzf2KYGJLON7VsKGBvZadWLQZo,621
10
10
  qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
11
11
  qulab/executor/analyze.py,sha256=VYTfiOYJe5gDbtGA4wOkrQhhu55iIrRVByx-gBLUUm4,5672
12
- qulab/executor/cli.py,sha256=fTB7V8xNCvpU8EMa__ysBvRCzruP-QFbXOyLpeTPx0E,25711
12
+ qulab/executor/cli.py,sha256=I63KA59Hr4SIVKAXyEAMDPdgANFx88e8F85wRqUai4g,26196
13
13
  qulab/executor/load.py,sha256=eMlzOrrn8GpbP3J3uY5JJ8iO7tL5B1DWP1z2qiGyNhU,20385
14
14
  qulab/executor/registry.py,sha256=yWO6nJ1nMVve_HF5xzSd7QmZEIjoGvD_Txg73_f30gE,9279
15
15
  qulab/executor/schedule.py,sha256=cDFM_tIMvxHLxb-tBA6fEPF9u-4LcgnQDxbaquZIQKc,21727
@@ -91,14 +91,14 @@ qulab/visualization/__init__.py,sha256=26cuHt3QIJXUb3VaMxlJx3IQTOUVJFKlYBZr7WMP5
91
91
  qulab/visualization/__main__.py,sha256=9zKK3yZFy0leU40ou6BpRC1Fsetfc1gjjFzIZYIwP6Y,1639
92
92
  qulab/visualization/_autoplot.py,sha256=2ECb2USU3_MSwo2d8qzMMO4DK9OU1bA6RYr7FCss1D0,14369
93
93
  qulab/visualization/plot_circ.py,sha256=Lxi-Nnik9MBtsNur0iyp9DTdy_IMALRsHBg2hZbPkGc,8769
94
- qulab/visualization/plot_layout.py,sha256=mRHinWX1Iq1qpcZ1OKrtcRoqJuv_a8d2qXrj23MeEjQ,17793
94
+ qulab/visualization/plot_layout.py,sha256=Q8yOGYQ-oOle1W7cN4am9ABI8T-Xtk3W6BEX5bFSeWg,20464
95
95
  qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2calY,6751
96
96
  qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
97
97
  qulab/visualization/rot3d.py,sha256=CuLfG1jw1032HNNZxzC0OWtNzKsbj2e2WRYhMWDgvMQ,1321
98
98
  qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
99
- qulab-2.11.16.dist-info/licenses/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
100
- qulab-2.11.16.dist-info/METADATA,sha256=XXJq2QfRxVsTyN5Szli0eQEIF-xEvr_4U0zsofxCMtc,3945
101
- qulab-2.11.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
102
- qulab-2.11.16.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
103
- qulab-2.11.16.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
104
- qulab-2.11.16.dist-info/RECORD,,
99
+ qulab-2.12.1.dist-info/licenses/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
100
+ qulab-2.12.1.dist-info/METADATA,sha256=3RqnUNugl7OdALKYsY5VQYPdOJgQ5HIlb_2ovOsVCqg,3944
101
+ qulab-2.12.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
102
+ qulab-2.12.1.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
103
+ qulab-2.12.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
104
+ qulab-2.12.1.dist-info/RECORD,,