QuLab 2.1.1__tar.gz → 2.1.2__tar.gz

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 (97) hide show
  1. {qulab-2.1.1 → qulab-2.1.2}/PKG-INFO +1 -1
  2. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/PKG-INFO +1 -1
  3. qulab-2.1.2/qulab/__init__.py +3 -0
  4. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/__init__.py +1 -1
  5. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/query.py +8 -8
  6. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/record.py +50 -3
  7. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/recorder.py +15 -9
  8. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/scan.py +29 -17
  9. qulab-2.1.2/qulab/version.py +1 -0
  10. qulab-2.1.1/qulab/__init__.py +0 -1
  11. qulab-2.1.1/qulab/version.py +0 -1
  12. {qulab-2.1.1 → qulab-2.1.2}/LICENSE +0 -0
  13. {qulab-2.1.1 → qulab-2.1.2}/MANIFEST.in +0 -0
  14. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/SOURCES.txt +0 -0
  15. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/dependency_links.txt +0 -0
  16. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/entry_points.txt +0 -0
  17. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/requires.txt +0 -0
  18. {qulab-2.1.1 → qulab-2.1.2}/QuLab.egg-info/top_level.txt +0 -0
  19. {qulab-2.1.1 → qulab-2.1.2}/README.md +0 -0
  20. {qulab-2.1.1 → qulab-2.1.2}/pyproject.toml +0 -0
  21. {qulab-2.1.1 → qulab-2.1.2}/qulab/__main__.py +0 -0
  22. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/__init__.py +0 -0
  23. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/__main__.py +0 -0
  24. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/config.py +0 -0
  25. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/dataset.py +0 -0
  26. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/event_queue.py +0 -0
  27. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/mainwindow.py +0 -0
  28. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/monitor.py +0 -0
  29. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/ploter.py +0 -0
  30. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/qt_compat.py +0 -0
  31. {qulab-2.1.1 → qulab-2.1.2}/qulab/monitor/toolbar.py +0 -0
  32. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/curd.py +0 -0
  33. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/expression.py +0 -0
  34. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/models.py +0 -0
  35. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/optimize.py +0 -0
  36. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/server.py +0 -0
  37. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/space.py +0 -0
  38. {qulab-2.1.1 → qulab-2.1.2}/qulab/scan/utils.py +0 -0
  39. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/__init__.py +0 -0
  40. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/__main__.py +0 -0
  41. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/backend/__init__.py +0 -0
  42. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/backend/redis.py +0 -0
  43. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/base_dataset.py +0 -0
  44. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/chunk.py +0 -0
  45. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/dataset.py +0 -0
  46. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/file.py +0 -0
  47. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/__init__.py +0 -0
  48. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/base.py +0 -0
  49. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/config.py +0 -0
  50. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/file.py +0 -0
  51. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/ipy.py +0 -0
  52. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/models.py +0 -0
  53. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/record.py +0 -0
  54. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/report.py +0 -0
  55. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/models/tag.py +0 -0
  56. {qulab-2.1.1 → qulab-2.1.2}/qulab/storage/storage.py +0 -0
  57. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/__init__.py +0 -0
  58. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/chat.py +0 -0
  59. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/device/__init__.py +0 -0
  60. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/device/basedevice.py +0 -0
  61. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/device/loader.py +0 -0
  62. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/device/utils.py +0 -0
  63. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/drivers/FakeInstrument.py +0 -0
  64. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/drivers/__init__.py +0 -0
  65. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/ipy_events.py +0 -0
  66. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/__init__.py +0 -0
  67. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/bencoder.py +0 -0
  68. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/cli.py +0 -0
  69. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/dhcp.py +0 -0
  70. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/dhcpd.py +0 -0
  71. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/kad.py +0 -0
  72. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/kcp.py +0 -0
  73. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/net/nginx.py +0 -0
  74. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/progress.py +0 -0
  75. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/__init__.py +0 -0
  76. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/client.py +0 -0
  77. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/exceptions.py +0 -0
  78. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/msgpack.py +0 -0
  79. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/msgpack.pyi +0 -0
  80. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/rpc.py +0 -0
  81. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/serialize.py +0 -0
  82. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/server.py +0 -0
  83. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/socket.py +0 -0
  84. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/utils.py +0 -0
  85. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/worker.py +0 -0
  86. {qulab-2.1.1 → qulab-2.1.2}/qulab/sys/rpc/zmq_socket.py +0 -0
  87. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/__init__.py +0 -0
  88. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/__main__.py +0 -0
  89. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/_autoplot.py +0 -0
  90. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/plot_layout.py +0 -0
  91. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/plot_seq.py +0 -0
  92. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/qdat.py +0 -0
  93. {qulab-2.1.1 → qulab-2.1.2}/qulab/visualization/widgets.py +0 -0
  94. {qulab-2.1.1 → qulab-2.1.2}/setup.cfg +0 -0
  95. {qulab-2.1.1 → qulab-2.1.2}/setup.py +0 -0
  96. {qulab-2.1.1 → qulab-2.1.2}/src/qulab.h +0 -0
  97. {qulab-2.1.1 → qulab-2.1.2}/tests/test_scan.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.1.1
