QuLab 2.0.4__cp311-cp311-macosx_10_9_universal2.whl → 2.0.6__cp311-cp311-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.4.dist-info → QuLab-2.0.6.dist-info}/METADATA +1 -1
- {QuLab-2.0.4.dist-info → QuLab-2.0.6.dist-info}/RECORD +10 -10
- qulab/fun.cpython-311-darwin.so +0 -0
- qulab/scan/recorder.py +197 -67
- qulab/scan/scan.py +16 -6
- qulab/version.py +1 -1
- {QuLab-2.0.4.dist-info → QuLab-2.0.6.dist-info}/LICENSE +0 -0
- {QuLab-2.0.4.dist-info → QuLab-2.0.6.dist-info}/WHEEL +0 -0
- {QuLab-2.0.4.dist-info → QuLab-2.0.6.dist-info}/entry_points.txt +0 -0
- {QuLab-2.0.4.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-311-darwin.so,sha256=
|
|
4
|
-
qulab/version.py,sha256=
|
|
3
|
+
qulab/fun.cpython-311-darwin.so,sha256=5n2eKR4XMC2UAch4iGZs8bvMxen1dAwPdaanMSzZYC4,159616
|
|
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=eupBwbXGAhwNAPJSvj5BiShZwdZO8jnQ5yHfv-9aUGw,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-311-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():
|
|
@@ -305,6 +418,16 @@ class Record():
|
|
|
305
418
|
with open(self._file, 'wb') as f:
|
|
306
419
|
dill.dump(self, f)
|
|
307
420
|
|
|
421
|
+
def __repr__(self):
|
|
422
|
+
return f"<Record: id={self.id} app={self.description['app']}, keys={self.keys()}>"
|
|
423
|
+
|
|
424
|
+
# def _repr_html_(self):
|
|
425
|
+
# return f"""
|
|
426
|
+
# <h3>Record: id={self.id}, app={self.description['app']}</h3>
|
|
427
|
+
# <p>keys={self.keys()}</p>
|
|
428
|
+
# <p>dims={self.dims}</p>
|
|
429
|
+
# """
|
|
430
|
+
|
|
308
431
|
|
|
309
432
|
class Request():
|
|
310
433
|
__slots__ = ['sock', 'identity', 'msg', 'method']
|
|
@@ -341,6 +464,7 @@ def get_record(session: Session, id: int, datapath: Path) -> Record:
|
|
|
341
464
|
path = datapath / 'objects' / record_in_db.file
|
|
342
465
|
with open(path, 'rb') as f:
|
|
343
466
|
record = dill.load(f)
|
|
467
|
+
record._file = path
|
|
344
468
|
else:
|
|
345
469
|
record = record_cache[id][1]
|
|
346
470
|
clear_cache()
|
|
@@ -390,6 +514,12 @@ async def handle(session: Session, request: Request, datapath: Path):
|
|
|
390
514
|
match request.method:
|
|
391
515
|
case 'ping':
|
|
392
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()))
|
|
393
523
|
case 'record_create':
|
|
394
524
|
description = dill.loads(msg['description'])
|
|
395
525
|
await reply(request, record_create(session, description, datapath))
|
qulab/scan/scan.py
CHANGED
|
@@ -174,6 +174,7 @@ class Scan():
|
|
|
174
174
|
tags: tuple[str] = (),
|
|
175
175
|
database: str | Path
|
|
176
176
|
| None = f'tcp://127.0.0.1:{default_record_port}',
|
|
177
|
+
dump_globals: bool = False,
|
|
177
178
|
mixin=None):
|
|
178
179
|
self.id = task_uuid()
|
|
179
180
|
self.record = None
|
|
@@ -185,7 +186,7 @@ class Scan():
|
|
|
185
186
|
'consts': {},
|
|
186
187
|
'functions': {},
|
|
187
188
|
'optimizers': {},
|
|
188
|
-
'namespace': {},
|
|
189
|
+
'namespace': {} if dump_globals else None,
|
|
189
190
|
'actions': {},
|
|
190
191
|
'dependents': {},
|
|
191
192
|
'order': {},
|
|
@@ -208,6 +209,7 @@ class Scan():
|
|
|
208
209
|
self._hide_pattern_re = re.compile('|'.join(self.description['hiden']))
|
|
209
210
|
self._task_queue = asyncio.Queue()
|
|
210
211
|
self._task_pool = []
|
|
212
|
+
self._single_step = True
|
|
211
213
|
|
|
212
214
|
def __del__(self):
|
|
213
215
|
try:
|
|
@@ -448,6 +450,9 @@ class Scan():
|
|
|
448
450
|
elif inspect.isawaitable(evt):
|
|
449
451
|
await evt
|
|
450
452
|
task.cancel()
|
|
453
|
+
if self._single_step:
|
|
454
|
+
await self.emit(0, 0, 0, self.variables.copy())
|
|
455
|
+
await self.emit(-1, 0, 0, {})
|
|
451
456
|
return self.variables
|
|
452
457
|
|
|
453
458
|
async def done(self):
|
|
@@ -504,6 +509,7 @@ class Scan():
|
|
|
504
509
|
self._current_level += 1
|
|
505
510
|
if await self._filter(variables, self.current_level - 1):
|
|
506
511
|
yield variables
|
|
512
|
+
self._single_step = False
|
|
507
513
|
asyncio.create_task(
|
|
508
514
|
self.emit(self.current_level - 1, step, position,
|
|
509
515
|
variables.copy()))
|
|
@@ -555,10 +561,13 @@ class Scan():
|
|
|
555
561
|
Returns:
|
|
556
562
|
Promise: A promise object.
|
|
557
563
|
"""
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
|
562
571
|
|
|
563
572
|
async def _await(self, awaitable: Awaitable):
|
|
564
573
|
async with self._sem:
|
|
@@ -614,7 +623,8 @@ def assymbly(description):
|
|
|
614
623
|
import __main__
|
|
615
624
|
from IPython import get_ipython
|
|
616
625
|
|
|
617
|
-
description['namespace']
|
|
626
|
+
if isinstance(description['namespace'], dict):
|
|
627
|
+
description['namespace'] = dump_globals()
|
|
618
628
|
|
|
619
629
|
ipy = get_ipython()
|
|
620
630
|
if ipy is not None:
|
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
|