QuLab 2.9.7__cp310-cp310-macosx_10_9_universal2.whl → 2.9.9__cp310-cp310-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/__init__.py CHANGED
@@ -1,3 +1,4 @@
1
+ from .executor.analyze import manual_analysis
1
2
  from .executor.storage import find_report
2
3
  from .executor.storage import get_report_by_index as get_report
3
4
  from .executor.template import VAR
@@ -0,0 +1,188 @@
1
+ import pickle
2
+ import threading
3
+ import time
4
+
5
+ import pyperclip
6
+ import zmq
7
+
8
+ from .storage import Report
9
+
10
+ # 需要复制到 Notebook 的代码模板
11
+ clip_template = """
12
+ from qulab.executor.analyze import get_report as get_report_{server_port}
13
+
14
+ report, history = get_report_{server_port}("tcp://{server_address}:{server_port}")
15
+ # 在这里插入数据处理逻辑
16
+
17
+ {analysis_code}
18
+ """
19
+
20
+ analysis_code = """
21
+ # report.state = 'OK'
22
+ # report.parameters = {}
23
+ # report.oracle = {}
24
+ # report.other_infomation = {}
25
+
26
+ report.parameters
27
+
28
+ """
29
+
30
+
31
+ # ZeroMQ 服务线程,用于响应 Notebook 的请求
32
+ class ServerThread(threading.Thread):
33
+
34
+ def __init__(self, data, timeout):
35
+ super().__init__()
36
+ self.data = data
37
+ self.result = None
38
+ self.port = 0
39
+ self.timeout = timeout
40
+ self.running = True
41
+ self.finished = threading.Event()
42
+ self.context = zmq.Context()
43
+
44
+ def find_free_port(self):
45
+ with zmq.Socket(self.context, zmq.REQ) as s:
46
+ s.bind_to_random_port("tcp://*")
47
+ self.port = int(
48
+ s.getsockopt(zmq.LAST_ENDPOINT).decode().split(":")[-1])
49
+ s.unbind(s.getsockopt(zmq.LAST_ENDPOINT))
50
+ return self.port
51
+
52
+ def run(self):
53
+ self.port = self.find_free_port()
54
+ socket = self.context.socket(zmq.REP)
55
+ socket.bind(f"tcp://*:{self.port}")
56
+ # 设置 recv 超时 1 秒
57
+ socket.RCVTIMEO = 1000
58
+ start_time = time.time()
59
+ try:
60
+ while self.running and (time.time() - start_time < self.timeout):
61
+ try:
62
+ msg = socket.recv()
63
+ except zmq.Again:
64
+ continue # 超时后继续等待
65
+
66
+ # Notebook 端请求数据
67
+ if msg == b"GET":
68
+ socket.send(pickle.dumps(self.data))
69
+ else:
70
+ # Notebook 端提交了处理结果
71
+ try:
72
+ self.result = pickle.loads(msg)
73
+ except Exception as e:
74
+ # 如果解析失败,也返回默认 ACK
75
+ self.result = None
76
+ socket.send(b"ACK")
77
+ self.running = False
78
+ break
79
+ finally:
80
+ socket.close()
81
+ self.context.term()
82
+ self.finished.set()
83
+
84
+ def stop(self):
85
+ self.running = False
86
+ self.finished.set()
87
+
88
+ def wait_for_result(self):
89
+ self.finished.wait()
90
+ return self.result
91
+
92
+
93
+ # 进入分析流程,启动服务并打印等待提示
94
+ def get_result_or_wait_until_timeout(report: Report, history: Report | None,
95
+ timeout: float) -> Report:
96
+ server = ServerThread((report, history), timeout)
97
+ server.start()
98
+
99
+ parameters = report.parameters
100
+ oracle = report.oracle
101
+ other_infomation = report.other_infomation
102
+ state = report.state
103
+
104
+ # 格式化代码模板
105
+ code = clip_template.format(server_address="127.0.0.1",
106
+ server_port=server.port,
107
+ analysis_code=analysis_code)
108
+
109
+ # 将代码复制到剪切板
110
+ pyperclip.copy(code)
111
+
112
+ # 同时打印到终端,防止误操作导致剪切板内容丢失
113
+ print("请在 Jupyter Notebook 中运行下面这段代码:")
114
+ print("-" * 60)
115
+ print(code)
116
+ print("-" * 60)
117
+ print("等待 Notebook 提交处理结果,或等待超时({} 秒)...".format(timeout))
118
+
119
+ start_time = time.time()
120
+ # 采用循环等待提交结果,间隔 0.5 秒检测一次
121
+ while server.finished.wait(timeout=0.5) is False:
122
+ elapsed = time.time() - start_time
123
+ if elapsed >= timeout:
124
+ # 超时后结束等待
125
+ server.stop()
126
+ break
127
+
128
+ result = server.wait_for_result()
129
+ if result is None:
130
+ return (state, parameters, oracle, other_infomation, code)
131
+ else:
132
+ return result
133
+
134
+
135
+ def manual_analysis(report: Report, history=None, timeout=3600):
136
+ try:
137
+ (state, parameters, oracle, other_infomation,
138
+ code) = get_result_or_wait_until_timeout(report, history, timeout)
139
+ report.parameters = parameters
140
+ report.oracle = oracle
141
+ report.state = state
142
+ report.other_infomation = other_infomation
143
+ except Exception as e:
144
+ pass
145
+ return report
146
+
147
+
148
+ def get_report(address: str) -> Report:
149
+ import IPython
150
+
151
+ ipy = IPython.get_ipython()
152
+ if ipy is None:
153
+ raise RuntimeError("请在 Jupyter Notebook 中运行此函数。")
154
+ ipy.set_next_input(("from qulab.executor.analyze import submit_report\n"
155
+ "# 处理完成后,提交结果\n"
156
+ f"# submit_report(report, \"{address}\")"),
157
+ replace=False)
158
+ context = zmq.Context()
159
+ sock = context.socket(zmq.REQ)
160
+ sock.connect(address)
161
+ # 请求数据
162
+ sock.send(b"GET")
163
+ report, history = pickle.loads(sock.recv())
164
+ return report, history
165
+
166
+
167
+ def submit_report(report: Report, address: str):
168
+ import IPython
169
+
170
+ ipy = IPython.get_ipython()
171
+ if ipy is None:
172
+ raise RuntimeError("请在 Jupyter Notebook 中运行此函数。")
173
+
174
+ code = ipy.user_ns['In'][-2]
175
+
176
+ parameters = report.parameters
177
+ oracle = report.oracle
178
+ other_infomation = report.other_infomation
179
+ state = report.state
180
+
181
+ context = zmq.Context()
182
+ sock = context.socket(zmq.REQ)
183
+ sock.connect(address)
184
+ # 提交处理后的结果
185
+ sock.send(pickle.dumps(
186
+ (state, parameters, oracle, other_infomation, code)))
187
+ ack = sock.recv()
188
+ print("结果已提交。")
qulab/executor/storage.py CHANGED
@@ -65,7 +65,7 @@ class Report():
65
65
 
