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.
Files changed (107) hide show
  1. qulab/__init__.py +33 -0
  2. qulab/__main__.py +4 -0
  3. qulab/cli/__init__.py +0 -0
  4. qulab/cli/commands.py +30 -0
  5. qulab/cli/config.py +170 -0
  6. qulab/cli/decorators.py +28 -0
  7. qulab/dicttree.py +523 -0
  8. qulab/executor/__init__.py +5 -0
  9. qulab/executor/analyze.py +188 -0
  10. qulab/executor/cli.py +434 -0
  11. qulab/executor/load.py +563 -0
  12. qulab/executor/registry.py +185 -0
  13. qulab/executor/schedule.py +543 -0
  14. qulab/executor/storage.py +615 -0
  15. qulab/executor/template.py +259 -0
  16. qulab/executor/utils.py +194 -0
  17. qulab/expression.py +827 -0
  18. qulab/fun.cp313-win_amd64.pyd +0 -0
  19. qulab/monitor/__init__.py +1 -0
  20. qulab/monitor/__main__.py +8 -0
  21. qulab/monitor/config.py +41 -0
  22. qulab/monitor/dataset.py +77 -0
  23. qulab/monitor/event_queue.py +54 -0
  24. qulab/monitor/mainwindow.py +234 -0
  25. qulab/monitor/monitor.py +115 -0
  26. qulab/monitor/ploter.py +123 -0
  27. qulab/monitor/qt_compat.py +16 -0
  28. qulab/monitor/toolbar.py +265 -0
  29. qulab/scan/__init__.py +2 -0
  30. qulab/scan/curd.py +221 -0
  31. qulab/scan/models.py +554 -0
  32. qulab/scan/optimize.py +76 -0
  33. qulab/scan/query.py +387 -0
  34. qulab/scan/record.py +603 -0
  35. qulab/scan/scan.py +1166 -0
  36. qulab/scan/server.py +450 -0
  37. qulab/scan/space.py +213 -0
  38. qulab/scan/utils.py +234 -0
  39. qulab/storage/__init__.py +0 -0
  40. qulab/storage/__main__.py +51 -0
  41. qulab/storage/backend/__init__.py +0 -0
  42. qulab/storage/backend/redis.py +204 -0
  43. qulab/storage/base_dataset.py +352 -0
  44. qulab/storage/chunk.py +60 -0
  45. qulab/storage/dataset.py +127 -0
  46. qulab/storage/file.py +273 -0
  47. qulab/storage/models/__init__.py +22 -0
  48. qulab/storage/models/base.py +4 -0
  49. qulab/storage/models/config.py +28 -0
  50. qulab/storage/models/file.py +89 -0
  51. qulab/storage/models/ipy.py +58 -0
  52. qulab/storage/models/models.py +88 -0
  53. qulab/storage/models/record.py +161 -0
  54. qulab/storage/models/report.py +22 -0
  55. qulab/storage/models/tag.py +93 -0
  56. qulab/storage/storage.py +95 -0
  57. qulab/sys/__init__.py +2 -0
  58. qulab/sys/chat.py +688 -0
  59. qulab/sys/device/__init__.py +3 -0
  60. qulab/sys/device/basedevice.py +255 -0
  61. qulab/sys/device/loader.py +86 -0
  62. qulab/sys/device/utils.py +79 -0
  63. qulab/sys/drivers/FakeInstrument.py +68 -0
  64. qulab/sys/drivers/__init__.py +0 -0
  65. qulab/sys/ipy_events.py +125 -0
  66. qulab/sys/net/__init__.py +0 -0
  67. qulab/sys/net/bencoder.py +205 -0
  68. qulab/sys/net/cli.py +169 -0
  69. qulab/sys/net/dhcp.py +543 -0
  70. qulab/sys/net/dhcpd.py +176 -0
  71. qulab/sys/net/kad.py +1142 -0
  72. qulab/sys/net/kcp.py +192 -0
  73. qulab/sys/net/nginx.py +194 -0
  74. qulab/sys/progress.py +190 -0
  75. qulab/sys/rpc/__init__.py +0 -0
  76. qulab/sys/rpc/client.py +0 -0
  77. qulab/sys/rpc/exceptions.py +96 -0
  78. qulab/sys/rpc/msgpack.py +1052 -0
  79. qulab/sys/rpc/msgpack.pyi +41 -0
  80. qulab/sys/rpc/router.py +35 -0
  81. qulab/sys/rpc/rpc.py +412 -0
  82. qulab/sys/rpc/serialize.py +139 -0
  83. qulab/sys/rpc/server.py +29 -0
  84. qulab/sys/rpc/socket.py +29 -0
  85. qulab/sys/rpc/utils.py +25 -0
  86. qulab/sys/rpc/worker.py +0 -0
  87. qulab/sys/rpc/zmq_socket.py +227 -0
  88. qulab/tools/__init__.py +0 -0
  89. qulab/tools/connection_helper.py +39 -0
  90. qulab/typing.py +2 -0
  91. qulab/utils.py +95 -0
  92. qulab/version.py +1 -0
  93. qulab/visualization/__init__.py +188 -0
  94. qulab/visualization/__main__.py +71 -0
  95. qulab/visualization/_autoplot.py +464 -0
  96. qulab/visualization/plot_circ.py +319 -0
  97. qulab/visualization/plot_layout.py +408 -0
  98. qulab/visualization/plot_seq.py +242 -0
  99. qulab/visualization/qdat.py +152 -0
  100. qulab/visualization/rot3d.py +23 -0
  101. qulab/visualization/widgets.py +86 -0
  102. qulab-2.10.10.dist-info/METADATA +110 -0
  103. qulab-2.10.10.dist-info/RECORD +107 -0
  104. qulab-2.10.10.dist-info/WHEEL +5 -0
  105. qulab-2.10.10.dist-info/entry_points.txt +2 -0
  106. qulab-2.10.10.dist-info/licenses/LICENSE +21 -0
  107. 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
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
+ """