3
+ Version: 2.1.2
4
4
  Summary: contral instruments and manage data
5
5
  Author-email: feihoo87 <feihoo87@gmail.com>
6
6
  Maintainer-email: feihoo87 <feihoo87@gmail.com>
@@ -0,0 +1,3 @@
1
+ from .scan import Scan, get_record, load_record, lookup, lookup_list
2
+ from .version import __version__
3
+ from .visualization import autoplot
@@ -1,3 +1,3 @@
1
1
  from .expression import Expression, Symbol
2
- from .query import get_record, lookup, lookup_list
2
+ from .query import get_record, load_record, lookup, lookup_list
3
3
  from .scan import Scan
@@ -6,10 +6,13 @@ import dill
6
6
  import ipywidgets as widgets
7
7
  import zmq
8
8
  from IPython.display import display
9
+ from sqlalchemy import create_engine
10
+ from sqlalchemy.orm import sessionmaker
9
11
 
10
12
  from qulab.sys.rpc.zmq_socket import ZMQContextManager
11
13
 
12
14
  from .record import Record
15
+ from .recorder import get_local_record
13
16
  from .scan import default_server
14
17
 
15
18
 
@@ -26,18 +29,15 @@ def get_record(id, database=default_server) -> Record:
26
29
  d._file = None
27
30
  return d
28
31
  else:
29
- from .models import Record as RecordInDB
30
- from .models import create_engine, sessionmaker
31
-
32
32
  db_file = Path(database) / 'data.db'
33
33
  engine = create_engine(f'sqlite:///{db_file}')
34
34
  Session = sessionmaker(bind=engine)
35
35
  with Session() as session:
36
- path = Path(database) / 'objects' / session.get(RecordInDB,
37
- id).file
38
- with open(path, 'rb') as f:
39
- record = dill.load(f)
40
- return record
36
+ return get_local_record(session, id, database)
37
+
38
+
39
+ def load_record(file):
40
+ return Record.load(file)
41
41
 
42
42
 
43
43
  def _format_tag(tag):
@@ -1,6 +1,7 @@
1
1
  import itertools
2
2
  import sys
3
3
  import uuid
4
+ import zipfile
4
5
  from pathlib import Path
5
6
  from threading import Lock
6
7
  from types import EllipsisType
@@ -13,7 +14,7 @@ from qulab.sys.rpc.zmq_socket import ZMQContextManager
13
14
 
14
15
  from .space import OptimizeSpace, Space
15
16
 
16
- _notgiven = object()
17
+ _not_given = object()
17
18
 
18
19
 
19
20
  def random_path(base):
@@ -120,6 +121,18 @@ class BufferList():
120
121
  yield pos, value
121
122
  except EOFError:
122
123
  break
124
+ elif isinstance(
125
+ self.file, tuple) and len(self.file) == 2 and isinstance(
126
+ self.file[0], str) and self.file[0].endswith('.zip'):
127
+ f, name = self.file
128
+ with zipfile.ZipFile(f, 'r') as z:
129
+ with z.open(name, 'r') as f:
130
+ while True:
131
+ try:
132
+ pos, value = dill.load(f)
133
+ yield pos, value
134
+ except EOFError:
135
+ break
123
136
 
124
137
  def iter(self):
125
138
  if self._data_id is None:
@@ -327,7 +340,7 @@ class Record():
327
340
  ret = ret.toarray()
328
341
  return ret
329
342
 
330
- def get(self, key, default=_notgiven, buffer_to_array=False, slice=None):
343
+ def get(self, key, default=_not_given, buffer_to_array=False, slice=None):
331
344
  if self.is_remote_record():