66
66
  def __getstate__(self):
67
67
  state = self.__dict__.copy()
68
- state.pop('base_path')
68
+ state.pop('base_path', None)
69
69
  for k in ['path', 'previous_path', 'config_path', 'script_path']:
70
70
  if state[k] is not None:
71
71
  state[k] = str(state[k])
Binary file
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.9.7"
1
+ __version__ = "2.9.9"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: QuLab
3
- Version: 2.9.7
3
+ Version: 2.9.9
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -36,6 +36,7 @@ Requires-Dist: msgpack>=1.0.5
36
36
  Requires-Dist: nevergrad>=1.0.2
37
37
  Requires-Dist: numpy>=1.13.3
38
38
  Requires-Dist: ply>=3.11
39
+ Requires-Dist: pyperclip>=1.8.2
39
40
  Requires-Dist: pyzmq>=25.1.0
40
41
  Requires-Dist: scipy>=1.0.0
41
42
  Requires-Dist: scikit-optimize>=0.9.0
@@ -1,18 +1,19 @@
1
- qulab/__init__.py,sha256=JZ3bn_kTVlnY-P8JXQ5xEdViieFXqfxX8ReLuiiXIpo,321
1
+ qulab/__init__.py,sha256=fL8FSMGk4vzTMXLxWgNHpd1fNWau4yujSWjPEPqudos,367
2
2
  qulab/__main__.py,sha256=fjaRSL_uUjNIzBGNgjlGswb9TJ2VD5qnkZHW3hItrD4,68
3
3
  qulab/dicttree.py,sha256=tRRMpGZYVOLw0TEByE3_2Ss8FdOmzuGL9e1DWbs8qoY,13684
