QuLab 2.2.3__cp312-cp312-win_amd64.whl → 2.2.5__cp312-cp312-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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: QuLab
3
- Version: 2.2.3
3
+ Version: 2.2.5
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,7 +1,7 @@
1
1
  qulab/__init__.py,sha256=vkFybY8YSsQilYdThPRD83-btPAR41sy_WCXiM-6mME,141
2
2
  qulab/__main__.py,sha256=V7iokU7awstgjCeiF_hoOdFyrqJwC_4QetiLe7cWvOQ,454
3
- qulab/fun.cp312-win_amd64.pyd,sha256=2t7RpwvU1lE3bd7l089Xj3XUJszO9Bz8ZeBlIfG4HfY,32256
4
- qulab/version.py,sha256=Nt4yGCnk6mAxHxAbWGL2m0dPsKn_yhp3_F9LBmkhnvI,21
3
+ qulab/fun.cp312-win_amd64.pyd,sha256=2bsHNMUaHgDI2Hdtivzp8n6F8T-iO9HkaoTVVD6dwP0,32256
4
+ qulab/version.py,sha256=zyH0HuxKprjHeDzaU3CDFspw9f0RqC0qcLriAPqWD_M,21
5
5
  qulab/monitor/__init__.py,sha256=xEVDkJF8issrsDeLqQmDsvtRmrf-UiViFcGTWuzdlFU,43
6
6
  qulab/monitor/__main__.py,sha256=k2H1H5Zf9LLXTDLISJkbikLH-z0f1e5i5i6wXXYPOrE,105
7
7
  qulab/monitor/config.py,sha256=y_5StMkdrbZO1ziyKBrvIkB7Jclp9RCPK1QbsOhCxnY,785
@@ -17,11 +17,11 @@ qulab/scan/curd.py,sha256=yaTglGiS6mlk0GqDHi_w8T02XGBMvDZtXSdML7zDywk,7117
17
17
  qulab/scan/expression.py,sha256=vwUM9E0OFQal4bljlUtLR3NJu4zGRyuWYrdyZSs3QTU,16199
18
18
  qulab/scan/models.py,sha256=ZvXkJEt5Yz3Sjx0JKzYka-q2Uo-w_iVzHgH8A6DbjF0,18236
19
19
  qulab/scan/optimize.py,sha256=MlT4y422CnP961IR384UKryyZh8riNvrPSd2z_MXLEg,2356
20
- qulab/scan/query.py,sha256=ejxaejMVwvYkSIGMPb95OU3DjMVWy3ID-Ea8mtsbxIc,11917
21
- qulab/scan/record.py,sha256=iCGkzIAFPYnT6idc--VloEVtyJPnHr35xt09lqtX674,20150
22
- qulab/scan/scan.py,sha256=fNpcL5KKSAGA1y6qteSxmH0Ii_I3IdDv5-ihhx1HUAs,35457
23
- qulab/scan/server.py,sha256=h5CPS1zKtBs0cKvEBdmT8_EQ_cxyX8VXGEjPlk9iD2I,12549
24
- qulab/scan/space.py,sha256=PBa7Z6KnS690x79WS2YU3PTA_s5K6MCJ6JmS93vs2s4,5381
20
+ qulab/scan/query.py,sha256=z94Ofbii4HZ4ZyZ7nos9-y37bH8-Xg4mA3QsF_aWx-c,11907
21
+ qulab/scan/record.py,sha256=crlNIm1ki6td2Z284D78M276aso7KhMnr4qjCCOj1Kk,21644
22
+ qulab/scan/scan.py,sha256=CNX2Z6vWMax9SqBWWYLghkz6TwIaLNnKypeyS7UCTfA,35773
23
+ qulab/scan/server.py,sha256=ZWTnlK_YMfPTCoq6GnGpsZzSFGyoO4qF7aEGW9wCwhM,14542
24
+ qulab/scan/space.py,sha256=fWsY99HDauk89f5ygqnJYBoeNFGTUkAGFssrw-YMHok,5453
25
25
  qulab/scan/utils.py,sha256=30qnYvyFyctwcWxOCUpCNxXgGysA7xdIDzYbjwxGUzA,3744
