QuLab 2.10.10__cp313-cp313-win_amd64.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 +33 -0
- qulab/__main__.py +4 -0
- qulab/cli/__init__.py +0 -0
- qulab/cli/commands.py +30 -0
- qulab/cli/config.py +170 -0
- qulab/cli/decorators.py +28 -0
- qulab/dicttree.py +523 -0
- qulab/executor/__init__.py +5 -0
- qulab/executor/analyze.py +188 -0
- qulab/executor/cli.py +434 -0
- qulab/executor/load.py +563 -0
- qulab/executor/registry.py +185 -0
- qulab/executor/schedule.py +543 -0
- qulab/executor/storage.py +615 -0
- qulab/executor/template.py +259 -0
- qulab/executor/utils.py +194 -0
- qulab/expression.py +827 -0
- qulab/fun.cp313-win_amd64.pyd +0 -0
- qulab/monitor/__init__.py +1 -0
- qulab/monitor/__main__.py +8 -0
- qulab/monitor/config.py +41 -0
- qulab/monitor/dataset.py +77 -0
- qulab/monitor/event_queue.py +54 -0
- qulab/monitor/mainwindow.py +234 -0
- qulab/monitor/monitor.py +115 -0
- qulab/monitor/ploter.py +123 -0
- qulab/monitor/qt_compat.py +16 -0
- qulab/monitor/toolbar.py +265 -0
- qulab/scan/__init__.py +2 -0
- qulab/scan/curd.py +221 -0
- qulab/scan/models.py +554 -0
- qulab/scan/optimize.py +76 -0
- qulab/scan/query.py +387 -0
- qulab/scan/record.py +603 -0
- qulab/scan/scan.py +1166 -0
- qulab/scan/server.py +450 -0
- qulab/scan/space.py +213 -0
- qulab/scan/utils.py +234 -0
- qulab/storage/__init__.py +0 -0
- qulab/storage/__main__.py +51 -0
- qulab/storage/backend/__init__.py +0 -0
- qulab/storage/backend/redis.py +204 -0
- qulab/storage/base_dataset.py +352 -0
- qulab/storage/chunk.py +60 -0
- qulab/storage/dataset.py +127 -0
- qulab/storage/file.py +273 -0
- qulab/storage/models/__init__.py +22 -0
- qulab/storage/models/base.py +4 -0
- qulab/storage/models/config.py +28 -0
- qulab/storage/models/file.py +89 -0
- qulab/storage/models/ipy.py +58 -0
- qulab/storage/models/models.py +88 -0
- qulab/storage/models/record.py +161 -0
- qulab/storage/models/report.py +22 -0
- qulab/storage/models/tag.py +93 -0
- qulab/storage/storage.py +95 -0
- qulab/sys/__init__.py +2 -0
- qulab/sys/chat.py +688 -0
- qulab/sys/device/__init__.py +3 -0
- qulab/sys/device/basedevice.py +255 -0
- qulab/sys/device/loader.py +86 -0
- qulab/sys/device/utils.py +79 -0
- qulab/sys/drivers/FakeInstrument.py +68 -0
- qulab/sys/drivers/__init__.py +0 -0
- qulab/sys/ipy_events.py +125 -0
- qulab/sys/net/__init__.py +0 -0
- qulab/sys/net/bencoder.py +205 -0
- qulab/sys/net/cli.py +169 -0
- qulab/sys/net/dhcp.py +543 -0
- qulab/sys/net/dhcpd.py +176 -0
- qulab/sys/net/kad.py +1142 -0
- qulab/sys/net/kcp.py +192 -0
- qulab/sys/net/nginx.py +194 -0
- qulab/sys/progress.py +190 -0
- qulab/sys/rpc/__init__.py +0 -0
- qulab/sys/rpc/client.py +0 -0
- qulab/sys/rpc/exceptions.py +96 -0
- qulab/sys/rpc/msgpack.py +1052 -0
- qulab/sys/rpc/msgpack.pyi +41 -0
- qulab/sys/rpc/router.py +35 -0
- qulab/sys/rpc/rpc.py +412 -0
- qulab/sys/rpc/serialize.py +139 -0
- qulab/sys/rpc/server.py +29 -0
- qulab/sys/rpc/socket.py +29 -0
- qulab/sys/rpc/utils.py +25 -0
- qulab/sys/rpc/worker.py +0 -0
- qulab/sys/rpc/zmq_socket.py +227 -0
- qulab/tools/__init__.py +0 -0
- qulab/tools/connection_helper.py +39 -0
- qulab/typing.py +2 -0
- qulab/utils.py +95 -0
- qulab/version.py +1 -0
- qulab/visualization/__init__.py +188 -0
- qulab/visualization/__main__.py +71 -0
- qulab/visualization/_autoplot.py +464 -0
- qulab/visualization/plot_circ.py +319 -0
- qulab/visualization/plot_layout.py +408 -0
- qulab/visualization/plot_seq.py +242 -0
- qulab/visualization/qdat.py +152 -0
- qulab/visualization/rot3d.py +23 -0
- qulab/visualization/widgets.py +86 -0
- qulab-2.10.10.dist-info/METADATA +110 -0
- qulab-2.10.10.dist-info/RECORD +107 -0
- qulab-2.10.10.dist-info/WHEEL +5 -0
- qulab-2.10.10.dist-info/entry_points.txt +2 -0
- qulab-2.10.10.dist-info/licenses/LICENSE +21 -0
- qulab-2.10.10.dist-info/top_level.txt +1 -0
qulab/sys/net/kcp.py
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
import asyncio
|
2
|
+
import time
|
3
|
+
|
4
|
+
from . import _kcp
|
5
|
+
|
6
|
+
|
7
|
+
class KCPConnection():
|
8
|
+
|
9
|
+
def __init__(self,
|
10
|
+
address: tuple[str, int],
|
11
|
+
transport: asyncio.DatagramTransport,
|
12
|
+
conv: int,
|
13
|
+
nodelay: bool = True,
|
14
|
+
interval: int = 20,
|
15
|
+
resend: int = 2,
|
16
|
+
nc: bool = True):
|
17
|
+
self._kcp = _kcp.kcp_create(conv, self)
|
18
|
+
_kcp.kcp_nodelay(self._kcp, int(nodelay), interval, resend, int(nc))
|
19
|
+
self.interval = interval
|
20
|
+
self.address = address
|
21
|
+
self.transport = transport
|
22
|
+
self.last_active = time.time()
|
23
|
+
self.send_queue = asyncio.Queue()
|
24
|
+
self.recv_queue = asyncio.Queue()
|
25
|
+
self.fut = asyncio.create_task(self.run())
|
26
|
+
|
27
|
+
def __del__(self):
|
28
|
+
try:
|
29
|
+
self.fut.cancel()
|
30
|
+
except:
|
31
|
+
pass
|
32
|
+
_kcp.kcp_release(self._kcp)
|
33
|
+
|
34
|
+
def output(self, msg):
|
35
|
+
self.transport.sendto(msg, self.address)
|
36
|
+
|
37
|
+
def send(self, buff):
|
38
|
+
self.last_active = time.time()
|
39
|
+
self.send_queue.put_nowait(buff)
|
40
|
+
|
41
|
+
def _send(self, buff):
|
42
|
+
return _kcp.kcp_send(self._kcp, buff)
|
43
|
+
|
44
|
+
async def recv(self):
|
45
|
+
return await self.recv_queue.get()
|
46
|
+
|
47
|
+
def recv_nowait(self):
|
48
|
+
self.flush()
|
49
|
+
try:
|
50
|
+
return self.recv_queue.get_nowait()
|
51
|
+
except:
|
52
|
+
return None
|
53
|
+
|
54
|
+
def _recv(self):
|
55
|
+
return _kcp.kcp_recv(self._kcp)
|
56
|
+
|
57
|
+
def _update(self):
|
58
|
+
_kcp.kcp_update(self._kcp, self.clock())
|
59
|
+
|
60
|
+
def check(self):
|
61
|
+
current = self.clock()
|
62
|
+
return _kcp.kcp_check(self._kcp, current) - current
|
63
|
+
|
64
|
+
def clock(self):
|
65
|
+
return (time.monotonic_ns() // 1000_000) & 0x7fffffff
|
66
|
+
|
67
|
+
def input(self, buff):
|
68
|
+
self.last_active = time.time()
|
69
|
+
return _kcp.kcp_input(self._kcp, buff)
|
70
|
+
|
71
|
+
async def update(self):
|
72
|
+
while True:
|
73
|
+
await asyncio.sleep(self.check() / 1000)
|
74
|
+
self._update()
|
75
|
+
|
76
|
+
async def sync(self):
|
77
|
+
while True:
|
78
|
+
await asyncio.sleep(self.interval / 1000)
|
79
|
+
self.flush()
|
80
|
+
|
81
|
+
async def run(self):
|
82
|
+
await asyncio.gather(self.update(), self.sync())
|
83
|
+
|
84
|
+
def flush(self):
|
85
|
+
while True:
|
86
|
+
buff = self._recv()
|
87
|
+
if isinstance(buff, int):
|
88
|
+
break
|
89
|
+
self.recv_queue.put_nowait(buff)
|
90
|
+
while True:
|
91
|
+
try:
|
92
|
+
buff = self.send_queue.get_nowait()
|
93
|
+
if self._send(buff) < 0:
|
94
|
+
self.send_queue.put_nowait(buff)
|
95
|
+
break
|
96
|
+
except asyncio.QueueEmpty:
|
97
|
+
break
|
98
|
+
|
99
|
+
return True
|
100
|
+
|
101
|
+
|
102
|
+
class KCPProtocol(asyncio.DatagramProtocol):
|
103
|
+
|
104
|
+
def __init__(self,
|
105
|
+
conv: int,
|
106
|
+
ttl: int = 3600,
|
107
|
+
nodelay: bool = True,
|
108
|
+
interval: int = 20,
|
109
|
+
resend: int = 2,
|
110
|
+
nc: bool = True):
|
111
|
+
self.ttl = ttl
|
112
|
+
self.conv = conv
|
113
|
+
self.nodelay = nodelay
|
114
|
+
self.interval = interval
|
115
|
+
self.resend = resend
|
116
|
+
self.nc = nc
|
117
|
+
self.transport = None
|
118
|
+
self.connections = {}
|
119
|
+
self.autoclean_loop: asyncio.Future = None
|
120
|
+
self.clean()
|
121
|
+
|
122
|
+
def connection_lost(self, exc):
|
123
|
+
self.autoclean_loop.cancel()
|
124
|
+
for address in self.connections:
|
125
|
+
del self.connections[address]
|
126
|
+
|
127
|
+
def connection_made(self, transport):
|
128
|
+
self.transport = transport
|
129
|
+
|
130
|
+
def get_connection(self, address):
|
131
|
+
if address not in self.connections:
|
132
|
+
self.connections[address] = KCPConnection(address, self.transport,
|
133
|
+
self.conv, self.nodelay,
|
134
|
+
self.interval,
|
135
|
+
self.resend, self.nc)
|
136
|
+
self.connections[address].last_recv = time.time()
|
137
|
+
return self.connections[address]
|
138
|
+
|
139
|
+
def datagram_received(self, datagram, address):
|
140
|
+
self.get_connection(address).input(datagram)
|
141
|
+
|
142
|
+
def sendto(self, msg, address):
|
143
|
+
self.get_connection(address).send(msg)
|
144
|
+
|
145
|
+
def recvfrom(self):
|
146
|
+
for address, conn in list(self.connections.items()):
|
147
|
+
buff = conn.recv_nowait()
|
148
|
+
if buff:
|
149
|
+
return buff, address
|
150
|
+
|
151
|
+
def clean(self):
|
152
|
+
current = time.time()
|
153
|
+
dead = []
|
154
|
+
for address, conn in list(self.connections.items()):
|
155
|
+
if current - conn.last_active > self.ttl:
|
156
|
+
dead.append(address)
|
157
|
+
for address in dead:
|
158
|
+
del self.connections[address]
|
159
|
+
loop = asyncio.get_running_loop()
|
160
|
+
self.autoclean_loop = loop.call_later(10, self.clean)
|
161
|
+
|
162
|
+
|
163
|
+
async def listen(address: tuple[str, int],
|
164
|
+
conv: int = 1234,
|
165
|
+
ttl: int = 3600,
|
166
|
+
nodelay: bool = True,
|
167
|
+
interval: int = 20,
|
168
|
+
resend: int = 2,
|
169
|
+
nc: bool = True):
|
170
|
+
"""
|
171
|
+
Listen on a UDP address and return a KCPProtocol instance.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
ttl (int): The connection TTL (in second).
|
175
|
+
address (ip, port): The address to listen on.
|
176
|
+
conv (int): The conversation ID.
|
177
|
+
nodelay (bool): Whether to enable nodelay mode.
|
178
|
+
interval (int): The internal update interval (in millisecond).
|
179
|
+
resend (int): The number of times to resend unacknowledged packets.
|
180
|
+
nc (bool): Whether to enable congestion control.
|
181
|
+
|
182
|
+
Returns:
|
183
|
+
A KCPProtocol instance.
|
184
|
+
"""
|
185
|
+
|
186
|
+
def protocol_factory():
|
187
|
+
return KCPProtocol(conv, ttl, nodelay, interval, resend, nc)
|
188
|
+
|
189
|
+
loop = asyncio.get_running_loop()
|
190
|
+
transport, protocol = await loop.create_datagram_endpoint(
|
191
|
+
protocol_factory, local_addr=address)
|
192
|
+
return protocol
|
qulab/sys/net/nginx.py
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
import asyncio
|
2
|
+
import os
|
3
|
+
from urllib.parse import quote_plus
|
4
|
+
|
5
|
+
from fastapi import FastAPI, Request
|
6
|
+
from fastapi.responses import Response
|
7
|
+
from pydantic import BaseModel
|
8
|
+
|
9
|
+
NGINX_DIR = 'C:/Users/Administrator/Desktop/nginx/nginx-1.20.2'
|
10
|
+
HOST_URL = 'https://systemq.baqis.ac.cn'
|
11
|
+
|
12
|
+
db = {
|
13
|
+
"n01": {
|
14
|
+
"notebook_port": 1000,
|
15
|
+
"codeserver_port": 1001,
|
16
|
+
"ip": "127.0.0.1",
|
17
|
+
"token": "ed747047-1d9d-47b0-8fc2-b4914f8a9bd9",
|
18
|
+
},
|
19
|
+
"n02": {
|
20
|
+
"notebook_port": 1002,
|
21
|
+
"codeserver_port": 1003,
|
22
|
+
"ip": "127.0.0.1",
|
23
|
+
"token": "ed423dd1-05fb-48d2-a720-dbebfb2ea3e1",
|
24
|
+
},
|
25
|
+
"n03": {
|
26
|
+
"notebook_port": 1004,
|
27
|
+
"codeserver_port": 1005,
|
28
|
+
"ip": "127.0.0.1",
|
29
|
+
"token": "e3b0c442-98fc-11e4-8dfc-aa07a5b093d3",
|
30
|
+
},
|
31
|
+
}
|
32
|
+
|
33
|
+
|
34
|
+
def fmt_config(ip, notebook_port, codeserver_port, local_notebook_port,
|
35
|
+
local_codeserver_port, page):
|
36
|
+
return """
|
37
|
+
server {""" + f"""
|
38
|
+
listen {notebook_port} ssl;
|
39
|
+
listen [::]:{notebook_port} ssl;
|
40
|
+
""" + """
|
41
|
+
include ssl/ssl.conf;
|
42
|
+
|
43
|
+
server_name systemq.baqis.ac.cn;
|
44
|
+
|
45
|
+
client_max_body_size 100M;
|
46
|
+
|
47
|
+
# notebook
|
48
|
+
location / {
|
49
|
+
include auth/auth.conf;
|
50
|
+
""" + f"""
|
51
|
+
proxy_pass http://{ip}:{local_notebook_port}/;""" + """
|
52
|
+
proxy_set_header X-Real_IP $remote_addr;
|
53
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
54
|
+
proxy_set_header X-NginX-Proxy true;
|
55
|
+
proxy_ssl_session_reuse off;
|
56
|
+
proxy_set_header Host $http_host;
|
57
|
+
|
58
|
+
proxy_redirect off;
|
59
|
+
proxy_http_version 1.1;
|
60
|
+
proxy_set_header Upgrade $http_upgrade;
|
61
|
+
proxy_set_header Connection "upgrade";
|
62
|
+
}
|
63
|
+
|
64
|
+
location /static/ {
|
65
|
+
alias html/_jupyter_notebook/static/;
|
66
|
+
}
|
67
|
+
|
68
|
+
location /login {
|
69
|
+
include auth/auth.conf;
|
70
|
+
default_type text/html;
|
71
|
+
add_header Content-Type "text/html; charset=UTF-8";
|
72
|
+
""" + f"""
|
73
|
+
return 200 "{page}";
|
74
|
+
""" + """
|
75
|
+
}
|
76
|
+
|
77
|
+
include auth/location.conf;
|
78
|
+
}
|
79
|
+
|
80
|
+
server {""" + f"""
|
81
|
+
listen {codeserver_port} ssl;
|
82
|
+
listen [::]:{codeserver_port} ssl;
|
83
|
+
""" + """
|
84
|
+
include ssl/ssl.conf;
|
85
|
+
|
86
|
+
server_name systemq.baqis.ac.cn;
|
87
|
+
|
88
|
+
client_max_body_size 100M;
|
89
|
+
|
90
|
+
# vscode
|
91
|
+
location / {
|
92
|
+
include auth/auth.conf;
|
93
|
+
""" + f"""
|
94
|
+
proxy_pass http://{ip}:{local_codeserver_port}/;""" + """
|
95
|
+
proxy_set_header X-Real_IP $remote_addr;
|
96
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
97
|
+
proxy_set_header X-NginX-Proxy true;
|
98
|
+
proxy_ssl_session_reuse off;
|
99
|
+
proxy_set_header Host $http_host;
|
100
|
+
|
101
|
+
proxy_redirect off;
|
102
|
+
proxy_http_version 1.1;
|
103
|
+
proxy_set_header Upgrade $http_upgrade;
|
104
|
+
proxy_set_header Connection "upgrade";
|
105
|
+
}
|
106
|
+
|
107
|
+
location /oss-dev/static/out/ {
|
108
|
+
root html;
|
109
|
+
}
|
110
|
+
|
111
|
+
include auth/location.conf;
|
112
|
+
}
|
113
|
+
"""
|
114
|
+
|
115
|
+
|
116
|
+
def fmt_page(notebook_url, codeserver_url):
|
117
|
+
return """
|
118
|
+
<!DOCTYPE html>
|
119
|
+
<html>
|
120
|
+
<head>
|
121
|
+
<title>Welcome to systemq!</title>
|
122
|
+
<style>
|
123
|
+
body {
|
124
|
+
width: 35em;
|
125
|
+
margin: 0 auto;
|
126
|
+
font-family: Tahoma, Verdana, Arial, sans-serif;
|
127
|
+
}
|
128
|
+
</style>
|
129
|
+
</head>
|
130
|
+
<body>
|
131
|
+
<h1>Welcome to systemq!</h1>""" + f"""
|
132
|
+
<a href=\\"{notebook_url}\\">notebook</a>.<br/>
|
133
|
+
<a href=\\"{codeserver_url}\\">codeserver</a>.<br/>
|
134
|
+
</body>
|
135
|
+
</html>
|
136
|
+
"""
|
137
|
+
|
138
|
+
|
139
|
+
class Node(BaseModel):
|
140
|
+
token: str
|
141
|
+
name: str
|
142
|
+
notebook_port: int = 8888
|
143
|
+
codeserver_port: int = 14263
|
144
|
+
codeserver_path: str = ""
|
145
|
+
|
146
|
+
|
147
|
+
app = FastAPI()
|
148
|
+
|
149
|
+
|
150
|
+
@app.post("/auth")
|
151
|
+
async def auth(request: Request, node: Node):
|
152
|
+
try:
|
153
|
+
assert node.name in db
|
154
|
+
assert node.token == db[node.name]['token']
|
155
|
+
notebook_port = db[node.name]['notebook_port']
|
156
|
+
codeserver_port = db[node.name]['codeserver_port']
|
157
|
+
|
158
|
+
ip = request.client.host
|
159
|
+
if ip == db[node.name]['ip']:
|
160
|
+
return Response(status_code=200)
|
161
|
+
else:
|
162
|
+
print(" CHANGE IP", db[node.name]['ip'], "===>", ip)
|
163
|
+
db[node.name]['ip'] = ip
|
164
|
+
|
165
|
+
#ip = request.headers.get('x-real-ip')
|
166
|
+
local_notebook_port = node.notebook_port
|
167
|
+
local_codeserver_port = node.codeserver_port
|
168
|
+
codeserver_path = quote_plus(node.codeserver_path)
|
169
|
+
|
170
|
+
codeserver_url = f"{HOST_URL}:{codeserver_port}?tkn=lZBAQISFF532&folder={codeserver_path}"
|
171
|
+
notebook_url = f"{HOST_URL}:{notebook_port}/tree"
|
172
|
+
|
173
|
+
page = fmt_page(notebook_url, codeserver_url)
|
174
|
+
page = ''.join(page.splitlines())
|
175
|
+
|
176
|
+
config = fmt_config(ip, notebook_port, codeserver_port,
|
177
|
+
local_notebook_port, local_codeserver_port, page)
|
178
|
+
|
179
|
+
with open(f"{NGINX_DIR}/conf/servers/{node.name}.conf", "w") as f:
|
180
|
+
f.write(config)
|
181
|
+
|
182
|
+
await asyncio.sleep(0.1)
|
183
|
+
|
184
|
+
cwd = os.getcwd()
|
185
|
+
|
186
|
+
os.chdir(NGINX_DIR)
|
187
|
+
|
188
|
+
os.system(f'{NGINX_DIR}/nginx.exe -s reload')
|
189
|
+
|
190
|
+
os.chdir(cwd)
|
191
|
+
|
192
|
+
return Response(status_code=200)
|
193
|
+
except:
|
194
|
+
return Response(status_code=400)
|
qulab/sys/progress.py
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections import deque
|
3
|
+
from datetime import timedelta
|
4
|
+
from time import monotonic
|
5
|
+
|
6
|
+
from blinker import Signal
|
7
|
+
|
8
|
+
try:
|
9
|
+
import ipywidgets as widgets
|
10
|
+
from IPython.display import display
|
11
|
+
except:
|
12
|
+
pass
|
13
|
+
|
14
|
+
|
15
|
+
class Progress:
|
16
|
+
sma_window = 10 # Simple Moving Average window
|
17
|
+
|
18
|
+
def __init__(self, *, max=10):
|
19
|
+
self.start_ts = monotonic()
|
20
|
+
self._ts = self.start_ts
|
21
|
+
self._xput = deque(maxlen=self.sma_window)
|
22
|
+
self._max = max
|
23
|
+
self.index = 0
|
24
|
+
self.updated = Signal()
|
25
|
+
self.finished = Signal()
|
26
|
+
self.status = "running"
|
27
|
+
|
28
|
+
@property
|
29
|
+
def progress(self):
|
30
|
+
return min(1.0, self.index / self.max)
|
31
|
+
|
32
|
+
@property
|
33
|
+
def remaining(self):
|
34
|
+
return max(self.max - self.index, 0)
|
35
|
+
|
36
|
+
@property
|
37
|
+
def percent(self):
|
38
|
+
return self.progress * 100
|
39
|
+
|
40
|
+
@property
|
41
|
+
def elapsed(self):
|
42
|
+
if self.status != "running":
|
43
|
+
return self._ts - self.start_ts
|
44
|
+
return monotonic() - self.start_ts
|
45
|
+
|
46
|
+
@property
|
47
|
+
def eta(self):
|
48
|
+
if self.status != "running":
|
49
|
+
return 0
|
50
|
+
avg = sum(self._xput) / len(self._xput)
|
51
|
+
dt = monotonic() - self._ts
|
52
|
+
if dt > avg:
|
53
|
+
avg = 0.9 * avg + 0.1 * dt
|
54
|
+
return avg * self.remaining
|
55
|
+
else:
|
56
|
+
return avg * self.remaining - dt
|
57
|
+
|
58
|
+
@property
|
59
|
+
def max(self):
|
60
|
+
return self._max
|
61
|
+
|
62
|
+
@max.setter
|
63
|
+
def max(self, x):
|
64
|
+
self._max = x
|
65
|
+
self.updated.send(self)
|
66
|
+
|
67
|
+
def next(self, n=1):
|
68
|
+
assert n > 0
|
69
|
+
now = monotonic()
|
70
|
+
dt = now - self._ts
|
71
|
+
self._xput.append(dt / n)
|
72
|
+
self._ts = now
|
73
|
+
self.index = self.index + n
|
74
|
+
self.updated.send(self)
|
75
|
+
|
76
|
+
def goto(self, index):
|
77
|
+
incr = index - self.index
|
78
|
+
self.next(incr)
|
79
|
+
|
80
|
+
def finish(self, success=True):
|
81
|
+
self._ts = monotonic()
|
82
|
+
if success:
|
83
|
+
self.status = "finished"
|
84
|
+
else:
|
85
|
+
self.status = "failure"
|
86
|
+
self.finished.send(self, success=success)
|
87
|
+
|
88
|
+
def __enter__(self):
|
89
|
+
return self
|
90
|
+
|
91
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
92
|
+
if exc_type is None:
|
93
|
+
self.finish(True)
|
94
|
+
else:
|
95
|
+
self.finish(False)
|
96
|
+
|
97
|
+
def iter(self, it, max=None):
|
98
|
+
if max is None:
|
99
|
+
try:
|
100
|
+
self.max = len(it)
|
101
|
+
except TypeError:
|
102
|
+
self.max = 0
|
103
|
+
else:
|
104
|
+
self.max = max
|
105
|
+
|
106
|
+
with self:
|
107
|
+
for x in it:
|
108
|
+
yield x
|
109
|
+
self.next()
|
110
|
+
|
111
|
+
def __repr__(self):
|
112
|
+
if self._ts == self.start_ts:
|
113
|
+
eta_td = '--:--:--'
|
114
|
+
else:
|
115
|
+
eta_td = timedelta(seconds=round(self.eta))
|
116
|
+
return (
|
117
|
+
f"({self.index}/{self.max}) {self.percent:.0f}%"
|
118
|
+
f" Used time: {timedelta(seconds=round(self.elapsed))} Remaining time: {eta_td}"
|
119
|
+
f" {self.status}")
|
120
|
+
|
121
|
+
|
122
|
+
class ProgressBar():
|
123
|
+
|
124
|
+
def listen(self, progress: Progress):
|
125
|
+
self.progress = progress
|
126
|
+
self.progress.updated.connect(self.update)
|
127
|
+
self.progress.finished.connect(self.finish)
|
128
|
+
|
129
|
+
def update(self, sender: Progress):
|
130
|
+
raise NotImplementedError()
|
131
|
+
|
132
|
+
def finish(self, sender: Progress, success: bool):
|
133
|
+
self.progress.updated.disconnect(self.update)
|
134
|
+
self.progress.finished.disconnect(self.finish)
|
135
|
+
|
136
|
+
|
137
|
+
class JupyterProgressBar(ProgressBar):
|
138
|
+
|
139
|
+
def __init__(self, *, description='Progressing', hiden=False):
|
140
|
+
self.description = description
|
141
|
+
self.hiden = hiden
|
142
|
+
|
143
|
+
def display(self):
|
144
|
+
if self.hiden:
|
145
|
+
return
|
146
|
+
self.progress_ui = widgets.FloatProgress(value=0,
|
147
|
+
min=0,
|
148
|
+
max=100.0,
|
149
|
+
step=1,
|
150
|
+
description=self.description,
|
151
|
+
bar_style='')
|
152
|
+
|
153
|
+
self.elapsed_ui = widgets.Label(value='Used time: 00:00:00')
|
154
|
+
self.eta_ui = widgets.Label(value='Remaining time: --:--:--')
|
155
|
+
self.ui = widgets.HBox(
|
156
|
+
[self.progress_ui, self.elapsed_ui, self.eta_ui])
|
157
|
+
display(self.ui)
|
158
|
+
|
159
|
+
def listen(self, progress: Progress):
|
160
|
+
super().listen(progress)
|
161
|
+
self.update_regularly()
|
162
|
+
|
163
|
+
def update_regularly(self, frequency=1):
|
164
|
+
try:
|
165
|
+
self.update(self.progress)
|
166
|
+
except:
|
167
|
+
pass
|
168
|
+
asyncio.get_running_loop().call_later(frequency, self.update_regularly)
|
169
|
+
|
170
|
+
def update(self, sender: Progress):
|
171
|
+
if self.hiden:
|
172
|
+
return
|
173
|
+
self.progress_ui.value = sender.percent
|
174
|
+
self.elapsed_ui.value = (
|
175
|
+
f'({sender.index}/{sender.max}) '
|
176
|
+
f'Used time: {timedelta(seconds=round(sender.elapsed))}')
|
177
|
+
if sender.eta == sender.start_ts:
|
178
|
+
self.eta_ui.value = f'Remaining time: --:--:--'
|
179
|
+
else:
|
180
|
+
self.eta_ui.value = f'Remaining time: {timedelta(seconds=round(sender.eta))}'
|
181
|
+
|
182
|
+
def finish(self, sender: Progress, success: bool = True):
|
183
|
+
if self.hiden:
|
184
|
+
return
|
185
|
+
if success:
|
186
|
+
self.progress_ui.bar_style = 'success'
|
187
|
+
self.progress_ui.value = 100.0
|
188
|
+
else:
|
189
|
+
self.progress_ui.bar_style = 'danger'
|
190
|
+
super().finish(sender, success)
|
File without changes
|
qulab/sys/rpc/client.py
ADDED
File without changes
|
@@ -0,0 +1,96 @@
|
|
1
|
+
import inspect
|
2
|
+
from collections import deque
|
3
|
+
|
4
|
+
|
5
|
+
def _parse_frame(frame):
|
6
|
+
ret = {}
|
7
|
+
ret['source'] = inspect.getsource(frame)
|
8
|
+
ret['name'] = frame.f_code.co_name
|
9
|
+
ret['firstlineno'] = 1
|
10
|
+
if ret['name'] != '<module>':
|
11
|
+
argnames = frame.f_code.co_varnames[:frame.f_code.co_argcount +
|
12
|
+
frame.f_code.co_kwonlyargcount]
|
13
|
+
ret['name'] += '(' + ', '.join(argnames) + ')'
|
14
|
+
ret['firstlineno'] = frame.f_code.co_firstlineno
|
15
|
+
ret['filename'] = frame.f_code.co_filename
|
16
|
+
return ret
|
17
|
+
|
18
|
+
|
19
|
+
def _parse_traceback(err):
|
20
|
+
ret = []
|
21
|
+
tb = err.__traceback__
|
22
|
+
while tb is not None:
|
23
|
+
frame = _parse_frame(tb.tb_frame)
|
24
|
+
frame['lineno'] = tb.tb_lineno
|
25
|
+
ret.append(frame)
|
26
|
+
tb = tb.tb_next
|
27
|
+
return ret
|
28
|
+
|
29
|
+
|
30
|
+
def _format_frame(frame):
|
31
|
+
post_lines = -1
|
32
|
+
lines = deque(maxlen=16)
|
33
|
+
lines.append(f"{frame['filename']} in {frame['name']}")
|
34
|
+
for n, line in enumerate(frame['source'].split('\n')):
|
35
|
+
lno = n + frame['firstlineno']
|
36
|
+
if lno == frame['lineno']:
|
37
|
+
lines.append(f"->{lno:3d} {line}")
|
38
|
+
post_lines = 0
|
39
|
+
else:
|
40
|
+
lines.append(f" {lno:3d} {line}")
|
41
|
+
if post_lines >= 0:
|
42
|
+
post_lines += 1
|
43
|
+
if post_lines >= 7:
|
44
|
+
break
|
45
|
+
return '\n'.join(lines)
|
46
|
+
|
47
|
+
|
48
|
+
def _format_traceback(err):
|
49
|
+
frame_text = []
|
50
|
+
for frame in _parse_traceback(err):
|
51
|
+
frame_text.append(_format_frame(frame))
|
52
|
+
traceback_text = '\n'.join(frame_text)
|
53
|
+
args = list(err.args)
|
54
|
+
args.append(traceback_text)
|
55
|
+
err.args = tuple(args)
|
56
|
+
return err
|
57
|
+
|
58
|
+
|
59
|
+
###############################################################
|
60
|
+
# RPC Exceptions
|
61
|
+
###############################################################
|
62
|
+
|
63
|
+
|
64
|
+
class RPCError(Exception):
|
65
|
+
"""
|
66
|
+
RPC base exception.
|
67
|
+
"""
|
68
|
+
|
69
|
+
|
70
|
+
class RPCServerError(RPCError):
|
71
|
+
"""
|
72
|
+
Server side error.
|
73
|
+
"""
|
74
|
+
|
75
|
+
@classmethod
|
76
|
+
def make(cls, exce):
|
77
|
+
exce = _format_traceback(exce)
|
78
|
+
args = [exce.__class__.__name__]
|
79
|
+
args.extend(list(exce.args))
|
80
|
+
return cls(*args)
|
81
|
+
|
82
|
+
def _repr_markdown_(self):
|
83
|
+
return '\n'.join([
|
84
|
+
'```python',
|
85
|
+
'---------------------------------------------------------------------------',
|
86
|
+
f'RPCServerError({self.args[0]}) Server raise:{self.args[1]}',
|
87
|
+
f'{self.args[2]}',
|
88
|
+
'---------------------------------------------------------------------------',
|
89
|
+
'```',
|
90
|
+
])
|
91
|
+
|
92
|
+
|
93
|
+
class RPCTimeout(RPCError):
|
94
|
+
"""
|
95
|
+
Timeout.
|
96
|
+
"""
|