332
345
  with ZMQContextManager(zmq.DEALER,
333
346
  connect=self.database) as socket:
@@ -355,7 +368,7 @@ class Record():
355
368
  else:
356
369
  return ret
357
370
  else:
358
- if default is _notgiven:
371
+ if default is _not_given:
359
372
  d = self._items.get(key)
360
373
  else:
361
374
  d = self._items.get(key, default)
@@ -437,6 +450,40 @@ class Record():
437
450
  with open(self._file, 'wb') as f:
438
451
  dill.dump(self, f)
439
452
 
453
+ def export(self, file):
454
+ with zipfile.ZipFile(file,
455
+ 'w',
456
+ compression=zipfile.ZIP_DEFLATED,
457
+ compresslevel=9) as z:
458
+ items = {}
459
+ for key in self.keys():
460
+ value = self.get(key)
461
+ if isinstance(value, BufferList):
462
+ v = BufferList()
463
+ v.lu = value.lu
464
+ v.rd = value.rd
465
+ v.inner_shape = value.inner_shape
466
+ items[key] = v
467
+ with z.open(f'{key}.buf', 'w') as f:
468
+ for pos, data in value.iter():
469
+ dill.dump((pos, data), f)
470
+ else:
471
+ items[key] = value
472
+ with z.open('record.pkl', 'w') as f:
473
+ dill.dump((self.description, items), f)
474
+
475
+ @classmethod
476
+ def load(cls, file: str):
477
+ with zipfile.ZipFile(file, 'r') as z:
478
+ with z.open('record.pkl', 'r') as f:
479
+ description, items = dill.load(f)
480
+ record = cls(None, None, description)
481
+ for key, value in items.items():
482
+ if isinstance(value, BufferList):
483
+ value.file = file, f'{key}.buf'
484
+ record._items[key] = value
485
+ return record
486
+
440
487
  def __repr__(self):
441
488
  return f"<Record: id={self.id} app={self.description['app']}, keys={self.keys()}>"
442
489
 
@@ -28,6 +28,7 @@ else:
28
28
  datapath.mkdir(parents=True, exist_ok=True)
29
29
 
30
30
  record_cache = {}
31
+ CACHE_SIZE = 1024
31
32
 
32
33
 
33
34
  class Request():
@@ -45,11 +46,11 @@ async def reply(req, resp):
45
46
 
46
47
 
47
48
  def clear_cache():
48
- if len(record_cache) < 1024:
49
+ if len(record_cache) < CACHE_SIZE:
49
50
  return
50
51
 
51
52
  for k, (t, _) in zip(sorted(record_cache.items(), key=lambda x: x[1][0]),
52
- range(len(record_cache) - 1024)):
53
+ range(len(record_cache) - CACHE_SIZE)):
53
54
  del record_cache[k]
54
55
 
55
56
 
@@ -58,15 +59,20 @@ def flush_cache():
58
59
  r.flush()
59
60
 
60
61
 
62
+ def get_local_record(session: Session, id: int, datapath: Path) -> Record:
63
+ record_in_db = session.get(RecordInDB, id)
64
+ record_in_db.atime = utcnow()
65
+ path = datapath / 'objects' / record_in_db.file
66
+ with open(path, 'rb') as f:
67
+ record = dill.load(f)
68
+ record.database = datapath
69
+ record._file = path
70
+ return record
71
+
72
+
61
73
  def get_record(session: Session, id: int, datapath: Path) -> Record:
62
74
  if id not in record_cache:
63
- record_in_db = session.get(RecordInDB, id)
64
- record_in_db.atime = utcnow()
65
- path = datapath / 'objects' / record_in_db.file
66
- with open(path, 'rb') as f:
67
- record = dill.load(f)
68
- record.database = datapath
69
- record._file = path
75
+ record = get_local_record(session, id, datapath)
70
76
  else:
71
77
  record = record_cache[id][1]
72
78
  clear_cache()
@@ -46,6 +46,10 @@ if os.getenv('QULAB_SERVER'):
46
46
  default_server = os.getenv('QULAB_SERVER')
47
47
  else:
48
48
  default_server = f'tcp://127.0.0.1:{default_record_port}'
49
+ if os.getenv('QULAB_EXECUTOR'):
50
+ default_executor = os.getenv('QULAB_EXECUTOR')
51
+ else:
52
+ default_executor = default_server
49
53
 
