QuLab 2.1.0__cp311-cp311-win_amd64.whl → 2.1.1__cp311-cp311-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.1.0
3
+ Version: 2.1.1
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=8zLGg-DfQhnDl2Ky0n-zXpN-8e-g7iR0AcaI4l4Vvpk,32
2
2
  qulab/__main__.py,sha256=XN2wrhlmEkTIPq_ZeSaO8rWXfYgD2Czkm9DVFVoCw_U,515
3
- qulab/fun.cp311-win_amd64.pyd,sha256=U8P2nkeDFljBCP5CuqmzcFRZWyOspJ_rrIkfa6FTwUk,31232
4
- qulab/version.py,sha256=5VFOC9N5P61WNNAC14BfsqZmQ2X-yL6b-UnG_oixpYM,21
3
+ qulab/fun.cp311-win_amd64.pyd,sha256=UDt4HGuuUwWs5ppErwUbge8zg6CnVY4_z-AoonzjuFg,31232
4
+ qulab/version.py,sha256=k4SipKIh6P-kJf4P7Os3KD55dGIg3hoiS5pK316IoMg,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
@@ -12,16 +12,18 @@ qulab/monitor/monitor.py,sha256=2AP-hhg1T6-38mieDm5_ONTIXnXYlIrSyOiAOxDKy0I,2398
12
12
  qulab/monitor/ploter.py,sha256=dg7W28XTwEbBxHVtdPkFV135OQgoQwTi-NJCZQF-HYU,3724
13
13
  qulab/monitor/qt_compat.py,sha256=Eq7zlA4_XstB92NhtAqebtWU_Btw4lcwFO30YxZ-TPE,804
14
14
  qulab/monitor/toolbar.py,sha256=HxqG6ywKFyQJM2Q1s7SnhuzjbyeROczAZKwxztD1WJ8,8213
15
- qulab/scan/__init__.py,sha256=O_m7HAjbavGUxl7MayY-PCGCXfzoASmeE-FX5zEIjCs,127
15
+ qulab/scan/__init__.py,sha256=QQtFFMWX9XUcZrq2KGiNgyckoQRGS4p8MhsMWNjidBE,120
16
16
  qulab/scan/curd.py,sha256=bEXtcmiaoAv5APToXx5O5tvmqAhE2_LkvdwLsI_8D5M,4662
17
17
  qulab/scan/expression.py,sha256=vwUM9E0OFQal4bljlUtLR3NJu4zGRyuWYrdyZSs3QTU,16199
18
18
  qulab/scan/models.py,sha256=TkiVHF_fUZzYHs4MsCTRh391thpf4Ozd3R_LAU0Gxkg,17657
19
19
  qulab/scan/optimize.py,sha256=MlT4y422CnP961IR384UKryyZh8riNvrPSd2z_MXLEg,2356
20
- qulab/scan/query_record.py,sha256=rpw4U3NjLzlv9QMwKdCvEUGHjzPF8u1UpodfLW8aoTY,11853
21
- qulab/scan/recorder.py,sha256=cTKYP6vQzOXl9E5bj50qkxJPOh1virpJRW21pi53SaY,26426
22
- qulab/scan/scan.py,sha256=2Ekfj3c7O91FR4eFSAb0G0wm8g9_f3xXfH7tIVnqrDc,30657
23
- qulab/scan/server.py,sha256=zDZfG6bOB3EUubfByQMq0BSQ9C6IV_Av0tDinzgpGjQ,2950
24
- qulab/scan/utils.py,sha256=XM-eKL5Xkm0hihhGS7Kq4g654Ye7n7TcU_f95gxtXq8,2634
20
+ qulab/scan/query.py,sha256=ieXz8_YGUuZfQTruJdtKLZT7ZIiYzcJNvnRseitbQDA,11943
21
+ qulab/scan/record.py,sha256=jJ_K3QrdEqtHRpG5EtkMRIKcFRNREgMxtoi7a9nMeeI,15535
22
+ qulab/scan/recorder.py,sha256=3CrFEs-tyiR3aSxhqFDIdhibHTLzVyxsDXRpovQ8dyI,8804
23
+ qulab/scan/scan.py,sha256=bFb20OXam6xj71tvZOws8VZ-iDRqLDHXTrZ8oGA2uDY,30022
24
+ qulab/scan/server.py,sha256=Q7lX9ms37WbnzuLhrv3YbNrusTsxQUNT9slFqon5VL0,2872
25
+ qulab/scan/space.py,sha256=OPceWIIrb2KDDQaSxD3Vkzkf9NDSuqWuQoDnKiWqtAo,5381
26
+ qulab/scan/utils.py,sha256=30qnYvyFyctwcWxOCUpCNxXgGysA7xdIDzYbjwxGUzA,3744
25
27
  qulab/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
