QuLab 2.0.5__cp312-cp312-macosx_10_9_universal2.whl → 2.0.6__cp312-cp312-macosx_10_9_universal2.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-2.0.5.dist-info → QuLab-2.0.6.dist-info}/METADATA +1 -1
- {QuLab-2.0.5.dist-info → QuLab-2.0.6.dist-info}/RECORD +10 -10
- qulab/fun.cpython-312-darwin.so +0 -0
- qulab/scan/recorder.py +188 -68
- qulab/scan/scan.py +7 -4
- qulab/version.py +1 -1
- {QuLab-2.0.5.dist-info → QuLab-2.0.6.dist-info}/LICENSE +0 -0
- {QuLab-2.0.5.dist-info → QuLab-2.0.6.dist-info}/WHEEL +0 -0
- {QuLab-2.0.5.dist-info → QuLab-2.0.6.dist-info}/entry_points.txt +0 -0
- {QuLab-2.0.5.dist-info → QuLab-2.0.6.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
qulab/__init__.py,sha256=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
|
|
2
2
|
qulab/__main__.py,sha256=eupSsrNVfnTFRpjgrY_knPvZIs0-Dk577LaN7qB15hI,487
|
|
3
|
-
qulab/fun.cpython-312-darwin.so,sha256=
|
|
4
|
-
qulab/version.py,sha256=
|
|
3
|
+
qulab/fun.cpython-312-darwin.so,sha256=rNmTa75srrkrXtW47WdDpa4l8GHWb398TVY2P4JUPoQ,159632
|
|
4
|
+
qulab/version.py,sha256=IoNlI2ogLAGBFo-lP1Eg_QnxTNCxj3o2OCiBaMyJrP8,21
|
|
5
5
|
qulab/monitor/__init__.py,sha256=nTHelnDpxRS_fl_B38TsN0njgq8eVTEz9IAnN3NbDlM,42
|
|
6
6
|
qulab/monitor/__main__.py,sha256=w3yUcqq195LzSnXTkQcuC1RSFRhy4oQ_PEBmucXguME,97
|
|
7
7
|
qulab/monitor/config.py,sha256=fQ5JcsMApKc1UwANEnIvbDQZl8uYW0tle92SaYtX9lI,744
|
|
@@ -18,8 +18,8 @@ qulab/scan/expression.py,sha256=-aTYbjFQNI1mwOcoSBztqhKfGJpu_n4a1QnWro_xnTU,1569
|
|
|
18
18
|
qulab/scan/models.py,sha256=S8Q9hC8nOzxyoNB10EYg-miDKqoNMnjyAECjD-TuORw,17117
|
|
19
19
|
qulab/scan/optimize.py,sha256=vErjRTCtn2MwMF5Xyhs1P4gHF2IFHv_EqxsUvH_4y7k,2287
|
|
20
20
|
qulab/scan/query_record.py,sha256=BVkNgv3yfbMXX_Kguq18fvowKOBmBiiTvUwj_CqpiF4,11493
|
|
21
|
-
qulab/scan/recorder.py,sha256=
|
|
22
|
-
qulab/scan/scan.py,sha256=
|
|
21
|
+
qulab/scan/recorder.py,sha256=0GXayspGWs-qFs5PZz25aMwTrl9Y0P-me0QDNmBQTeQ,22163
|
|
22
|
+
qulab/scan/scan.py,sha256=g-2o0zr_BU5Ky0DZ6ksbcxFMpQdNnRuv22WyphF2rjA,26033
|
|
23
23
|
qulab/scan/server.py,sha256=W8z3vr0cqSSKWzIG6_b0d-lpBpDXGpHSwN6VJuv3w9U,2844
|
|
24
24
|
qulab/scan/utils.py,sha256=n5yquKlz2QYMzciPgD9vkpBJVgzVzOqAlfvB4Qu6oOk,2551
|
|
25
25
|
qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -77,9 +77,9 @@ qulab/visualization/plot_layout.py,sha256=clNw9QjE_kVNpIIx2Ob4YhAz2fucPGMuzkoIrO
|
|
|
77
77
|
qulab/visualization/plot_seq.py,sha256=lphYF4VhkEdc_wWr1kFBwrx2yujkyFPFaJ3pjr61awI,2693
|
|
78
78
|
qulab/visualization/qdat.py,sha256=ZeevBYWkzbww4xZnsjHhw7wRorJCBzbG0iEu-XQB4EA,5735
|
|
79
79
|
qulab/visualization/widgets.py,sha256=6KkiTyQ8J-ei70LbPQZAK35wjktY47w2IveOa682ftA,3180
|
|
80
|
-
QuLab-2.0.
|
|
81
|
-
QuLab-2.0.
|
|
82
|
-
QuLab-2.0.
|
|
83
|
-
QuLab-2.0.
|
|
84
|
-
QuLab-2.0.
|
|
85
|
-
QuLab-2.0.
|
|
80
|
+
QuLab-2.0.6.dist-info/LICENSE,sha256=PRzIKxZtpQcH7whTG6Egvzl1A0BvnSf30tmR2X2KrpA,1065
|
|
81
|
+
QuLab-2.0.6.dist-info/METADATA,sha256=HXuU9olYtxNzfvx5keAhwCay9lNv0Mzs-7LXK5AuT4s,3510
|
|
82
|
+
QuLab-2.0.6.dist-info/WHEEL,sha256=aK27B_a3TQKBFhN_ATCfuFR4pBRqHlzwr7HpZ6iA79M,115
|
|
83
|
+
QuLab-2.0.6.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
|
|
84
|
+
QuLab-2.0.6.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
|
|
85
|
+
QuLab-2.0.6.dist-info/RECORD,,
|
qulab/fun.cpython-312-darwin.so
CHANGED
|
Binary file
|
qulab/scan/recorder.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import itertools
|
|
2
3
|
import os
|
|
3
4
|
import pickle
|
|
4
5
|
import sys
|
|
@@ -7,6 +8,7 @@ import uuid
|
|
|
7
8
|
from collections import defaultdict
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from threading import Lock
|
|
11
|
+
from types import EllipsisType
|
|
10
12
|
|
|
11
13
|
import click
|
|
12
14
|
import dill
|
|
@@ -44,52 +46,74 @@ def random_path(base):
|
|
|
44
46
|
return path
|
|
45
47
|
|
|
46
48
|
|
|
49
|
+
def index_in_slice(slice_obj: slice | int, index: int):
|
|
50
|
+
if isinstance(slice_obj, int):
|
|
51
|
+
return slice_obj == index
|
|
52
|
+
start, stop, step = slice_obj.start, slice_obj.stop, slice_obj.step
|
|
53
|
+
if start is None:
|
|
54
|
+
start = 0
|
|
55
|
+
if step is None:
|
|
56
|
+
step = 1
|
|
57
|
+
if stop is None:
|
|
58
|
+
stop = sys.maxsize
|
|
59
|
+
|
|
60
|
+
if step > 0:
|
|
61
|
+
return start <= index < stop and (index - start) % step == 0
|
|
62
|
+
else:
|
|
63
|
+
return stop < index <= start and (index - start) % step == 0
|
|
64
|
+
|
|
65
|
+
|
|
47
66
|
class BufferList():
|
|
48
67
|
|
|
49
|
-
def __init__(self,
|
|
50
|
-
self.
|
|
51
|
-
self._value = []
|
|
68
|
+
def __init__(self, file=None, slice=None):
|
|
69
|
+
self._list = []
|
|
52
70
|
self.lu = ()
|
|
53
71
|
self.rd = ()
|
|
54
|
-
self.
|
|
55
|
-
self.
|
|
72
|
+
self.inner_shape = None
|
|
73
|
+
self.file = file
|
|
74
|
+
self._slice = slice
|
|
56
75
|
self._lock = Lock()
|
|
76
|
+
self._database = None
|
|
77
|
+
|
|
78
|
+
def __repr__(self):
|
|
79
|
+
return f"<BufferList: lu={self.lu}, rd={self.rd}, slice={self._slice}>"
|
|
57
80
|
|
|
58
81
|
def __getstate__(self):
|
|
82
|
+
self.flush()
|
|
83
|
+
if isinstance(self.file, Path):
|
|
84
|
+
file = '/'.join(self.file.parts[-4:])
|
|
85
|
+
else:
|
|
86
|
+
file = self.file
|
|
59
87
|
return {
|
|
60
|
-
'
|
|
61
|
-
'value_file': self.value_file,
|
|
62
|
-
'_pos': self._pos,
|
|
63
|
-
'_value': self._value,
|
|
88
|
+
'file': file,
|
|
64
89
|
'lu': self.lu,
|
|
65
|
-
'rd': self.rd
|
|
90
|
+
'rd': self.rd,
|
|
91
|
+
'inner_shape': self.inner_shape,
|
|
66
92
|
}
|
|
67
93
|
|
|
68
94
|
def __setstate__(self, state):
|
|
69
|
-
self.
|
|
70
|
-
self.value_file = state['value_file']
|
|
71
|
-
self._pos = state['_pos']
|
|
72
|
-
self._value = state['_value']
|
|
95
|
+
self.file = state['file']
|
|
73
96
|
self.lu = state['lu']
|
|
74
97
|
self.rd = state['rd']
|
|
98
|
+
self.inner_shape = state['inner_shape']
|
|
99
|
+
self._list = []
|
|
100
|
+
self._slice = None
|
|
75
101
|
self._lock = Lock()
|
|
102
|
+
self._database = None
|
|
76
103
|
|
|
77
104
|
@property
|
|
78
105
|
def shape(self):
|
|
79
106
|
return tuple([i - j for i, j in zip(self.rd, self.lu)])
|
|
80
107
|
|
|
81
108
|
def flush(self):
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
for value in self._value:
|
|
91
|
-
dill.dump(value, f)
|
|
92
|
-
self._value.clear()
|
|
109
|
+
if not self._list:
|
|
110
|
+
return
|
|
111
|
+
if isinstance(self.file, Path):
|
|
112
|
+
with self._lock:
|
|
113
|
+
with open(self.file, 'ab') as f:
|
|
114
|
+
for item in self._list:
|
|
115
|
+
dill.dump(item, f)
|
|
116
|
+
self._list.clear()
|
|
93
117
|
|
|
94
118
|
def append(self, pos, value, dims=None):
|
|
95
119
|
if dims is not None:
|
|
@@ -98,45 +122,96 @@ class BufferList():
|
|
|
98
122
|
pos = tuple([pos[i] for i in dims])
|
|
99
123
|
self.lu = tuple([min(i, j) for i, j in zip(pos, self.lu)])
|
|
100
124
|
self.rd = tuple([max(i + 1, j) for i, j in zip(pos, self.rd)])
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
if hasattr(value, 'shape'):
|
|
126
|
+
if self.inner_shape is None:
|
|
127
|
+
self.inner_shape = value.shape
|
|
128
|
+
elif self.inner_shape != value.shape:
|
|
129
|
+
self.inner_shape = ()
|
|
130
|
+
self._list.append((pos, value))
|
|
131
|
+
if len(self._list) > 1000:
|
|
104
132
|
self.flush()
|
|
105
133
|
|
|
106
|
-
def
|
|
107
|
-
|
|
108
|
-
if self.value_file is not None and self.value_file.exists():
|
|
134
|
+
def _iter_file(self):
|
|
135
|
+
if isinstance(self.file, Path) and self.file.exists():
|
|
109
136
|
with self._lock:
|
|
110
|
-
with open(self.
|
|
137
|
+
with open(self.file, 'rb') as f:
|
|
111
138
|
while True:
|
|
112
139
|
try:
|
|
113
|
-
|
|
140
|
+
pos, value = dill.load(f)
|
|
141
|
+
yield pos, value
|
|
114
142
|
except EOFError:
|
|
115
143
|
break
|
|
116
|
-
|
|
117
|
-
|
|
144
|
+
|
|
145
|
+
def iter(self):
|
|
146
|
+
for pos, value in itertools.chain(self._iter_file(), self._list):
|
|
147
|
+
if not self._slice:
|
|
148
|
+
yield pos, value
|
|
149
|
+
elif all([index_in_slice(s, i) for s, i in zip(self._slice, pos)]):
|
|
150
|
+
yield pos, value[self._slice[len(pos):]]
|
|
151
|
+
|
|
152
|
+
def value(self):
|
|
153
|
+
d = []
|
|
154
|
+
for pos, value in self.iter():
|
|
155
|
+
d.append(value)
|
|
156
|
+
return d
|
|
118
157
|
|
|
119
158
|
def pos(self):
|
|
120
159
|
p = []
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
with open(self.pos_file, 'rb') as f:
|
|
124
|
-
while True:
|
|
125
|
-
try:
|
|
126
|
-
p.append(dill.load(f))
|
|
127
|
-
except EOFError:
|
|
128
|
-
break
|
|
129
|
-
p.extend(self._pos)
|
|
160
|
+
for pos, value in self.iter():
|
|
161
|
+
p.append(pos)
|
|
130
162
|
return p
|
|
131
163
|
|
|
164
|
+
def items(self):
|
|
165
|
+
p, d = [], []
|
|
166
|
+
for pos, value in self.iter():
|
|
167
|
+
p.append(pos)
|
|
168
|
+
d.append(value)
|
|
169
|
+
return p, d
|
|
170
|
+
|
|
132
171
|
def array(self):
|
|
133
|
-
pos =
|
|
134
|
-
|
|
172
|
+
pos, data = self.items()
|
|
173
|
+
pos = np.asarray(pos) - np.asarray(self.lu)
|
|
174
|
+
data = np.asarray(data)
|
|
135
175
|
inner_shape = data.shape[1:]
|
|
136
176
|
x = np.full(self.shape + inner_shape, np.nan, dtype=data[0].dtype)
|
|
137
177
|
x.__setitem__(tuple(pos.T), data)
|
|
138
178
|
return x
|
|
139
179
|
|
|
180
|
+
def _full_slice(self, slice_tuple: slice
|
|
181
|
+
| tuple[slice | int | EllipsisType, ...]):
|
|
182
|
+
if isinstance(slice_tuple, slice):
|
|
183
|
+
slice_tuple = (slice_tuple, ) + (slice(0, sys.maxsize,
|
|
184
|
+
1), ) * (len(self.lu) - 1)
|
|
185
|
+
if slice_tuple is Ellipsis:
|
|
186
|
+
slice_tuple = (slice(0, sys.maxsize, 1), ) * len(self.lu)
|
|
187
|
+
else:
|
|
188
|
+
head, tail = [], []
|
|
189
|
+
for i, s in enumerate(slice_tuple):
|
|
190
|
+
if s is Ellipsis:
|
|
191
|
+
head = slice_tuple[:i]
|
|
192
|
+
tail = slice_tuple[i + 1:]
|
|
193
|
+
break
|
|
194
|
+
slice_tuple = head + (slice(0, sys.maxsize, 1), ) * (
|
|
195
|
+
len(self.lu) - len(head) - len(tail)) + tail
|
|
196
|
+
slice_list = []
|
|
197
|
+
for s in slice_tuple:
|
|
198
|
+
if isinstance(s, int):
|
|
199
|
+
slice_list.append(s)
|
|
200
|
+
else:
|
|
201
|
+
start, stop, step = s.start, s.stop, s.step
|
|
202
|
+
if start is None:
|
|
203
|
+
start = 0
|
|
204
|
+
if step is None:
|
|
205
|
+
step = 1
|
|
206
|
+
if stop is None:
|
|
207
|
+
stop = sys.maxsize
|
|
208
|
+
slice_list.append(slice(start, stop, step))
|
|
209
|
+
return tuple(slice_list)
|
|
210
|
+
|
|
211
|
+
def __getitem__(self, slice_tuple: slice | EllipsisType
|
|
212
|
+
| tuple[slice | int | EllipsisType, ...]):
|
|
213
|
+
return super().__getitem__(self._full_slice(slice_tuple))
|
|
214
|
+
|
|
140
215
|
|
|
141
216
|
class Record():
|
|
142
217
|
|
|
@@ -149,7 +224,6 @@ class Record():
|
|
|
149
224
|
self._index = []
|
|
150
225
|
self._pos = []
|
|
151
226
|
self._last_vars = set()
|
|
152
|
-
self._levels = {}
|
|
153
227
|
self._file = None
|
|
154
228
|
self.independent_variables = {}
|
|
155
229
|
self.constants = {}
|
|
@@ -170,7 +244,6 @@ class Record():
|
|
|
170
244
|
for level, group in self.description['order'].items():
|
|
171
245
|
for names in group:
|
|
172
246
|
for name in names:
|
|
173
|
-
self._levels[name] = level
|
|
174
247
|
if name not in self.dims:
|
|
175
248
|
if name not in self.description['dependents']:
|
|
176
249
|
self.dims[name] = (level, )
|
|
@@ -185,6 +258,35 @@ class Record():
|
|
|
185
258
|
self._file = random_path(self.database / 'objects')
|
|
186
259
|
self._file.parent.mkdir(parents=True, exist_ok=True)
|
|
187
260
|
|
|
261
|
+
def __getstate__(self) -> dict:
|
|
262
|
+
return {
|
|
263
|
+
'id': self.id,
|
|
264
|
+
'database': self.database,
|
|
265
|
+
'description': self.description,
|
|
266
|
+
'_keys': self._keys,
|
|
267
|
+
'_items': self._items,
|
|
268
|
+
'_index': self._index,
|
|
269
|
+
'_pos': self._pos,
|
|
270
|
+
'_last_vars': self._last_vars,
|
|
271
|
+
'independent_variables': self.independent_variables,
|
|
272
|
+
'constants': self.constants,
|
|
273
|
+
'dims': self.dims,
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
def __setstate__(self, state: dict):
|
|
277
|
+
self.id = state['id']
|
|
278
|
+
self.database = state['database']
|
|
279
|
+
self.description = state['description']
|
|
280
|
+
self._keys = state['_keys']
|
|
281
|
+
self._items = state['_items']
|
|
282
|
+
self._index = state['_index']
|
|
283
|
+
self._pos = state['_pos']
|
|
284
|
+
self._last_vars = state['_last_vars']
|
|
285
|
+
self.independent_variables = state['independent_variables']
|
|
286
|
+
self.constants = state['constants']
|
|
287
|
+
self.dims = state['dims']
|
|
288
|
+
self._file = None
|
|
289
|
+
|
|
188
290
|
def is_local_record(self):
|
|
189
291
|
return not self.is_cache_record() and not self.is_remote_record()
|
|
190
292
|
|
|
@@ -201,7 +303,7 @@ class Record():
|
|
|
201
303
|
def __getitem__(self, key):
|
|
202
304
|
return self.get(key)
|
|
203
305
|
|
|
204
|
-
def get(self, key, default=_notgiven, buffer_to_array=True):
|
|
306
|
+
def get(self, key, default=_notgiven, buffer_to_array=True, slice=None):
|
|
205
307
|
if self.is_remote_record():
|
|
206
308
|
with ZMQContextManager(zmq.DEALER,
|
|
207
309
|
connect=self.database) as socket:
|
|
@@ -211,8 +313,21 @@ class Record():
|
|
|
211
313
|
'key': key
|
|
212
314
|
})
|
|
213
315
|
ret = socket.recv_pyobj()
|
|
214
|
-
if isinstance(ret, BufferList)
|
|
215
|
-
|
|
316
|
+
if isinstance(ret, BufferList):
|
|
317
|
+
socket.send_pyobj({
|
|
318
|
+
'method': 'bufferlist_slice',
|
|
319
|
+
'record_id': self.id,
|
|
320
|
+
'key': key,
|
|
321
|
+
'slice': slice
|
|
322
|
+
})
|
|
323
|
+
lst = socket.recv_pyobj()
|
|
324
|
+
ret._list = lst
|
|
325
|
+
ret._slice = slice
|
|
326
|
+
if buffer_to_array:
|
|
327
|
+
return ret.array()
|
|
328
|
+
else:
|
|
329
|
+
ret._database = self.database
|
|
330
|
+
return ret
|
|
216
331
|
else:
|
|
217
332
|
return ret
|
|
218
333
|
else:
|
|
@@ -221,15 +336,13 @@ class Record():
|
|
|
221
336
|
else:
|
|
222
337
|
d = self._items.get(key, default)
|
|
223
338
|
if isinstance(d, BufferList):
|
|
339
|
+
if isinstance(d.file, str):
|
|
340
|
+
d.file = self._file.parent.parent.parent.parent / d.file
|
|
341
|
+
d._slice = slice
|
|
224
342
|
if buffer_to_array:
|
|
225
343
|
return d.array()
|
|
226
344
|
else:
|
|
227
|
-
|
|
228
|
-
ret._pos = d.pos()
|
|
229
|
-
ret._value = d.value()
|
|
230
|
-
ret.lu = d.lu
|
|
231
|
-
ret.rd = d.rd
|
|
232
|
-
return ret
|
|
345
|
+
return d
|
|
233
346
|
else:
|
|
234
347
|
return d
|
|
235
348
|
|
|
@@ -251,8 +364,7 @@ class Record():
|
|
|
251
364
|
return
|
|
252
365
|
|
|
253
366
|
for key in set(variables.keys()) - self._last_vars:
|
|
254
|
-
if key not in self.
|
|
255
|
-
self._levels[key] = level
|
|
367
|
+
if key not in self.dims:
|
|
256
368
|
self.dims[key] = tuple(range(level + 1))
|
|
257
369
|
|
|
258
370
|
self._last_vars = set(variables.keys())
|
|
@@ -276,14 +388,17 @@ class Record():
|
|
|
276
388
|
self._pos[-1] += 1
|
|
277
389
|
|
|
278
390
|
for key, value in variables.items():
|
|
279
|
-
if
|
|
391
|
+
if self.dims[key] == ():
|
|
392
|
+
if key not in self._items:
|
|
393
|
+
self._items[key] = value
|
|
394
|
+
elif level == self.dims[key][-1]:
|
|
280
395
|
if key not in self._items:
|
|
281
396
|
if self.is_local_record():
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
self._items[key] = BufferList(
|
|
397
|
+
bufferlist_file = random_path(self.database /
|
|
398
|
+
'objects')
|
|
399
|
+
bufferlist_file.parent.mkdir(parents=True,
|
|
400
|
+
exist_ok=True)
|
|
401
|
+
self._items[key] = BufferList(bufferlist_file)
|
|
287
402
|
else:
|
|
288
403
|
self._items[key] = BufferList()
|
|
289
404
|
self._items[key].lu = pos
|
|
@@ -291,8 +406,6 @@ class Record():
|
|
|
291
406
|
self._items[key].append(pos, value, self.dims[key])
|
|
292
407
|
elif isinstance(self._items[key], BufferList):
|
|
293
408
|
self._items[key].append(pos, value, self.dims[key])
|
|
294
|
-
elif self._levels[key] == -1 and key not in self._items:
|
|
295
|
-
self._items[key] = value
|
|
296
409
|
|
|
297
410
|
def flush(self):
|
|
298
411
|
if self.is_remote_record() or self.is_cache_record():
|
|
@@ -307,7 +420,7 @@ class Record():
|
|
|
307
420
|
|
|
308
421
|
def __repr__(self):
|
|
309
422
|
return f"<Record: id={self.id} app={self.description['app']}, keys={self.keys()}>"
|
|
310
|
-
|
|
423
|
+
|
|
311
424
|
# def _repr_html_(self):
|
|
312
425
|
# return f"""
|
|
313
426
|
# <h3>Record: id={self.id}, app={self.description['app']}</h3>
|
|
@@ -351,6 +464,7 @@ def get_record(session: Session, id: int, datapath: Path) -> Record:
|
|
|
351
464
|
path = datapath / 'objects' / record_in_db.file
|
|
352
465
|
with open(path, 'rb') as f:
|
|
353
466
|
record = dill.load(f)
|
|
467
|
+
record._file = path
|
|
354
468
|
else:
|
|
355
469
|
record = record_cache[id][1]
|
|
356
470
|
clear_cache()
|
|
@@ -400,6 +514,12 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
400
514
|
match request.method:
|
|
401
515
|
case 'ping':
|
|
402
516
|
await reply(request, 'pong')
|
|
517
|
+
case 'bufferlist_slice':
|
|
518
|
+
record = get_record(session, msg['record_id'], datapath)
|
|
519
|
+
bufferlist = record.get(msg['key'],
|
|
520
|
+
buffer_to_array=False,
|
|
521
|
+
slice=msg['slice'])
|
|
522
|
+
await reply(request, list(bufferlist.iter()))
|
|
403
523
|
case 'record_create':
|
|
404
524
|
description = dill.loads(msg['description'])
|
|
405
525
|
await reply(request, record_create(session, description, datapath))
|
qulab/scan/scan.py
CHANGED
|
@@ -561,10 +561,13 @@ class Scan():
|
|
|
561
561
|
Returns:
|
|
562
562
|
Promise: A promise object.
|
|
563
563
|
"""
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
564
|
+
if inspect.isawaitable(awaitable):
|
|
565
|
+
async with self._sem:
|
|
566
|
+
task = asyncio.create_task(self._await(awaitable))
|
|
567
|
+
self._task_queue.put_nowait(task)
|
|
568
|
+
return Promise(task)
|
|
569
|
+
else:
|
|
570
|
+
return awaitable
|
|
568
571
|
|
|
569
572
|
async def _await(self, awaitable: Awaitable):
|
|
570
573
|
async with self._sem:
|
qulab/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "2.0.
|
|
1
|
+
__version__ = "2.0.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|