50
54
 
51
55
  def task_uuid():
@@ -136,6 +140,7 @@ class Scan():
136
140
  'app': app,
137
141
  'tags': tags,
138
142
  'loops': {},
143
+ 'intrinsic_loops': {},
139
144
  'consts': {},
140
145
  'functions': {},
141
146
  'getters': {},
@@ -287,10 +292,10 @@ class Scan():
287
292
  else:
288
293
  return Symbol(name)
289
294
 
290
- def _add_loop_var(self, name: str, level: int, range):
295
+ def _add_search_space(self, name: str, level: int, space):
291
296
  if level not in self.description['loops']:
292
297
  self.description['loops'][level] = []
293
- self.description['loops'][level].append((name, range))
298
+ self.description['loops'][level].append((name, space))
294
299
 
295
300
  def add_depends(self, name: str, depends: list[str]):
296
301
  if isinstance(depends, str):
@@ -299,7 +304,7 @@ class Scan():
299
304
  self.description['dependents'][name] = set()
300
305
  self.description['dependents'][name].update(depends)
301
306
 
302
- def add_filter(self, func: Callable, level: int):
307
+ def add_filter(self, func: Callable, level: int = -1):
303
308
  """
304
309
  Add a filter function to the scan.
305
310
 
@@ -345,26 +350,33 @@ class Scan():
345
350
 
346
351
  def search(self,
347
352
  name: str,
348
- range: Iterable | Expression | Callable | OptimizeSpace,
353
+ space: Iterable | Expression | Callable | OptimizeSpace,
349
354
  level: int | None = None,
350
- setter: Callable | None = None):
355
+ setter: Callable | None = None,
356
+ intrinsic: bool = False):
351
357
  if level is not None:
352
- assert level >= 0, 'level must be greater than or equal to 0.'
353
- if isinstance(range, OptimizeSpace):
354
- range.name = name
355
- range.optimizer.dimensions[name] = range.space
356
- self._add_loop_var(name, range.optimizer.level, range)
357
- self.add_depends(range.optimizer.name, [name])
358
+ if not intrinsic:
359
+ assert level >= 0, 'level must be greater than or equal to 0.'
360
+ if intrinsic:
361
+ assert isinstance(space, (np.ndarray, list, tuple, range, Space)), \
362
+ 'space must be an instance of np.ndarray, list, tuple, range or Space.'
363
+ self.description['intrinsic_loops'][name] = level
364
+ self.set(name, space)
365
+ elif isinstance(space, OptimizeSpace):
366
+ space.name = name
367
+ space.optimizer.dimensions[name] = space.space
368
+ self._add_search_space(name, space.optimizer.level, space)
369
+ self.add_depends(space.optimizer.name, [name])
358
370
  else:
359
371
  if level is None:
360
372
  raise ValueError('level must be provided.')
361
373
  try:
362
- range = Space.fromarray(range)
374
+ space = Space.fromarray(space)
363
375
  except:
364
376
  pass
365
- self._add_loop_var(name, level, range)
366
- if isinstance(range, Expression) or callable(range):
367
- self.add_depends(name, range.symbols())
377
+ self._add_search_space(name, level, space)
378
+ if isinstance(space, Expression) or callable(space):
379
+ self.add_depends(name, space.symbols())
368
380
  if setter:
369
381
  self.description['setters'][name] = setter
370
382
 
@@ -500,7 +512,7 @@ class Scan():
500
512
  import asyncio
501
513
  self._main_task = asyncio.create_task(self.run())
502
514
 
503
- async def submit(self, server='tcp://127.0.0.1:6788'):
515
+ async def submit(self, server=default_executor):
504
516
  assymbly(self.description)
505
517
  async with ZMQContextManager(zmq.DEALER, connect=server) as socket:
506
518
  await socket.send_pyobj({
@@ -740,7 +752,7 @@ def assymbly(description):
740
752
  keys -= set(ready)
741
753
 
742
754
  axis = {}
743
- independent_variables = set()
755
+ independent_variables = set(description['intrinsic_loops'].keys())
744
756
 
745
757
  for name in description['consts']:
746
758
  axis[name] = ()
@@ -0,0 +1 @@
1
+ __version__ = "2.1.2"
@@ -1 +0,0 @@
1
- from .version import __version__
@@ -1 +0,0 @@
1
- __version__ = "2.1.1"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes