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/executor/cli.py ADDED
@@ -0,0 +1,434 @@
1
+ import functools
2
+ import graphlib
3
+ import importlib
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ import click
9
+ from loguru import logger
10
+
11
+ from ..cli.config import get_config_value, log_options
12
+ from ..cli.decorators import async_command
13
+ from .load import (WorkflowType, find_unreferenced_workflows, get_entries,
14
+ load_workflow, make_graph)
15
+ from .registry import Registry, set_config_api
16
+ from .schedule import CalibrationFailedError
17
+ from .schedule import maintain as maintain_workflow
18
+ from .schedule import run as run_workflow
19
+ from .utils import workflow_template
20
+
21
+
22
+ @logger.catch(reraise=True)
23
+ def boot(script_path):
24
+ """Run a script in a new terminal."""
25
+ import subprocess
26
+ import sys
27
+
28
+ proc = subprocess.Popen([sys.executable, script_path])
29
+ proc.communicate()
30
+
31
+
32
+ @logger.catch(reraise=True)
33
+ def check_toplogy(workflow: WorkflowType,
34
+ code_path: str | Path,
35
+ veryfy_source_code: bool = True) -> dict:
36
+ graph = {}
37
+ try:
38
+ graphlib.TopologicalSorter(
39
+ make_graph(workflow,
40
+ graph,
41
+ code_path,
42
+ veryfy_source_code=veryfy_source_code)).static_order()
43
+ except graphlib.CycleError as e:
44
+ logger.error(
45
+ f"Workflow {workflow.__workflow_id__} has a circular dependency: {e}"
46
+ )
47
+ raise e
48
+ return graph
49
+
50
+
51
+ def command_option(command_name):
52
+ """命令专属配置装饰器工厂"""
53
+
54
+ def decorator(func):
55
+
56
+ @click.option(
57
+ '--code',
58
+ '-c',
59
+ default=lambda: get_config_value("code", str, command_name),
60
+ help='The path of the code.')
61
+ @click.option(
62
+ '--data',
63
+ '-d',
64
+ default=lambda: get_config_value("data", str, command_name),
65
+ help='The path of the data.')
66
+ @click.option(
67
+ '--api',
68
+ '-a',
69
+ default=lambda: get_config_value("api", str, command_name),
70
+ help='The modlule name of the api.')
71
+ @click.option(
72
+ '--bootstrap',
73
+ '-b',
74
+ default=lambda: get_config_value("bootstrap", Path, command_name),
75
+ help='The path of the bootstrap.')
76
+ @functools.wraps(func)
77
+ def wrapper(*args, **kwargs):
78
+ if 'code' in kwargs and kwargs['code'] is not None:
79
+ code = os.path.expanduser(kwargs['code'])
80
+ if code not in sys.path:
81
+ sys.path.insert(0, code)
82
+ bootstrap = kwargs.pop('bootstrap')
83
+ if bootstrap is not None:
84
+ boot(bootstrap)
85
+ return func(*args, **kwargs)
86
+
87
+ return wrapper
88
+
89
+ return decorator
90
+
91
+
92
+ @click.command()
93
+ @click.argument('workflow')
94
+ @click.option('--code',
95
+ '-c',
96
+ default=lambda: get_config_value("code", str, 'create'),
97
+ help='The path of the code.')
98
+ @log_options('create')
99
+ def create(workflow, code):
100
+ """
101
+ Create a new workflow file.
102
+ """
103
+ logger.info(f'[CMD]: create {workflow} --code {code}')
104
+ if code is None:
105
+ code = Path.cwd()
106
+
107
+ fname = Path(code) / f'{workflow}'
108
+ fname = Path(os.path.expanduser(fname))
109
+ if fname.exists():
110
+ click.echo(f'{workflow} already exists')
111
+ return
112
+
113
+ fname.parent.mkdir(parents=True, exist_ok=True)
114
+ deps = find_unreferenced_workflows(code)
115
+
116
+ with open(fname, 'w') as f:
117
+ f.write(workflow_template(workflow, list(deps)))
118
+ click.echo(f'{workflow} created')
119
+
120
+
121
+ @click.command()
122
+ @click.argument('key')
123
+ @click.argument('value', type=str)
124
+ @click.option('--api',
125
+ '-a',
126
+ default=lambda: get_config_value("api", str, 'set'),
127
+ help='The modlule name of the api.')
128
+ @log_options('set')
129
+ def set(key, value, api):
130
+ """
131
+ Set a config.
132
+ """
133
+ logger.info(f'[CMD]: set {key} {value} --api {api}')
134
+ reg = Registry()
135
+ if api is not None:
136
+ api = importlib.import_module(api)
137
+ set_config_api(api.query_config, api.update_config, api.delete_config,
138
+ api.export_config, api.clear_config)
139
+ try:
140
+ value = eval(value)
141
+ except:
142
+ pass
143
+ reg.set(key, value)
144
+
145
+
146
+ @click.command()
147
+ @click.argument('key')
148
+ @click.option('--api',
149
+ '-a',
150
+ default=lambda: get_config_value("api", str, 'get'),
151
+ help='The modlule name of the api.')
152
+ @log_options('get')
153
+ def get(key, api):
154
+ """
155
+ Get a config.
156
+ """
157
+ logger.info(f'[CMD]: get {key} --api {api}')
158
+ reg = Registry()
159
+ if api is not None:
160
+ api = importlib.import_module(api)
161
+ set_config_api(api.query_config, api.update_config, api.delete_config,
162
+ api.export_config, api.clear_config)
163
+ click.echo(reg.get(key))
164
+
165
+
166
+ @click.command()
167
+ @click.argument('workflow')
168
+ @click.option('--plot', '-p', is_flag=True, help='Plot the report.')
169
+ @click.option('--no-dependents',
170
+ '-n',
171
+ is_flag=True,
172
+ help='Do not run dependents.')
173
+ @click.option('--retry', '-r', default=1, type=int, help='Retry times.')
174
+ @click.option('--freeze', is_flag=True, help='Freeze the config table.')
175
+ @click.option('--fail-fast',
176
+ '-f',
177
+ is_flag=True,
178
+ help='Fail immediately on first error.')
179
+ @click.option('--veryfy-source-code',
180
+ is_flag=True,
181
+ help='Veryfy the source code.')
182
+ @log_options('run')
183
+ @command_option('run')
184
+ @async_command
185
+ async def run(workflow,
186
+ code,
187
+ data,
188
+ api,
189
+ plot,
190
+ no_dependents,
191
+ retry,
192
+ freeze,
193
+ fail_fast,
194
+ veryfy_source_code=True):
195
+ """
196
+ Run a workflow.
197
+
198
+ If the workflow has entries, run all entries.
199
+ If `--no-dependents` is set, only run the workflow itself.
200
+ If `--retry` is set, retry the workflow when calibration failed.
201
+ If `--freeze` is set, freeze the config table.
202
+ If `--plot` is set, plot the report.
203
+ If `--api` is set, use the api to get and update the config table.
204
+ If `--code` is not set, use the current working directory.
205
+ If `--data` is not set, use the `logs` directory in the code path.
206
+ """
207
+ logger.info(
208
+ f'[CMD]: run {workflow} --code {code} --data {data} --api {api}'
209
+ f'{" --plot" if plot else ""}'
210
+ f'{" --no-dependents" if no_dependents else ""}'
211
+ f' --retry {retry}'
212
+ f'{" --freeze " if freeze else ""}')
213
+ if api is not None:
214
+ api = importlib.import_module(api)
215
+ set_config_api(api.query_config, api.update_config, api.delete_config,
216
+ api.export_config, api.clear_config)
217
+ if code is None:
218
+ code = Path.cwd()
219
+ if data is None:
220
+ data = Path(code) / 'logs'
221
+
222
+ code = Path(os.path.expanduser(code))
223
+ data = Path(os.path.expanduser(data))
224
+
225
+ wf = load_workflow(workflow, code, veryfy_source_code=veryfy_source_code)
226
+ check_toplogy(wf, code, veryfy_source_code=veryfy_source_code)
227
+
228
+ for i in range(retry):
229
+ try:
230
+ if no_dependents:
231
+ if hasattr(wf, 'entries'):
232
+ exceptions = []
233
+ for entry in get_entries(
234
+ wf, code, veryfy_source_code=veryfy_source_code):
235
+ try:
236
+ await run_workflow(
237
+ entry,
238
+ code,
239
+ data,
240
+ plot=plot,
241
+ freeze=freeze,
242
+ )
243
+ except Exception as e:
244
+ if fail_fast:
245
+ raise e
246
+ exceptions.append(e)
247
+ if any(exceptions):
248
+ raise exceptions[0]
249
+ else:
250
+ await run_workflow(
251
+ wf,
252
+ code,
253
+ data,
254
+ plot=plot,
255
+ freeze=freeze,
256
+ )
257
+ else:
258
+ if hasattr(wf, 'entries'):
259
+ exceptions = []
260
+ for entry in get_entries(
261
+ wf, code, veryfy_source_code=veryfy_source_code):
262
+ try:
263
+ await maintain_workflow(
264
+ entry,
265
+ code,
266
+ data,
267
+ run=True,
268
+ plot=plot,
269
+ freeze=freeze,
270
+ fail_fast=fail_fast,
271
+ veryfy_source_code=veryfy_source_code,
272
+ )
273
+ except Exception as e:
274
+ if fail_fast:
275
+ raise e
276
+ exceptions.append(e)
277
+ if any(exceptions):
278
+ raise exceptions[0]
279
+ else:
280
+ await maintain_workflow(
281
+ wf,
282
+ code,
283
+ data,
284
+ run=True,
285
+ plot=plot,
286
+ freeze=freeze,
287
+ fail_fast=fail_fast,
288
+ veryfy_source_code=veryfy_source_code,
289
+ )
290
+ break
291
+ except CalibrationFailedError as e:
292
+ if i == retry - 1:
293
+ raise e
294
+ logger.warning(f'Calibration failed, retrying ({i + 1}/{retry})')
295
+ continue
296
+
297
+
298
+ @click.command()
299
+ @click.argument('workflow')
300
+ @click.option('--retry', '-r', default=1, type=int, help='Retry times.')
301
+ @click.option('--plot', '-p', is_flag=True, help='Plot the report.')
302
+ @click.option('--fail-fast',
303
+ '-f',
304
+ is_flag=True,
305
+ help='Fail immediately on first error.')
306
+ @click.option('--veryfy-source-code',
307
+ is_flag=True,
308
+ help='Veryfy the source code.')
309
+ @log_options('maintain')
310
+ @command_option('maintain')
311
+ @async_command
312
+ async def maintain(workflow,
313
+ code,
314
+ data,
315
+ api,
316
+ retry,
317
+ plot,
318
+ fail_fast,
319
+ veryfy_source_code=True):
320
+ """
321
+ Maintain a workflow.
322
+
323
+ If the workflow has entries, run all entries.
324
+ If `--retry` is set, retry the workflow when calibration failed.
325
+ If `--plot` is set, plot the report.
326
+ If `--api` is set, use the api to get and update the config table.
327
+ If `--code` is not set, use the current working directory.
328
+ If `--data` is not set, use the `logs` directory in the code path.
329
+ """
330
+ logger.info(
331
+ f'[CMD]: maintain {workflow} --code {code} --data {data} --api {api}'
332
+ f' --retry {retry}'
333
+ f'{" --plot" if plot else ""}')
334
+ if api is not None:
335
+ api = importlib.import_module(api)
336
+ set_config_api(api.query_config, api.update_config, api.delete_config,
337
+ api.export_config, api.clear_config)
338
+ if code is None:
339
+ code = Path.cwd()
340
+ if data is None:
341
+ data = Path(code) / 'logs'
342
+
343
+ code = Path(os.path.expanduser(code))
344
+ data = Path(os.path.expanduser(data))
345
+
346
+ wf = load_workflow(workflow, code, veryfy_source_code=veryfy_source_code)
347
+ check_toplogy(wf, code, veryfy_source_code=veryfy_source_code)
348
+
349
+ for i in range(retry):
350
+ try:
351
+ if hasattr(wf, 'entries'):
352
+ exceptions = []
353
+ for entry in get_entries(
354
+ wf, code, veryfy_source_code=veryfy_source_code):
355
+ try:
356
+ await maintain_workflow(
357
+ entry,
358
+ code,
359
+ data,
360
+ run=False,
361
+ plot=plot,
362
+ freeze=False,
363
+ fail_fast=fail_fast,
364
+ veryfy_source_code=veryfy_source_code,
365
+ )
366
+ except Exception as e:
367
+ if fail_fast:
368
+ raise e
369
+ exceptions.append(e)
370
+ if any(exceptions):
371
+ raise exceptions[0]
372
+ else:
373
+ await maintain_workflow(
374
+ wf,
375
+ code,
376
+ data,
377
+ run=False,
378
+ plot=plot,
379
+ freeze=False,
380
+ fail_fast=fail_fast,
381
+ veryfy_source_code=veryfy_source_code,
382
+ )
383
+ break
384
+ except CalibrationFailedError as e:
385
+ if i == retry - 1:
386
+ raise e
387
+ logger.warning(f'Calibration failed, retrying ({i + 1}/{retry})')
388
+ continue
389
+
390
+
391
+ @click.command()
392
+ @click.argument('report_id')
393
+ @click.option('--plot', '-p', is_flag=True, help='Plot the report.')
394
+ @log_options('reproduce')
395
+ @command_option('reproduce')
396
+ @async_command
397
+ async def reproduce(report_id, code, data, api, plot):
398
+ """
399
+ Reproduce a report.
400
+
401
+ If `--plot` is set, plot the report.
402
+ If `--api` is set, use the api to get and update the config table.
403
+ If `--code` is not set, use the current working directory.
404
+ If `--data` is not set, use the `logs` directory in the code path.
405
+ """
406
+ logger.info(
407
+ f'[CMD]: reproduce {report_id} --code {code} --data {data} --api {api}'
408
+ f'{" --plot" if plot else ""}')
409
+ if api is not None:
410
+ api = importlib.import_module(api)
411
+ set_config_api(api.query_config, api.update_config, api.delete_config,
412
+ api.export_config, api.clear_config)
413
+ if code is None:
414
+ code = Path.cwd()
415
+ if data is None:
416
+ data = Path(code) / 'logs'
417
+
418
+ code = Path(os.path.expanduser(code))
419
+ data = Path(os.path.expanduser(data))
420
+
421
+ from .load import load_workflow_from_source_code
422
+ from .storage import get_report_by_index
423
+
424
+ reg = Registry()
425
+
426
+ r = get_report_by_index(int(report_id), data)
427
+
428
+ wf = load_workflow_from_source_code(r.workflow, r.script)
429
+ cfg = reg.export()
430
+ reg.clear()
431
+ reg.update(r.config)
432
+ await run_workflow(wf, code, data, plot=plot, freeze=True)
433
+ reg.clear()
434
+ reg.update(cfg)