26
26
  qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  qulab/storage/__main__.py,sha256=6-EjN0waX1yfcMPJXqpIr9UlrIEsSCFApm5G-ZeaPMQ,1742
@@ -78,9 +78,9 @@ qulab/visualization/plot_layout.py,sha256=yAnMONOms7_szCdng-8wPpUMPis5UnbaNNzV4K
78
78
  qulab/visualization/plot_seq.py,sha256=h9D0Yl_yO64IwlvBgzMu9EBKr9gg6y8QE55gu2PfTns,2783
79
79
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
80
80
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
81
- QuLab-2.2.3.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
82
- QuLab-2.2.3.dist-info/METADATA,sha256=QjGRvgbe0XCIgNaV05AHTHgLWLvbd5kaJi9Ceo73Pgc,3609
83
- QuLab-2.2.3.dist-info/WHEEL,sha256=fZWyj_84lK0cA-ZNCsdwhbJl0OTrpWkxInEn424qrSs,102
84
- QuLab-2.2.3.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
85
- QuLab-2.2.3.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
86
- QuLab-2.2.3.dist-info/RECORD,,
81
+ QuLab-2.2.5.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
82
+ QuLab-2.2.5.dist-info/METADATA,sha256=BspoYai-nQ5IQpf_AqvzYlKLZ3QZwUfDbw9Cz_73yME,3609
83
+ QuLab-2.2.5.dist-info/WHEEL,sha256=fZWyj_84lK0cA-ZNCsdwhbJl0OTrpWkxInEn424qrSs,102
84
+ QuLab-2.2.5.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
85
+ QuLab-2.2.5.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
86
+ QuLab-2.2.5.dist-info/RECORD,,
Binary file
qulab/scan/query.py CHANGED
@@ -24,7 +24,7 @@ def get_record(id, database=default_server) -> Record:
24
24
  'record_id': id
25
25
  })
26
26
  d = dill.loads(socket.recv_pyobj())
27
- if isinstance(d, None):
27
+ if d is None:
28
28
  raise ValueError(f'No record with id {id}')
29
29
  d.id = id
30
30
  d.database = database
qulab/scan/record.py CHANGED
@@ -115,7 +115,8 @@ class BufferList():
115
115
  self.inner_shape = value.shape
116
116
  elif self.inner_shape != value.shape:
117
117
  self.inner_shape = ()
118
- self._list.append((pos, value))
118
+ with self._lock:
119
+ self._list.append((pos, value))
119
120
  if len(self._list) > 1000:
120
121
  self.flush()
121
122
 
@@ -156,14 +157,29 @@ class BufferList():
156
157
  else:
157
158
  server, record_id, key = self._data_id
158
159
  with ZMQContextManager(zmq.DEALER, connect=server) as socket:
159
- socket.send_pyobj({
160
- 'method': 'bufferlist_slice',
161
- 'record_id': record_id,
162
- 'key': key,
163
- 'slice': self._slice
164
- })
165
- ret = socket.recv_pyobj()
166
- yield from ret
160
+ iter_id = b''
161
+ start = 0
162
+ try:
163
+ while True:
164
+ socket.send_pyobj({
165
+ 'method': 'bufferlist_iter',
166
+ 'record_id': record_id,
167
+ 'iter_id': iter_id,
168
+ 'key': key,
169
+ 'slice': self._slice,
170
+ 'start': start
171
+ })
172
+ iter_id, lst, finished = socket.recv_pyobj()
173
+ start += len(lst)
174
+ yield from lst
175
+ if finished:
176
+ break
177
+ finally:
178
+ if iter_id:
179
+ socket.send_pyobj({
180
+ 'method': 'bufferlist_iter_exit',
181
+ 'iter_id': iter_id
182
+ })
167
183
 
168
184
  def value(self):
169
185
  d = []
@@ -304,6 +320,14 @@ class Record():
304
320
  self._last_vars = set()
305
321
  self._file = None
306
322
 
323
+ for name, value in self.description['intrinsic_loops'].items():
324
+ self._items[name] = value
325
+
326
+ for level, range_list in description['loops'].items():
327
+ for name, iterable in range_list:
328
+ if name in self.description['independent_variables']:
329
+ self._items[name] = iterable
330
+
307
331
  if self.is_local_record():
308
332
  self.database = Path(self.database)
309
333
  self._file = random_path(self.database / 'objects')
@@ -395,6 +419,11 @@ class Record():
395
419
  else:
396
420
  ret._data_id = self.database, self.id, key
397
421
  return ret
422
+ elif isinstance(ret, Space):
423
+ if buffer_to_array:
424
+ return ret.toarray()
425
+ else:
426
+ return ret
398
427
  else:
399
428
  return ret
400
429
  else:
@@ -410,6 +439,11 @@ class Record():
410
439
  return d.array()
411
440
  else:
412
441
  return d
442
+ elif isinstance(d, Space):
443
+ if buffer_to_array:
444
+ return d.toarray()
445
+ else:
446
+ return d
413
447
  else:
414
448
  return d
415
449
 
@@ -516,6 +550,8 @@ class Record():
516
550
  with z.open('record.pkl', 'w') as f:
517
551
  self.description['entry']['scripts'] = self.scripts()
518
552
  dill.dump((self.description, items), f)
553
+ with z.open('config.pkl', 'w') as f:
554
+ f.write(dill.dumps(self.config()))
519
555
 
520
556
  def scripts(self, session=None):
521
557
  scripts = self.description['entry']['scripts']
qulab/scan/scan.py CHANGED
@@ -225,6 +225,7 @@ class Scan():
225
225
  dump_globals: bool = False,
226
226
  max_workers: int = 4,
227
227
  max_promise: int = 100,
228
+ max_message: int = 1000,
228
229
  mixin=None):
229
230
  self.id = task_uuid()
230
231
  self.record = None
@@ -265,11 +266,12 @@ class Scan():
265
266
  self._sem = asyncio.Semaphore(max_promise + 1)
266
267
  self._bar: dict[int, tqdm] = {}
267
268
  self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
268
- self._msg_queue = asyncio.Queue()
269
+ self._msg_queue = asyncio.Queue(max_message)
269
270
  self._prm_queue = asyncio.Queue()
270
271
  self._single_step = True
271
272
  self._max_workers = max_workers
272
273
  self._max_promise = max_promise
274
+ self._max_message = max_message
273
275
  self._executors = ProcessPoolExecutor(max_workers=max_workers)
274
276
 
275
277
  def __del__(self):
@@ -297,7 +299,7 @@ class Scan():
297
299
  self._main_task = None
298
300
  self._bar = {}
299
301
  self._prm_queue = asyncio.Queue()
300
- self._msg_queue = asyncio.Queue()
302
+ self._msg_queue = asyncio.Queue(self._max_message)
301
303
  self._sem = asyncio.Semaphore(self._max_promise + 1)
302
304
  self._executors = ProcessPoolExecutor(max_workers=self._max_workers)
303
305
  for opt in self.description['optimizers'].values():
@@ -344,8 +346,9 @@ class Scan():
344
346
  for k, v in variables.items() if not self.hiden(k)
345
347
  })
346
348
 
347
- def emit(self, current_level, step, position, variables: dict[str, Any]):
348
- self._msg_queue.put_nowait(
349
+ async def emit(self, current_level, step, position, variables: dict[str,
350
+ Any]):
351
+ await self._msg_queue.put(
349
352
  self._emit(current_level, step, position, variables.copy()))
350
353
 
351
354
  def hide(self, name: str):
@@ -561,7 +564,7 @@ class Scan():
561
564
  await self._run()
562
565
 
563
566
  async def _run(self):
564
- send_msg = asyncio.create_task(self._send_msg())
567
+ send_msg_task = asyncio.create_task(self._send_msg())
565
568
  update_progress_task = asyncio.create_task(self._update_progress())
566
569
 
567
570
  self._variables = {'self': self}
@@ -596,13 +599,13 @@ class Scan():
596
599
  self.description['order'].get(-1, []),
597
600
  self.description['getters'], self.variables))
598
601
 
599
- self.emit(0, 0, 0, self.variables)
600
- self.emit(-1, 0, 0, {})
602
+ await self.emit(0, 0, 0, self.variables)
603
+ await self.emit(-1, 0, 0, {})
601
604
 
602
605
  await self._prm_queue.join()
603
606
  update_progress_task.cancel()
604
607
  await self._msg_queue.join()
