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/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")