4
- qulab/fun.cpython-310-darwin.so,sha256=VrUlHJ1pFO5oNrnp2dTPjzK0QA-z2vCrZbhevORa26o,126864
4
+ qulab/fun.cpython-310-darwin.so,sha256=XWLiXx9_kVCfIZTM2Qd4MQICq-dRez6ZBl7nLoNxMLA,126864
5
5
  qulab/typing.py,sha256=vg62sGqxuD9CI5677ejlzAmf2fVdAESZCQjAE_xSxPg,69
6
6
  qulab/utils.py,sha256=BdLdlfjpe6m6gSeONYmpAKTTqxDaYHNk4exlz8kZxTg,2982
7
- qulab/version.py,sha256=YMyATiSQWC8XaFTG2e9YghQWC6WcAk1_57Et_fYwGVs,21
7
+ qulab/version.py,sha256=gB2GONub0WyICh4-SbXI8ce5oNADu2_gH_-ZqWOveM0,21
8
8
  qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  qulab/cli/commands.py,sha256=F1LATmSC9lOAdnrOTMK7DRjETCEcOmMsocovWRyjWTc,597
10
10
  qulab/cli/config.py,sha256=Ei7eSYnbwPPlluDnm8YmWONYiI4g7WtvlZGQdr1Z6vo,3688
11
11
  qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
12
+ qulab/executor/analyze.py,sha256=4Hau5LrKUdpweh7W94tcG4ahgxucHOevbM0hm57T7zE,5649
12
13
  qulab/executor/cli.py,sha256=xceK6XNLnNpAVtqvs0_wOAuG0sgS9jg1iTFYmxVUMWY,11795
13
14
  qulab/executor/load.py,sha256=qI-3b3xvsjZMCthRO3hlzHA0BZI-tH9Y_L0XLBcyWV8,18657
14
15
  qulab/executor/schedule.py,sha256=XRimchHYCgnMAOtCvNLjwMv9IkcTAyBAUCHKQs5RBRw,18745
15
- qulab/executor/storage.py,sha256=PWQIDYjQaoyLGgAKh0X1tlNQTgDWR8bI-HVie4hSkyA,21075
16
+ qulab/executor/storage.py,sha256=8K73KGLAVgchJdtd4rKHXkr1CQOJORWH-Gi57w8IYsw,21081
16
17
  qulab/executor/template.py,sha256=_HEtsUQ5_jSujCw8FBDAK1PRTMRCa4iD4DduHIpjo3c,10569
17
18
  qulab/executor/transform.py,sha256=rk4CLIKVjGRaFzi5FVSgadUxAKKVLSopEHZCaAzDwDg,3435
18
19
  qulab/executor/utils.py,sha256=l_b0y2kMwYKyyXeFtoblPYwKNU-wiFQ9PMo9QlWl9wE,6213
@@ -97,9 +98,9 @@ qulab/visualization/plot_seq.py,sha256=UWTS6p9nfX_7B8ehcYo6UnSTUCjkBsNU9jiOeW2ca
97
98
  qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
98
99
  qulab/visualization/rot3d.py,sha256=lMrEJlRLwYe6NMBlGkKYpp_V9CTipOAuDy6QW_cQK00,734
99
100
  qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
100
- qulab-2.9.7.dist-info/licenses/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
101
- qulab-2.9.7.dist-info/METADATA,sha256=R4asNQDngbtrmIQiaHPnNBGubf76IoqxnODjnKx8GEw,3720
102
- qulab-2.9.7.dist-info/WHEEL,sha256=qnIvK8L8kOW9FTrzifubcmNsZckgNfGDNKzGG7FMEdE,114
103
- qulab-2.9.7.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
104
- qulab-2.9.7.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
105
- qulab-2.9.7.dist-info/RECORD,,
101
+ qulab-2.9.9.dist-info/licenses/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
102
+ qulab-2.9.9.dist-info/METADATA,sha256=YNn0O6ThCfze52902y9RPVsTFtwpoVUpxzKjzqcrZmE,3752
103
+ qulab-2.9.9.dist-info/WHEEL,sha256=qnIvK8L8kOW9FTrzifubcmNsZckgNfGDNKzGG7FMEdE,114
104
+ qulab-2.9.9.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
105
+ qulab-2.9.9.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
106
+ qulab-2.9.9.dist-info/RECORD,,
File without changes