28
  qulab/storage/__main__.py,sha256=6-EjN0waX1yfcMPJXqpIr9UlrIEsSCFApm5G-ZeaPMQ,1742
27
29
  qulab/storage/base_dataset.py,sha256=28y3-OZrqJ52p5sbirEpUgjb7hqwLLpd38KU9DCkD24,12217
@@ -77,9 +79,9 @@ qulab/visualization/plot_layout.py,sha256=yAnMONOms7_szCdng-8wPpUMPis5UnbaNNzV4K
77
79
  qulab/visualization/plot_seq.py,sha256=h9D0Yl_yO64IwlvBgzMu9EBKr9gg6y8QE55gu2PfTns,2783
78
80
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
79
81
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
80
- QuLab-2.1.0.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
81
- QuLab-2.1.0.dist-info/METADATA,sha256=w7Kk5WbBivHCA5jWGexSPxsiwY_PBVr85_-wrXz3BW0,3609
82
- QuLab-2.1.0.dist-info/WHEEL,sha256=nSybvzWlmdJnHiUQSY-d7V1ycwEVUTqXiTvr2eshg44,102
83
- QuLab-2.1.0.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
84
- QuLab-2.1.0.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
85
- QuLab-2.1.0.dist-info/RECORD,,
82
+ QuLab-2.1.1.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
83
+ QuLab-2.1.1.dist-info/METADATA,sha256=nxgn3sJ3bOPGYgZ_3nNqUswtTIJcEzdsaJEGMX0fvi4,3609
84
+ QuLab-2.1.1.dist-info/WHEEL,sha256=nSybvzWlmdJnHiUQSY-d7V1ycwEVUTqXiTvr2eshg44,102
85
+ QuLab-2.1.1.dist-info/entry_points.txt,sha256=ohBzutEnQimP_BZWiuXdSliu4QAYSHHcN0PZD8c7ZCY,46
86
+ QuLab-2.1.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
87
+ QuLab-2.1.1.dist-info/RECORD,,
Binary file
qulab/scan/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from .expression import Expression, Symbol
2
- from .query_record import get_record, lookup, lookup_list
2
+ from .query import get_record, lookup, lookup_list
3
3
  from .scan import Scan
@@ -9,10 +9,11 @@ from IPython.display import display
9
9
 
10
10
  from qulab.sys.rpc.zmq_socket import ZMQContextManager
11
11
 
12
- from .recorder import Record
12
+ from .record import Record
13
+ from .scan import default_server
13
14
 
14
15
 
15
- def get_record(id, database='tcp://127.0.0.1:6789'):
16
+ def get_record(id, database=default_server) -> Record:
16
17
  if isinstance(database, str) and database.startswith('tcp://'):
17
18
  with ZMQContextManager(zmq.DEALER, connect=database) as socket:
18
19
  socket.send_pyobj({
@@ -20,7 +21,10 @@ def get_record(id, database='tcp://127.0.0.1:6789'):
20
21
  'record_id': id
21
22
  })
22
23
  d = dill.loads(socket.recv_pyobj())
23
- return Record(id, database, d)
24
+ d.id = id
25
+ d.database = database
26
+ d._file = None
27
+ return d
24
28
  else:
25
29
  from .models import Record as RecordInDB
26
30
  from .models import create_engine, sessionmaker
@@ -292,7 +296,7 @@ def _on_tags_submit(tags, ui_widgets):
292
296
  _update_view(ui_widgets)
