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/scan/query.py
ADDED
@@ -0,0 +1,387 @@
|
|
1
|
+
import functools
|
2
|
+
import math
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
import dill
|
6
|
+
import ipywidgets as widgets
|
7
|
+
import zmq
|
8
|
+
from IPython.display import display
|
9
|
+
from sqlalchemy import create_engine
|
10
|
+
from sqlalchemy.orm import sessionmaker
|
11
|
+
|
12
|
+
from qulab.sys.rpc.zmq_socket import ZMQContextManager
|
13
|
+
|
14
|
+
from .record import Record
|
15
|
+
from .scan import default_server
|
16
|
+
from .server import get_local_record
|
17
|
+
|
18
|
+
|
19
|
+
def get_record(id,
|
20
|
+
database=default_server,
|
21
|
+
socket=None,
|
22
|
+
session=None) -> Record:
|
23
|
+
if isinstance(database, str) and database.startswith('tcp://'):
|
24
|
+
with ZMQContextManager(zmq.DEALER, connect=database,
|
25
|
+
socket=socket) as socket:
|
26
|
+
socket.send_pyobj({
|
27
|
+
'method': 'record_description',
|
28
|
+
'record_id': id
|
29
|
+
})
|
30
|
+
d = dill.loads(socket.recv_pyobj())
|
31
|
+
if d is None:
|
32
|
+
raise ValueError(f'No record with id {id}')
|
33
|
+
d.id = id
|
34
|
+
d.database = database
|
35
|
+
d._file = None
|
36
|
+
d._sock = socket
|
37
|
+
return d
|
38
|
+
else:
|
39
|
+
if session is None:
|
40
|
+
db_file = Path(database) / 'data.db'
|
41
|
+
engine = create_engine(f'sqlite:///{db_file}')
|
42
|
+
Session = sessionmaker(bind=engine)
|
43
|
+
with Session() as session:
|
44
|
+
return get_local_record(session, id, database)
|
45
|
+
else:
|
46
|
+
return get_local_record(session, id, database)
|
47
|
+
|
48
|
+
|
49
|
+
def load_record(file):
|
50
|
+
return Record.load(file)
|
51
|
+
|
52
|
+
|
53
|
+
def _format_tag(tag):
|
54
|
+
if tag.startswith('!'):
|
55
|
+
return f'<code style="color: white; background: red">{tag}</code>'
|
56
|
+
elif tag.startswith('?'):
|
57
|
+
return f'<code style="background: orange">{tag}</code>'
|
58
|
+
elif tag.startswith('@'):
|
59
|
+
return f'<code style="color: white; background: green">{tag}</code>'
|
60
|
+
elif tag.startswith('#'):
|
61
|
+
return f'<code style="color: white; background: blue">{tag}</code>'
|
62
|
+
elif tag.startswith('$'):
|
63
|
+
return f'<code style="color: white; background: purple">{tag}</code>'
|
64
|
+
elif tag.startswith('%'):
|
65
|
+
return f'<code style="color: white; background: brown">{tag}</code>'
|
66
|
+
else:
|
67
|
+
return f'<code>{tag}</code>'
|
68
|
+
|
69
|
+
|
70
|
+
def _format_value(title, value):
|
71
|
+
if title in ['ID', 'App']:
|
72
|
+
return str(value)
|
73
|
+
elif title in ['created time']:
|
74
|
+
return str(value).split('.')[0]
|
75
|
+
elif title in ['tags']:
|
76
|
+
tags = sorted(value)
|
77
|
+
if len(tags) <= 6:
|
78
|
+
tags = [_format_tag(t) for t in tags]
|
79
|
+
elif len(tags) <= 12:
|
80
|
+
tags = [_format_tag(t) for t in tags[:6]
|
81
|
+
] + ['<br />'] + [_format_tag(t) for t in tags[6:]]
|
82
|
+
elif len(tags) <= 18:
|
83
|
+
tags = [_format_tag(t) for t in tags[:6]] + ['<br />'] + [
|
84
|
+
_format_tag(t) for t in tags[6:12]
|
85
|
+
] + ['<br />'] + [_format_tag(t) for t in tags[12:]]
|
86
|
+
else:
|
87
|
+
tags = [_format_tag(t) for t in tags[:6]] + ['<br />'] + [
|
88
|
+
_format_tag(t) for t in tags[6:12]
|
89
|
+
] + ['<br />'] + [_format_tag(t) for t in tags[12:17]] + ['...']
|
90
|
+
return ' '.join(tags)
|
91
|
+
else:
|
92
|
+
return repr(value)
|
93
|
+
|
94
|
+
|
95
|
+
def _format_table(table):
|
96
|
+
tb = [
|
97
|
+
"""<div class="output_subarea output_markdown rendered_html" dir="auto">"""
|
98
|
+
"""<table>"""
|
99
|
+
"""<thead>"""
|
100
|
+
"""<tr>"""
|
101
|
+
]
|
102
|
+
for s in table['header']:
|
103
|
+
tb.append(f'<th style="text-align: center">{s}</th>')
|
104
|
+
tb.append("""</tr></thead><tbody>""")
|
105
|
+
|
106
|
+
for row in table["body"]:
|
107
|
+
r = ["<tr>"]
|
108
|
+
for k, v in zip(table['header'], row):
|
109
|
+
s = _format_value(k, v)
|
110
|
+
r.append(f'<td style="text-align: center">{s}</td>')
|
111
|
+
r.append("</tr>")
|
112
|
+
tb.append(''.join(r))
|
113
|
+
tb.append("""</tbody></table>"""
|
114
|
+
"""</div>""")
|
115
|
+
return ''.join(tb)
|
116
|
+
|
117
|
+
|
118
|
+
class _QueryState():
|
119
|
+
|
120
|
+
def __init__(self):
|
121
|
+
self.table = None
|
122
|
+
self.apps = {}
|
123
|
+
self.page = 1
|
124
|
+
self.total = 0
|
125
|
+
self.app_prefix = []
|
126
|
+
self.app_name = '*'
|
127
|
+
self.records_per_page = 10
|
128
|
+
|
129
|
+
def list_apps(self, prefix=None):
|
130
|
+
common = ('..', '*') if prefix else ('*', )
|
131
|
+
|
132
|
+
if prefix is None:
|
133
|
+
prefix = self.app_prefix
|
134
|
+
d = self.apps
|
135
|
+
for p in prefix:
|
136
|
+
try:
|
137
|
+
d = d[p]
|
138
|
+
except:
|
139
|
+
return common
|
140
|
+
if isinstance(d, dict):
|
141
|
+
return common + tuple(sorted(d.keys()))
|
142
|
+
elif prefix:
|
143
|
+
return prefix[-1]
|
144
|
+
else:
|
145
|
+
return common + tuple(sorted(self.apps.keys()))
|
146
|
+
|
147
|
+
|
148
|
+
__query_state = _QueryState()
|
149
|
+
|
150
|
+
|
151
|
+
def _update_state(app_prefix,
|
152
|
+
app_name,
|
153
|
+
tags,
|
154
|
+
offset,
|
155
|
+
after,
|
156
|
+
before,
|
157
|
+
records_per_page,
|
158
|
+
database='tcp://127.0.0.1:6789'):
|
159
|
+
|
160
|
+
state = __query_state
|
161
|
+
|
162
|
+
app_pattern = '.'.join(app_prefix + [app_name])
|
163
|
+
if app_pattern == '*':
|
164
|
+
app_pattern = None
|
165
|
+
|
166
|
+
if app_name == '..':
|
167
|
+
app_prefix = app_prefix[:-1]
|
168
|
+
app_name = '*'
|
169
|
+
elif app_name == '*':
|
170
|
+
pass
|
171
|
+
else:
|
172
|
+
app_prefix = app_prefix + [app_name]
|
173
|
+
app_name = '*'
|
174
|
+
|
175
|
+
if isinstance(database, str) and database.startswith('tcp://'):
|
176
|
+
with ZMQContextManager(zmq.DEALER, connect=database) as socket:
|
177
|
+
socket.send_pyobj({
|
178
|
+
'method': 'record_query',
|
179
|
+
'app': app_pattern,
|
180
|
+
'tags': tags,
|
181
|
+
'offset': offset,
|
182
|
+
'limit': records_per_page,
|
183
|
+
'before': before,
|
184
|
+
'after': after
|
185
|
+
})
|
186
|
+
total, apps, table = socket.recv_pyobj()
|
187
|
+
else:
|
188
|
+
from .curd import query_record
|
189
|
+
from .models import create_engine, sessionmaker
|
190
|
+
|
191
|
+
url = f'sqlite:///{database}/data.db'
|
192
|
+
|
193
|
+
engine = create_engine(url)
|
194
|
+
Session = sessionmaker(bind=engine)
|
195
|
+
with Session() as db:
|
196
|
+
total, apps, table = query_record(db,
|
197
|
+
offset=offset,
|
198
|
+
limit=records_per_page,
|
199
|
+
app=app_pattern,
|
200
|
+
tags=tags,
|
201
|
+
before=before,
|
202
|
+
after=after)
|
203
|
+
state.table = table
|
204
|
+
state.apps = apps
|
205
|
+
state.total = total
|
206
|
+
state.records_per_page = records_per_page
|
207
|
+
app_list = state.list_apps(app_prefix)
|
208
|
+
if isinstance(app_list, str):
|
209
|
+
state.app_name = app_prefix[-1]
|
210
|
+
else:
|
211
|
+
state.app_prefix = app_prefix
|
212
|
+
state.app_name = '*'
|
213
|
+
return total
|
214
|
+
|
215
|
+
|
216
|
+
def _update_view(ui_widgets):
|
217
|
+
state = __query_state
|
218
|
+
|
219
|
+
page = state.page
|
220
|
+
total = state.total
|
221
|
+
records_per_page = state.records_per_page
|
222
|
+
|
223
|
+
app_options = state.list_apps(state.app_prefix)
|
224
|
+
ui_widgets['app_prefix'].value = 'App:' + '.'.join(state.app_prefix)
|
225
|
+
handlers = ui_widgets['app']._trait_notifiers['value']['change']
|
226
|
+
ui_widgets['app']._trait_notifiers['value']['change'] = handlers[:1]
|
227
|
+
ui_widgets['app'].options = app_options
|
228
|
+
ui_widgets['app']._trait_notifiers['value']['change'] = handlers
|
229
|
+
ui_widgets['app'].value = state.app_name
|
230
|
+
|
231
|
+
offset = (page - 1) * records_per_page
|
232
|
+
if offset < records_per_page:
|
233
|
+
ui_widgets['bt_pre'].disabled = True
|
234
|
+
else:
|
235
|
+
ui_widgets['bt_pre'].disabled = False
|
236
|
+
|
237
|
+
ui_widgets['table'].value = _format_table(state.table)
|
238
|
+
if total - offset <= records_per_page:
|
239
|
+
ui_widgets['bt_next'].disabled = True
|
240
|
+
else:
|
241
|
+
ui_widgets['bt_next'].disabled = False
|
242
|
+
ui_widgets[
|
243
|
+
'page_num_label'].value = f"{page} | {math.ceil(total/10)} pages"
|
244
|
+
|
245
|
+
|
246
|
+
def _get_query_params(state: _QueryState, ui_widgets: dict):
|
247
|
+
page = state.page
|
248
|
+
records_per_page = state.records_per_page
|
249
|
+
tags = [t.strip() for t in ui_widgets['tags'].value.split(',') if t]
|
250
|
+
offset = (page - 1) * records_per_page
|
251
|
+
after = ui_widgets['after'].value
|
252
|
+
before = ui_widgets['before'].value
|
253
|
+
|
254
|
+
if state.app_name == '..' and len(state.app_prefix) == 1:
|
255
|
+
state.app_prefix = []
|
256
|
+
state.app_name = '*'
|
257
|
+
|
258
|
+
return state.app_prefix, state.app_name, tags, offset, after, before, records_per_page
|
259
|
+
|
260
|
+
|
261
|
+
def _on_pre_bt_clicked(bt, ui_widgets):
|
262
|
+
__query_state.page -= 1
|
263
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
264
|
+
_update_view(ui_widgets)
|
265
|
+
|
266
|
+
|
267
|
+
def _on_next_bt_clicked(bt, ui_widgets):
|
268
|
+
__query_state.page += 1
|
269
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
270
|
+
_update_view(ui_widgets)
|
271
|
+
|
272
|
+
|
273
|
+
def _on_app_changed(changes, ui_widgets, stack=[]):
|
274
|
+
if changes['name'] not in ['value', 'index']:
|
275
|
+
stack.append(changes['name'])
|
276
|
+
return
|
277
|
+
if stack and changes['name'] == 'index':
|
278
|
+
stack.clear()
|
279
|
+
return
|
280
|
+
|
281
|
+
__query_state.app_name = ui_widgets['app'].value
|
282
|
+
__query_state.page = 1
|
283
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
284
|
+
_update_view(ui_widgets)
|
285
|
+
|
286
|
+
|
287
|
+
def _on_after_changed(changes, ui_widgets):
|
288
|
+
if changes['name'] != 'value':
|
289
|
+
return
|
290
|
+
__query_state.page = 1
|
291
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
292
|
+
_update_view(ui_widgets)
|
293
|
+
|
294
|
+
|
295
|
+
def _on_before_changed(changes, ui_widgets):
|
296
|
+
if changes['name'] != 'value':
|
297
|
+
return
|
298
|
+
__query_state.page = 1
|
299
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
300
|
+
_update_view(ui_widgets)
|
301
|
+
|
302
|
+
|
303
|
+
def _on_tags_submit(tags, ui_widgets):
|
304
|
+
__query_state.page = 1
|
305
|
+
_update_state(*_get_query_params(__query_state, ui_widgets))
|
306
|
+
_update_view(ui_widgets)
|
307
|
+
|
308
|
+
|
309
|
+
def lookup(app=None, limit=10, database=default_server):
|
310
|
+
after = widgets.DatePicker()
|
311
|
+
before = widgets.DatePicker()
|
312
|
+
app_prefix = widgets.Label('App:')
|
313
|
+
app_name = widgets.Dropdown(
|
314
|
+
options=[
|
315
|
+
'*',
|
316
|
+
],
|
317
|
+
value='*',
|
318
|
+
disabled=False,
|
319
|
+
)
|
320
|
+
bt_pre = widgets.Button(description='<<')
|
321
|
+
bt_next = widgets.Button(description='>>')
|
322
|
+
tags = widgets.Text()
|
323
|
+
page_num_label = widgets.Label('1 | * pages')
|
324
|
+
row1 = widgets.HBox(
|
325
|
+
[bt_pre, page_num_label, bt_next, app_prefix, app_name])
|
326
|
+
row2 = widgets.HBox([widgets.Label('Between:'), after, before])
|
327
|
+
row3 = widgets.HBox([widgets.Label(' Tags :'), tags])
|
328
|
+
table = widgets.HTML()
|
329
|
+
box = widgets.VBox([row1, row2, row3, table])
|
330
|
+
|
331
|
+
ui_widgets = {
|
332
|
+
'app_prefix': app_prefix,
|
333
|
+
'app': app_name,
|
334
|
+
'before': before,
|
335
|
+
'after': after,
|
336
|
+
'tags': tags,
|
337
|
+
'table': table,
|
338
|
+
'page_num_label': page_num_label,
|
339
|
+
'bt_pre': bt_pre,
|
340
|
+
'bt_next': bt_next,
|
341
|
+
}
|
342
|
+
|
343
|
+
__query_state.records_per_page = limit
|
344
|
+
if app is not None:
|
345
|
+
__query_state.app_prefix = app.split('.')
|
346
|
+
__query_state.app_name = '*'
|
347
|
+
|
348
|
+
_update_state(*_get_query_params(__query_state, ui_widgets),
|
349
|
+
database=database)
|
350
|
+
_update_view(ui_widgets)
|
351
|
+
|
352
|
+
bt_pre.on_click(
|
353
|
+
functools.partial(_on_pre_bt_clicked, ui_widgets=ui_widgets))
|
354
|
+
bt_next.on_click(
|
355
|
+
functools.partial(_on_next_bt_clicked, ui_widgets=ui_widgets))
|
356
|
+
after.observe(functools.partial(_on_after_changed, ui_widgets=ui_widgets),
|
357
|
+
names='value')
|
358
|
+
before.observe(functools.partial(_on_before_changed,
|
359
|
+
ui_widgets=ui_widgets),
|
360
|
+
names='value')
|
361
|
+
app_name.observe(functools.partial(_on_app_changed, ui_widgets=ui_widgets),
|
362
|
+
names='value')
|
363
|
+
tags.on_submit(functools.partial(_on_tags_submit, ui_widgets=ui_widgets))
|
364
|
+
|
365
|
+
display(box)
|
366
|
+
|
367
|
+
|
368
|
+
def lookup_list(*, full=False):
|
369
|
+
if __query_state.table is None:
|
370
|
+
return []
|
371
|
+
if full:
|
372
|
+
return __query_state.table['body']
|
373
|
+
else:
|
374
|
+
return [r[0] for r in __query_state.table['body']]
|
375
|
+
|
376
|
+
|
377
|
+
def ping(database=default_server, timeout=1, socket=None):
|
378
|
+
with ZMQContextManager(zmq.DEALER,
|
379
|
+
connect=database,
|
380
|
+
socket=socket,
|
381
|
+
timeout=timeout) as socket:
|
382
|
+
|
383
|
+
socket.send_pyobj({'method': 'ping'})
|
384
|
+
try:
|
385
|
+
return socket.recv_pyobj()
|
386
|
+
except zmq.Again:
|
387
|
+
raise TimeoutError(f"No response from server within {timeout} s")
|