605
- send_msg.cancel()
608
+ send_msg_task.cancel()
606
609
  return self.variables
607
610
 
608
611
  async def done(self):
@@ -623,11 +626,14 @@ class Scan():
623
626
  assymbly(self.description)
624
627
  async with ZMQContextManager(zmq.DEALER, connect=server) as socket:
625
628
  await socket.send_pyobj({
626
- 'method': 'submit',
629
+ 'method': 'task_submit',
627
630
  'description': dill.dumps(self.description)
628
631
  })
629
632
  self.id = await socket.recv_pyobj()
630
- await socket.send_pyobj({'method': 'get_record_id', 'id': self.id})
633
+ await socket.send_pyobj({
634
+ 'method': 'task_get_record_id',
635
+ 'id': self.id
636
+ })
631
637
  record_id = await socket.recv_pyobj()
632
638
  self.record = Record(record_id, self.description['database'],
633
639
  self.description)
@@ -661,14 +667,15 @@ class Scan():
661
667
  if await self._filter(variables, self.current_level - 1):
662
668
  yield variables
663
669
  self._single_step = False
664
- self.emit(self.current_level - 1, step, position, variables)
670
+ await self.emit(self.current_level - 1, step, position,
671
+ variables)
665
672
  step += 1
666
673
  position += 1
667
674
  self._current_level -= 1
668
675
  self._prm_queue.put_nowait(
669
676
  self._update_progress_bar(self.current_level, 1))
670
677
  if self.current_level == 0:
671
- self.emit(self.current_level - 1, 0, 0, {})
678
+ await self.emit(self.current_level - 1, 0, 0, {})
672
679
  for name, value in self.variables.items():
673
680
  if inspect.isawaitable(value):
674
681
  self.variables[name] = await value
qulab/scan/server.py CHANGED
@@ -2,6 +2,7 @@ import asyncio
2
2
  import os
3
3
  import pickle
4
4
  import time
5
+ import uuid
5
6
  from pathlib import Path
6
7
 
7
8
  import click
@@ -29,7 +30,9 @@ else:
29
30
  datapath = Path.home() / 'qulab' / 'data'
30
31
  datapath.mkdir(parents=True, exist_ok=True)
31
32
 
33
+ namespace = uuid.uuid4()
32
34
  record_cache = {}
35
+ buffer_list_cache = {}
33
36
  CACHE_SIZE = 1024
34
37
 
35
38
  pool = {}
@@ -44,6 +47,9 @@ class Request():
44
47
  self.msg = pickle.loads(msg)
45
48
  self.method = self.msg.get('method', '')
46
49
 
50
+ def __repr__(self):
51
+ return f"Request({self.method})"
52
+
47
53
 
48
54
  async def reply(req, resp):
49
55
  await req.sock.send_multipart([req.identity, pickle.dumps(resp)])
@@ -57,6 +63,11 @@ def clear_cache():
57
63
  range(len(record_cache) - CACHE_SIZE)):
58
64
  del record_cache[k]
59
65
 
66
+ for k, (t,
67
+ _) in zip(sorted(buffer_list_cache.items(), key=lambda x: x[1][0]),
68
+ range(len(buffer_list_cache) - CACHE_SIZE)):
69
+ del buffer_list_cache[k]
70
+
60
71
 
61
72
  def flush_cache():
62
73
  for k, (t, r) in record_cache.items():
@@ -142,12 +153,37 @@ async def handle(session: Session, request: Request, datapath: Path):
142
153
  match request.method:
143
154
  case 'ping':
144
155
  await reply(request, 'pong')