293
297
 
294
298
 
295
- def lookup(app=None, limit=10, database='tcp://127.0.0.1:6789'):
299
+ def lookup(app=None, limit=10, database=default_server):
296
300
  after = widgets.DatePicker()
297
301
  before = widgets.DatePicker()
298
302
  app_prefix = widgets.Label('App:')
qulab/scan/record.py ADDED
@@ -0,0 +1,448 @@
1
+ import itertools
2
+ import sys
3
+ import uuid
4
+ from pathlib import Path
5
+ from threading import Lock
6
+ from types import EllipsisType
7
+
8
+ import dill
9
+ import numpy as np
10
+ import zmq
11
+
12
+ from qulab.sys.rpc.zmq_socket import ZMQContextManager
13
+
14
+ from .space import OptimizeSpace, Space
15
+
16
+ _notgiven = object()
17
+
18
+
19
+ def random_path(base):
20
+ while True:
21
+ s = uuid.uuid4().hex
22
+ path = base / s[:2] / s[2:4] / s[4:6] / s[6:]
23
+ if not path.exists():
24
+ return path
25
+
26
+
27
+ def index_in_slice(slice_obj: slice | int, index: int):
28
+ if isinstance(slice_obj, int):
29
+ return slice_obj == index
30
+ start, stop, step = slice_obj.start, slice_obj.stop, slice_obj.step
31
+ if start is None:
32
+ start = 0
33
+ if step is None:
34
+ step = 1
35
+ if stop is None:
36
+ stop = sys.maxsize
37
+
38
+ if step > 0:
39
+ return start <= index < stop and (index - start) % step == 0
40
+ else:
41
+ return stop < index <= start and (index - start) % step == 0
42
+
43
+
44
+ class BufferList():
45
+
46
+ def __init__(self, file=None, slice=None):
47
+ self._list = []
48
+ self.lu = ()
49
+ self.rd = ()
50
+ self.inner_shape = ()
51
+ self.file = file
52
+ self._slice = slice
53
+ self._lock = Lock()
54
+ self._data_id = None
55
+
56
+ def __repr__(self):
57
+ return f"<BufferList: shape={self.shape}, lu={self.lu}, rd={self.rd}, slice={self._slice}>"
58
+
59
+ def __getstate__(self):
60
+ self.flush()
61
+ if isinstance(self.file, Path):
62
+ file = '/'.join(self.file.parts[-4:])
63
+ else:
64
+ file = self.file
65
+ return {
66
+ 'file': file,
67
+ 'lu': self.lu,
68
+ 'rd': self.rd,
69
+ 'inner_shape': self.inner_shape,
70
+ }
71
+
72
+ def __setstate__(self, state):
73
+ self.file = state['file']
74
+ self.lu = state['lu']
75
+ self.rd = state['rd']
76
+ self.inner_shape = state['inner_shape']
77
+ self._list = []
78
+ self._slice = None
79
+ self._lock = Lock()
80
+ self._data_id = None
81
+
82
+ @property
83
+ def shape(self):
84
+ return tuple([i - j
85
+ for i, j in zip(self.rd, self.lu)]) + self.inner_shape
86
+
87
+ def flush(self):
88
+ if not self._list:
89
+ return
90
+ if isinstance(self.file, Path):
91
+ with self._lock:
92
+ with open(self.file, 'ab') as f:
93
+ for item in self._list:
94
+ dill.dump(item, f)
95
+ self._list.clear()
96
+
97
+ def append(self, pos, value, dims=None):
98
+ if dims is not None:
99
+ if any([p != 0 for i, p in enumerate(pos) if i not in dims]):
100
+ return
101
+ pos = tuple([pos[i] for i in dims])
102
+ self.lu = tuple([min(i, j) for i, j in zip(pos, self.lu)])
103
+ self.rd = tuple([max(i + 1, j) for i, j in zip(pos, self.rd)])
104
+ if hasattr(value, 'shape'):
105
+ if self.inner_shape is None:
106
+ self.inner_shape = value.shape
107
+ elif self.inner_shape != value.shape:
108
+ self.inner_shape = ()
109
+ self._list.append((pos, value))
110
+ if len(self._list) > 1000:
111
+ self.flush()
112
+
113
+ def _iter_file(self):
114
+ if isinstance(self.file, Path) and self.file.exists():
115
+ with self._lock:
116
+ with open(self.file, 'rb') as f:
117
+ while True:
118
+ try:
119
+ pos, value = dill.load(f)
120
+ yield pos, value
121
+ except EOFError:
122
+ break
123
+
124
+ def iter(self):
125
+ if self._data_id is None:
126
+ for pos, value in itertools.chain(self._iter_file(), self._list):
127
+ if not self._slice:
128
+ yield pos, value
129
+ elif all(
130
+ [index_in_slice(s, i) for s, i in zip(self._slice, pos)]):
131
+ if self.inner_shape:
132
+ yield pos, value[self._slice[len(pos):]]
133
+ else:
134
+ yield pos, value
135
+ else:
136
+ server, record_id, key = self._data_id
137
+ with ZMQContextManager(zmq.DEALER, connect=server) as socket:
138
+ socket.send_pyobj({
139
+ 'method': 'bufferlist_slice',
140
+ 'record_id': record_id,
141
+ 'key': key,
142
+ 'slice': self._slice
143
+ })
144
+ ret = socket.recv_pyobj()
145
+ yield from ret
146
+
147
+ def value(self):
148
+ d = []
149
+ for pos, value in self.iter():
150
+ d.append(value)
151
+ return d
152
+
153
+ def pos(self):
154
+ p = []
155
+ for pos, value in self.iter():
156
+ p.append(pos)
157
+ return p
158
+
159
+ def items(self):
160
+ p, d = [], []
161
+ for pos, value in self.iter():
162
+ p.append(pos)
163
+ d.append(value)
164
+ return p, d
165
+
166
+ def array(self):
167
+ pos, data = self.items()
168
+ if self._slice:
169
+ pos = np.asarray(pos)
170
+ lu = tuple(np.min(pos, axis=0))
171
+ rd = tuple(np.max(pos, axis=0) + 1)
172
+ pos = np.asarray(pos) - np.asarray(lu)
173
+ shape = []
174
+ for k, (s, i, j) in enumerate(zip(self._slice, rd, lu)):
175
+ if s.step is not None:
176
+ pos[:, k] = pos[:, k] / s.step
177
+ shape.append(round(np.ceil((i - j) / s.step)))
178
+ else:
179
+ shape.append(i - j)
180
+ shape = tuple(shape)
181
+ else:
182
+ shape = tuple([i - j for i, j in zip(self.rd, self.lu)])
183
+ pos = np.asarray(pos) - np.asarray(self.lu)
184
+ data = np.asarray(data)
185
+ inner_shape = data.shape[1:]
186
+ x = np.full(shape + inner_shape, np.nan, dtype=data[0].dtype)
187
+ x.__setitem__(tuple(pos.T), data)
188
+ return x
189
+
190
+ def _full_slice(self, slice_tuple: slice
191
+ | tuple[slice | int | EllipsisType, ...]):
192
+ ndim = len(self.lu)
193
+ if self.inner_shape:
194
+ ndim += len(self.inner_shape)
195
+
196
+ if isinstance(slice_tuple, slice):
197
+ slice_tuple = (
198
+ slice_tuple, ) + (slice(0, sys.maxsize, 1), ) * (ndim - 1)
199
+ if slice_tuple is Ellipsis:
200
+ slice_tuple = (slice(0, sys.maxsize, 1), ) * ndim
201
+ else:
202
+ head, tail = (), ()
203
+ for i, s in enumerate(slice_tuple):
204
+ if s is Ellipsis:
205
+ head = slice_tuple[:i]
206
+ tail = slice_tuple[i + 1:]
207
+ break
208
+ else:
209
+ head = slice_tuple
210
+ tail = ()
211
+ slice_tuple = head + (slice(
212
+ 0, sys.maxsize, 1), ) * (ndim - len(head) - len(tail)) + tail
213
+ slice_list = []
214
+ contract = []
215
+ reversed = []
216
+ for i, s in enumerate(slice_tuple):
217
+ if isinstance(s, int):
218
+ if s >= 0:
219
+ slice_list.append(slice(s, s + 1, 1))
220
+ elif i < len(self.lu):
221
+ s = self.rd[i] + s
222
+ slice_list.append(slice(s, s + 1, 1))
223
+ else:
224
+ slice_list.append(slice(s, s - 1, -1))
225
+ contract.append(i)
226
+ else:
227
+ start, stop, step = s.start, s.stop, s.step
228
+ if step is None:
229
+ step = 1
230
+ if step < 0 and i < len(self.lu):
231
+ step = -step
232
+ reversed.append(i)
233
+ if start is None and stop is None:
234
+ start, stop = 0, sys.maxsize
235
+ elif start is None:
236
+ start, stop = self.lu[i], sys.maxsize
237
+ elif stop is None:
238
+ start, stop = 0, start + self.lu[i]
239
+ else:
240
+ start, stop = stop + self.lu[i] + 1, start + self.lu[
241
+ i] + 1
242
+
243
+ if start is None:
244
+ start = 0
245
+ elif start < 0 and i < len(self.lu):
246
+ start = self.rd[i] + start
247
+ if step is None:
248
+ step = 1
249
+ if stop is None:
250
+ stop = sys.maxsize
251
+ elif stop < 0 and i < len(self.lu):
252
+ stop = self.rd[i] + stop
253
+
254
+ slice_list.append(slice(start, stop, step))
255
+ return tuple(slice_list), contract, reversed
256
+
257
+ def __getitem__(self, slice_tuple: slice | EllipsisType
258
+ | tuple[slice | int | EllipsisType, ...]):
259
+ self._slice, contract, reversed = self._full_slice(slice_tuple)
260
+ ret = self.array()
261
+ slices = []
262
+ for i, s in enumerate(self._slice):
263
+ if i in contract:
264
+ slices.append(0)
265
+ elif isinstance(s, slice):
266
+ if i in reversed:
267
+ slices.append(slice(None, None, -1))
268
+ else:
269
+ slices.append(slice(None, None, 1))
270
+ ret = ret.__getitem__(tuple(slices))
271
+ self._slice = None
272
+ return ret
273
+
274
+
275
+ class Record():
276
+
277
+ def __init__(self, id, database, description=None):
278
+ self.id = id
279
+ self.database = database
280
+ self.description = description
281
+ self._items = {}
282
+ self._pos = []
283
+ self._last_vars = set()
284
+ self._file = None
285
+
286
+ if self.is_local_record():
287
+ self.database = Path(self.database)
288
+ self._file = random_path(self.database / 'objects')
289
+ self._file.parent.mkdir(parents=True, exist_ok=True)
290
+
291
+ def __getstate__(self) -> dict:
292
+ return {
293
+ 'id': self.id,
294
+ 'description': self.description,
295
+ '_items': self._items,
296
+ }
297
+
298
+ def __setstate__(self, state: dict):
299
+ self.id = state['id']
300
+ self.description = state['description']
301
+ self._items = state['_items']
302
+ self._pos = []
303
+ self._last_vars = set()
304
+ self.database = None
305
+ self._file = None
306
+
307
+ @property
308
+ def axis(self):
309
+ return self.description.get('axis', {})
310
+
311
+ def is_local_record(self):
312
+ return not self.is_cache_record() and not self.is_remote_record()
313
+
314
+ def is_cache_record(self):
315
+ return self.database is None
316
+
317
+ def is_remote_record(self):
318
+ return isinstance(self.database,
319
+ str) and self.database.startswith("tcp://")
320
+
321
+ def __del__(self):
322
+ self.flush()
323
+
324
+ def __getitem__(self, key):
325
+ ret = self.get(key, buffer_to_array=True)
326
+ if isinstance(ret, Space):
327
+ ret = ret.toarray()
328
+ return ret
329
+
330
+ def get(self, key, default=_notgiven, buffer_to_array=False, slice=None):
331
+ if self.is_remote_record():
332
+ with ZMQContextManager(zmq.DEALER,
333
+ connect=self.database) as socket:
334
+ socket.send_pyobj({
335
+ 'method': 'record_getitem',
336
+ 'record_id': self.id,
337
+ 'key': key
338
+ })
339
+ ret = socket.recv_pyobj()
340
+ if isinstance(ret, BufferList):
341
+ if buffer_to_array:
342
+ socket.send_pyobj({
343
+ 'method': 'bufferlist_slice',
344
+ 'record_id': self.id,
345
+ 'key': key,
346
+ 'slice': slice
347
+ })
348
+ lst = socket.recv_pyobj()
349
+ ret._list = lst
350
+ ret._slice = slice
351
+ return ret.array()
352
+ else:
353
+ ret._data_id = self.database, self.id, key
354
+ return ret
355
+ else:
356
+ return ret
357
+ else:
358
+ if default is _notgiven:
359
+ d = self._items.get(key)
360
+ else:
361
+ d = self._items.get(key, default)
362
+ if isinstance(d, BufferList):
363
+ if isinstance(d.file, str):
364
+ d.file = self._file.parent.parent.parent.parent / d.file
365
+ d._slice = slice
366
+ if buffer_to_array:
367
+ return d.array()
368
+ else:
369
+ return d
370
+ else:
371
+ return d
372
+
373
+ def keys(self):
374
+ if self.is_remote_record():
375
+ with ZMQContextManager(zmq.DEALER,
376
+ connect=self.database) as socket:
377
+ socket.send_pyobj({
378
+ 'method': 'record_keys',
379
+ 'record_id': self.id
380
+ })
381
+ return socket.recv_pyobj()
382
+ else:
383
+ return list(self._items.keys())
384
+
385
+ def append(self, level, step, position, variables):
386
+ if level < 0:
387
+ self.flush()
388
+ return
389
+
390
+ for key in set(variables.keys()) - self._last_vars:
391
+ if key not in self.axis:
392
+ self.axis[key] = tuple(range(level + 1))
393
+
394
+ self._last_vars = set(variables.keys())
395
+
396
+ if level >= len(self._pos):
397
+ l = level + 1 - len(self._pos)
398
+ self._pos.extend(([0] * (l - 1)) + [position])
399
+ pos = tuple(self._pos)
400
+ elif level == len(self._pos) - 1:
401
+ self._pos[-1] = position
402
+ pos = tuple(self._pos)
403
+ else:
404
+ self._pos = self._pos[:level + 1]
405
+ self._pos[-1] = position
406
+ pos = tuple(self._pos)
407
+ self._pos[-1] += 1
408
+
409
+ for key, value in variables.items():
410
+ if self.axis[key] == ():
411
+ if key not in self._items:
412
+ self._items[key] = value
413
+ elif level == self.axis[key][-1]:
414
+ if key not in self._items:
415
+ if self.is_local_record():
416
+ bufferlist_file = random_path(self.database /
417
+ 'objects')
418
+ bufferlist_file.parent.mkdir(parents=True,
419
+ exist_ok=True)
420
+ self._items[key] = BufferList(bufferlist_file)
421
+ else:
422
+ self._items[key] = BufferList()
423
+ self._items[key].lu = pos
424
+ self._items[key].rd = tuple([i + 1 for i in pos])
425
+ self._items[key].append(pos, value, self.axis[key])
426
+ elif isinstance(self._items[key], BufferList):
427
+ self._items[key].append(pos, value, self.axis[key])
428
+
429
+ def flush(self):
430
+ if self.is_remote_record() or self.is_cache_record():
431
+ return
432
+
433
+ for key, value in self._items.items():
434
+ if isinstance(value, BufferList):
435
+ value.flush()
436
+
437
+ with open(self._file, 'wb') as f:
438
+ dill.dump(self, f)
439
+
440
+ def __repr__(self):
441
+ return f"<Record: id={self.id} app={self.description['app']}, keys={self.keys()}>"
442
+
443
+ # def _repr_html_(self):
444
+ # return f"""
445
+ # <h3>Record: id={self.id}, app={self.description['app']}</h3>
446
+ # <p>keys={self.keys()}</p>
447
+ # <p>axis={self.axis}</p>
448
+ # """