145
- case 'bufferlist_slice':
146
- record = get_record(session, msg['record_id'], datapath)
147
- bufferlist = record.get(msg['key'],
148
- buffer_to_array=False,
149
- slice=msg['slice'])
150
- await reply(request, list(bufferlist.iter()))
156
+ case 'bufferlist_iter':
157
+ if msg['iter_id'] in buffer_list_cache:
158
+ it = buffer_list_cache[msg['iter_id']][1]
159
+ iter_id = msg['iter_id']
160
+ else:
161
+ iter_id = uuid.uuid3(namespace, str(time.time_ns())).bytes
162
+ record = get_record(session, msg['record_id'], datapath)
163
+ bufferlist = record.get(msg['key'],
164
+ buffer_to_array=False,
165
+ slice=msg['slice'])
166
+ it = bufferlist.iter()
167
+ for _, _ in zip(range(msg['start']), it):
168
+ pass
169
+ current_time = time.time()
170
+ ret, end = [], False
171
+ while time.time() - current_time < 0.02:
172
+ try:
173
+ ret.append(next(it))
174
+ except StopIteration:
175
+ end = True
176
+ break
177
+ await reply(request, (iter_id, ret, end))
178
+ buffer_list_cache[iter_id] = time.time(), it
179
+ clear_cache()
180
+ case 'bufferlist_iter_exit':
181
+ try:
182
+ it = buffer_list_cache.pop(msg['iter_id'])[1]
183
+ it.throw(Exception)
184
+ except:
185
+ pass
186
+ clear_cache()
151
187
  case 'record_create':
152
188
  description = dill.loads(msg['description'])
153
189
  await reply(request, record_create(session, description, datapath))
@@ -220,7 +256,7 @@ async def handle(session: Session, request: Request, datapath: Path):
220
256
  'objects').parts[-4:]))
221
257
  session.commit()
222
258
  await reply(request, config.id)
223
- case 'submit':
259
+ case 'task_submit':
224
260
  from .scan import Scan
225
261
  finished = [(id, queried) for id, (task, queried) in pool.items()
226
262
  if not isinstance(task, int) and task.finished()]
@@ -235,7 +271,7 @@ async def handle(session: Session, request: Request, datapath: Path):
235
271
  task.start()
236
272
  pool[task.id] = [task, False]
237
273
  await reply(request, task.id)
238
- case 'get_record_id':
274
+ case 'task_get_record_id':
239
275
  task, queried = pool.get(msg['id'])
240
276
  if isinstance(task, int):
241
277
  await reply(request, task)
@@ -249,15 +285,28 @@ async def handle(session: Session, request: Request, datapath: Path):
249
285
  await asyncio.sleep(1)
250
286
  else:
251
287
  await reply(request, None)
288
+ case 'task_get_progress':
289
+ task, _ = pool.get(msg['id'])
290
+ if isinstance(task, int):
291
+ await reply(request, 1)
292
+ else:
293
+ await reply(request,
294
+ [(bar.n, bar.total) for bar in task._bar.values()])
252
295
  case _:
253
296
  logger.error(f"Unknown method: {msg['method']}")
254
297
 
255
298
 
256
- async def _handle(session: Session, request: Request, datapath: Path):
299
+ async def handle_with_timeout(session: Session, request: Request,
300
+ datapath: Path, timeout: float):
257
301
  try:
258
- await handle(session, request, datapath)
259
- except:
260
- await reply(request, 'error')
302
+ await asyncio.wait_for(handle(session, request, datapath),
303
+ timeout=timeout)
304
+ except asyncio.TimeoutError:
305
+ logger.warning(
306
+ f"Task handling request {request} timed out and was cancelled.")
307
+ await reply(request, 'timeout')
308
+ except Exception as e:
309
+ await reply(request, f'{e!r}')
261
310
 
262
311
 
263
312
  async def serv(port,
@@ -280,7 +329,8 @@ async def serv(port,
280
329
  identity, msg = await sock.recv_multipart()
281
330
  received += len(msg)
282
331
  req = Request(sock, identity, msg)
283
- asyncio.create_task(_handle(session, req, datapath))
332
+ asyncio.create_task(
333
+ handle_with_timeout(session, req, datapath, timeout=60.0))
284
334
  if received > buffer_size or time.time(
285
335
  ) - last_flush_time > interval:
286
336
  flush_cache()
qulab/scan/space.py CHANGED
@@ -28,6 +28,8 @@ class Space():
28
28
  return space
29
29
  if isinstance(space, (list, tuple)):
30
30
  array = np.array(space)
31
+ elif isinstance(space, np.ndarray):
32
+ array = space
31
33
  try:
32
34
  a = np.linspace(array[0], array[-1], len(array), dtype=array.dtype)
33
35
  if np.allclose(a, array):
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.2.3"
1
+ __version__ = "2.2.5"
File without changes
File without changes