QuLab 2.7.7__cp310-cp310-win_amd64.whl → 2.7.10__cp310-cp310-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.2
2
2
  Name: QuLab
3
- Version: 2.7.7
3
+ Version: 2.7.10
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,19 +1,19 @@
1
1
  qulab/__init__.py,sha256=RZme5maBSMZpP6ckXymqZpo2sRYttwEpTYCIzIvys1c,292
2
2
  qulab/__main__.py,sha256=FL4YsGZL1jEtmcPc5WbleArzhOHLMsWl7OH3O-1d1ss,72
3
3
  qulab/dicttree.py,sha256=ZoSJVWK4VMqfzj42gPb_n5RqLlM6K1Me0WmLIfLEYf8,14195
4
- qulab/fun.cp310-win_amd64.pyd,sha256=vauOCBvFFrTfjSoJBrubXMCNetihsicaB3Ff1I57_1E,31232
4
+ qulab/fun.cp310-win_amd64.pyd,sha256=y0aR1tHQkJeC9hmGmZpfrLsZQ2V_xhoGnFZ_V9MOSWU,31232
5
5
  qulab/typing.py,sha256=PRtwbCHWY2ROKK8GHq4Bo8llXrIGo6xC73DrQf7S9os,71
6
6
  qulab/utils.py,sha256=UyZNPIyvis5t2MJBkXXLO5EmYP3mQZbt87zmYAHgoyk,1291
7
- qulab/version.py,sha256=TXxZaBvn1Y_BQ2YYBZ0iedwKmA3iOfYiZehFXuAoky0,21
7
+ qulab/version.py,sha256=jdPSCkDOwzHQzdidl89buWuyX5dorFZluLWAvXtMdIU,22
8
8
  qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  qulab/cli/commands.py,sha256=6xd2eYw32k1NmfAuYSu__1kaP12Oz1QVqwbkYXdWno4,588
10
10
  qulab/cli/config.py,sha256=tNmH4ggdgrFqcQa2WZKLpidiYTg95_UnT0paDJ4fi4c,3204
11
11
  qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
12
12
  qulab/executor/cli.py,sha256=gGka2M6xccfM8facsIJ2qZ1y2Yx8C4BRhc1JG6nK9mo,8932
13
13
  qulab/executor/load.py,sha256=4FY_SwumLDUewC265v4j_ZGGpfYOgH4c8PtglYcWpBw,18077
14
- qulab/executor/schedule.py,sha256=DHQ5dI5YX8_frWplOoLEb9htcfM5-mikiSBNSPWT1io,16725
15
- qulab/executor/storage.py,sha256=sBD-aNvj29l5HtoTpk_627qarZkPn33F-hcc80AuF6k,11079
16
- qulab/executor/transform.py,sha256=s0kxWQx8Sr9pMIQke1BLNM6KqrSogAkjB6Zkapl8YSU,2189
14
+ qulab/executor/schedule.py,sha256=S8zRdkM2_I9-EqMUCEGI9boe3sfc68Gn5NRK057ShAw,17997
15
+ qulab/executor/storage.py,sha256=gI6g28BmKKEZ_Pl-hFwvpiOj3mF8Su-yjj3hfMXs1VY,11630
16
+ qulab/executor/transform.py,sha256=4DyGXv1Iw36cCPqbqXlsn0Lw6gFjQpp_6Hcta50YQxU,2181
17
17
  qulab/executor/utils.py,sha256=cF6-2jlvlHyTjNHdxXKG04Fjfm3_3wfDQAF1G8DQphk,5686
18
18
  qulab/monitor/__init__.py,sha256=xEVDkJF8issrsDeLqQmDsvtRmrf-UiViFcGTWuzdlFU,43
19
19
  qulab/monitor/__main__.py,sha256=k2H1H5Zf9LLXTDLISJkbikLH-z0f1e5i5i6wXXYPOrE,105
@@ -94,9 +94,9 @@ qulab/visualization/plot_seq.py,sha256=Uo1-dB1YE9IN_A9tuaOs9ZG3S5dKDQ_l98iD2Wbxp
94
94
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
95
95
  qulab/visualization/rot3d.py,sha256=jGHJcqj1lEWBUV-W4GUGONGacqjrYvuFoFCwPse5h1Y,757
96
96
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
97
- QuLab-2.7.7.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
98
- QuLab-2.7.7.dist-info/METADATA,sha256=wLdPCOG28AtjkgODhWfbkl1uLP1i3G9Rj-feGwWtHKM,3803
99
- QuLab-2.7.7.dist-info/WHEEL,sha256=rzGfZgUcGeKSgIHGYMuqg4xE4VPHxnaldXH6BG0zjVk,101
100
- QuLab-2.7.7.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
101
- QuLab-2.7.7.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
102
- QuLab-2.7.7.dist-info/RECORD,,
97
+ QuLab-2.7.10.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
98
+ QuLab-2.7.10.dist-info/METADATA,sha256=AfZd0GQ9mjSrXkCkGbvWEHs7uJ_jt7QKh4T6wZtZ5ws,3804
99
+ QuLab-2.7.10.dist-info/WHEEL,sha256=rzGfZgUcGeKSgIHGYMuqg4xE4VPHxnaldXH6BG0zjVk,101
100
+ QuLab-2.7.10.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
101
+ QuLab-2.7.10.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
102
+ QuLab-2.7.10.dist-info/RECORD,,
@@ -7,8 +7,8 @@ from pathlib import Path
7
7
  from loguru import logger
8
8
 
9
9
  from .load import WorkflowType, get_dependents
10
- from .storage import (Report, find_report, get_heads, renew_report,
11
- revoke_report, save_report)
10
+ from .storage import (Report, find_report, get_head, get_heads, renew_report,
11
+ revoke_report, save_item, save_report)
12
12
  from .transform import current_config, obey_the_oracle, update_parameters
13
13
 
14
14
  __session_id = None
@@ -69,6 +69,16 @@ def veryfy_analyzed_report(report: Report, script: str, method: str):
69
69
  )
70
70
 
71
71
 
72
+ def get_source(workflow: WorkflowType, code_path: str | Path) -> str:
73
+ if isinstance(code_path, str):
74
+ code_path = Path(code_path)
75
+ try:
76
+ with open(code_path / workflow.__workflow_id__, 'r') as f:
77
+ return f.read()
78
+ except:
79
+ return ''
80
+
81
+
72
82
  def check_state(workflow: WorkflowType, code_path: str | Path,
73
83
  state_path: str | Path) -> bool:
74
84
  """
@@ -91,6 +101,11 @@ def check_state(workflow: WorkflowType, code_path: str | Path,
91
101
  f'check_state: "{workflow.__workflow_id__}" has custom check_state method'
92
102
  )
93
103
  return workflow.check_state(report)
104
+ if datetime.fromtimestamp(workflow.__mtime__) > report.checked_time:
105
+ logger.debug(
106
+ f'check_state failed: "{workflow.__workflow_id__}" has been modified after last calibration'
107
+ )
108
+ return False
94
109
  if workflow.__timeout__ is not None and datetime.now(
95
110
  ) > report.checked_time + timedelta(seconds=workflow.__timeout__):
96
111
  logger.debug(
@@ -120,42 +135,6 @@ def check_state(workflow: WorkflowType, code_path: str | Path,
120
135
  return True
121
136
 
122
137
 
123
- def call_analyzer(node: WorkflowType,
124
- report: Report,
125
- history: Report | None,
126
- check=False,
127
- plot=False) -> Report:
128
- if check:
129
- report = node.check_analyze(report, history=history)
130
- veryfy_analyzed_report(report, node.__workflow_id__, "check_analyze")
131
- report.fully_calibrated = False
132
- else:
133
- report = node.analyze(report, history=history)
134
- veryfy_analyzed_report(report, node.__workflow_id__, "analyze")
135
- if hasattr(node, 'oracle') and callable(node.oracle):
136
- logger.debug(
137
- f'"{node.__workflow_id__}" has oracle method, calling ...')
138
- try:
139
- report = node.oracle(report,
140
- history=history,
141
- system_state=get_heads(report.base_path))
142
- except Exception as e:
143
- logger.exception(e)
144
- report.oracle = {}
145
- if not isinstance(report, Report):
146
- raise TypeError(
147
- f'"{node.__workflow_id__}" : function "oracle" must return a Report object'
148
- )
149
- if not is_pickleable(report.oracle):
150
- raise TypeError(
151
- f'"{node.__workflow_id__}" : function "oracle" return not pickleable data'
152
- )
153
- report.fully_calibrated = True
154
- if plot:
155
- call_plot(node, report)
156
- return report
157
-
158
-
159
138
  @logger.catch()
160
139
  def call_plot(node: WorkflowType, report: Report, check=False):
161
140
  if hasattr(node, 'plot') and callable(node.plot):
@@ -177,12 +156,13 @@ def call_check(workflow: WorkflowType, session_id: str, state_path: Path):
177
156
  data=data,
178
157
  config_path=current_config(state_path),
179
158
  base_path=state_path,
180
- heads=get_heads(state_path))
159
+ heads=get_heads(state_path),
160
+ previous_path=get_head(workflow.__workflow_id__,
161
+ state_path),
162
+ script_path=save_item(get_source(workflow, state_path),
163
+ state_path))
181
164
 
182
- save_report(workflow.__workflow_id__,
183
- report,
184
- state_path,
185
- refresh_heads=False)
165
+ save_report(workflow.__workflow_id__, report, state_path)
186
166
 
187
167
  set_cache(session_id, (workflow, 'check'), report)
188
168
  return report
@@ -203,7 +183,11 @@ def call_calibrate(workflow: WorkflowType, session_id: str, state_path: Path):
203
183
  data=data,
204
184
  config_path=current_config(state_path),
205
185
  base_path=state_path,
206
- heads=get_heads(state_path))
186
+ heads=get_heads(state_path),
187
+ previous_path=get_head(workflow.__workflow_id__,
188
+ state_path),
189
+ script_path=save_item(get_source(workflow, state_path),
190
+ state_path))
207
191
 
208
192
  save_report(workflow.__workflow_id__, report, state_path)
209
193
 
@@ -211,8 +195,66 @@ def call_calibrate(workflow: WorkflowType, session_id: str, state_path: Path):
211
195
  return report
212
196
 
213
197
 
214
- def check_data(workflow: WorkflowType, code_path: str | Path,
215
- state_path: str | Path, plot: bool, session_id: str) -> Report:
198
+ def call_check_analyzer(node: WorkflowType,
199
+ report: Report,
200
+ history: Report | None,
201
+ state_path: Path,
202
+ plot=False) -> Report:
203
+ report = node.check_analyze(report, history=history)
204
+ veryfy_analyzed_report(report, node.__workflow_id__, "check_analyze")
205
+ report.fully_calibrated = False
206
+ if report.in_spec:
207
+ logger.debug(
208
+ f'"{node.__workflow_id__}": checked in spec, renewing report')
209
+ if report.previous is not None:
210
+ renew_report(node.__workflow_id__, report.previous, state_path)
211
+ else:
212
+ renew_report(node.__workflow_id__, report, state_path)
213
+ else:
214
+ logger.debug(
215
+ f'"{node.__workflow_id__}": checked out of spec, revoking report')
216
+ if report.previous is not None:
217
+ revoke_report(node.__workflow_id__, report.previous, state_path)
218
+ else:
219
+ revoke_report(node.__workflow_id__, report, state_path)
220
+ return report
221
+
222
+
223
+ def call_analyzer(node: WorkflowType,
224
+ report: Report,
225
+ history: Report | None,
226
+ state_path: Path,
227
+ plot=False) -> Report:
228
+
229
+ report = node.analyze(report, history=history)
230
+ veryfy_analyzed_report(report, node.__workflow_id__, "analyze")
231
+ if hasattr(node, 'oracle') and callable(node.oracle):
232
+ logger.debug(
233
+ f'"{node.__workflow_id__}" has oracle method, calling ...')
234
+ try:
235
+ report = node.oracle(report,
236
+ history=history,
237
+ system_state=get_heads(report.base_path))
238
+ except Exception as e:
239
+ logger.exception(e)
240
+ report.oracle = {}
241
+ if not isinstance(report, Report):
242
+ raise TypeError(
243
+ f'"{node.__workflow_id__}" : function "oracle" must return a Report object'
244
+ )
245
+ if not is_pickleable(report.oracle):
246
+ raise TypeError(
247
+ f'"{node.__workflow_id__}" : function "oracle" return not pickleable data'
248
+ )
249
+ report.fully_calibrated = True
250
+ save_report(node.__workflow_id__, report, state_path, overwrite=True)
251
+ if plot:
252
+ call_plot(node, report)
253
+ return report
254
+
255
+
256
+ def check_data(workflow: WorkflowType, state_path: str | Path, plot: bool,
257
+ session_id: str) -> Report:
216
258
  """
217
259
  check data answers two questions:
218
260
  Is the parameter associated with this cal in spec,
@@ -225,7 +267,11 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
225
267
  report = Report(workflow=workflow.__workflow_id__,
226
268
  config_path=current_config(state_path),
227
269
  base_path=state_path,
228
- heads=get_heads(state_path))
270
+ heads=get_heads(state_path),
271
+ previous_path=get_head(workflow.__workflow_id__,
272
+ state_path),
273
+ script_path=save_item(get_source(workflow, state_path),
274
+ state_path))
229
275
  report.in_spec = False
230
276
  report.bad_data = False
231
277
  return report
@@ -250,21 +296,11 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
250
296
  report = call_check(workflow, session_id, state_path)
251
297
 
252
298
  logger.debug(f'Checked "{workflow.__workflow_id__}" !')
253
- report = call_analyzer(workflow,
254
- report,
255
- history,
256
- check=True,
257
- plot=plot)
258
- if report.in_spec:
259
- logger.debug(
260
- f'"{workflow.__workflow_id__}": checked in spec, renewing report'
261
- )
262
- renew_report(workflow.__workflow_id__, report, state_path)
263
- else:
264
- logger.debug(
265
- f'"{workflow.__workflow_id__}": checked out of spec, revoking report'
266
- )
267
- revoke_report(workflow.__workflow_id__, report, state_path)
299
+ report = call_check_analyzer(workflow,
300
+ report,
301
+ history,
302
+ state_path,
303
+ plot=plot)
268
304
  else:
269
305
  logger.debug(
270
306
  f'Checking "{workflow.__workflow_id__}" with "calibrate" method ...'
@@ -276,17 +312,13 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
276
312
  report = call_analyzer(workflow,
277
313
  report,
278
314
  history,
279
- check=False,
315
+ state_path,
280
316
  plot=plot)
281
- save_report(workflow.__workflow_id__,
282
- report,
283
- state_path,
284
- overwrite=True)
285
317
  return report
286
318
 
287
319
 
288
- def calibrate(workflow: WorkflowType, code_path: str | Path,
289
- state_path: str | Path, plot: bool, session_id: str) -> Report:
320
+ def calibrate(workflow: WorkflowType, state_path: str | Path, plot: bool,
321
+ session_id: str) -> Report:
290
322
  history = find_report(workflow.__workflow_id__, state_path)
291
323
 
292
324
  logger.debug(f'Calibrating "{workflow.__workflow_id__}" ...')
@@ -295,9 +327,7 @@ def calibrate(workflow: WorkflowType, code_path: str | Path,
295
327
 
296
328
  logger.debug(f'Calibrated "{workflow.__workflow_id__}" !')
297
329
 
298
- report = call_analyzer(workflow, report, history, check=False, plot=plot)
299
-
300
- save_report(workflow.__workflow_id__, report, state_path, overwrite=True)
330
+ report = call_analyzer(workflow, report, history, state_path, plot=plot)
301
331
  return report
302
332
 
303
333
 
@@ -308,7 +338,7 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
308
338
  '''
309
339
  logger.debug(f'diagnose "{workflow.__workflow_id__}"')
310
340
  # check_data
311
- report = check_data(workflow, code_path, state_path, plot, session_id)
341
+ report = check_data(workflow, state_path, plot, session_id)
312
342
  # in spec case
313
343
  if report.in_spec:
314
344
  logger.debug(
@@ -350,7 +380,7 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
350
380
  else:
351
381
  logger.error(f'Never reach: recalibrate "{workflow.__workflow_id__}"')
352
382
 
353
- report = calibrate(workflow, code_path, state_path, plot, session_id)
383
+ report = calibrate(workflow, state_path, plot, session_id)
354
384
  if report.bad_data or not report.in_spec:
355
385
  obey_the_oracle(report, state_path)
356
386
  raise CalibrationFailedError(
@@ -393,7 +423,7 @@ def maintain(workflow: WorkflowType,
393
423
  f'"{workflow.__workflow_id__}": In spec, no need to maintain')
394
424
  return
395
425
  # check_data
396
- report = check_data(workflow, code_path, state_path, plot, session_id)
426
+ report = check_data(workflow, state_path, plot, session_id)
397
427
  if report.in_spec:
398
428
  if not run:
399
429
  logger.debug(
@@ -412,7 +442,7 @@ def maintain(workflow: WorkflowType,
412
442
  f'"{workflow.__workflow_id__}": All dependents diagnosed')
413
443
  # calibrate
414
444
  logger.debug(f'recalibrate "{workflow.__workflow_id__}"')
415
- report = calibrate(workflow, code_path, state_path, plot, session_id)
445
+ report = calibrate(workflow, state_path, plot, session_id)
416
446
  if report.bad_data or not report.in_spec:
417
447
  if not freeze:
418
448
  obey_the_oracle(report, state_path)
@@ -432,11 +462,7 @@ def run(workflow: WorkflowType,
432
462
  freeze: bool = False):
433
463
  session_id = uuid.uuid4().hex
434
464
  logger.debug(f'run "{workflow.__workflow_id__}" without dependences.')
435
- report = calibrate(workflow,
436
- code_path,
437
- state_path,
438
- plot,
439
- session_id=session_id)
465
+ report = calibrate(workflow, state_path, plot, session_id=session_id)
440
466
  if report.bad_data or not report.in_spec:
441
467
  if not freeze:
442
468
  obey_the_oracle(report, state_path)
qulab/executor/storage.py CHANGED
@@ -34,6 +34,7 @@ class Report():
34
34
  base_path: Path | None = field(default=None, repr=False)
35
35
  path: Path | None = field(default=None, repr=False)
36
36
  config_path: Path | None = field(default=None, repr=False)
37
+ script_path: Path | None = field(default=None, repr=False)
37
38
 
38
39
  @property
39
40
  def previous(self):
@@ -54,13 +55,6 @@ class Report():
54
55
  state = 'Outdated'
55
56
  return state
56
57
 
57
- @property
58
- def config(self):
59
- if self.config_path is not None and self.base_path is not None:
60
- return load_config(self.config_path, self.base_path)
61
- else:
62
- return None
63
-
64
58
  @state.setter
65
59
  def state(self, state: Literal['OK', 'Bad', 'Outdated', 'In spec',
66
60
  'Out of spec', 'Bad data']):
@@ -80,6 +74,20 @@ class Report():
80
74
  self.bad_data = False
81
75
  self.in_spec = False
82
76
 
77
+ @property
78
+ def config(self):
79
+ if self.config_path is not None and self.base_path is not None:
80
+ return load_item(self.config_path, self.base_path)
81
+ else:
82
+ return None
83
+
84
+ @property
85
+ def script(self):
86
+ if self.script_path is not None and self.base_path is not None:
87
+ return load_item(self.script_path, self.base_path)
88
+ else:
89
+ return None
90
+
83
91
 
84
92
  def random_path(base: Path) -> Path:
85
93
  while True:
@@ -149,27 +157,27 @@ def save_report(workflow: str,
149
157
  f'Saving report for "{workflow}", {report.in_spec=}, {report.bad_data=}, {report.fully_calibrated=}'
150
158
  )
151
159
  base_path = Path(base_path)
152
- if overwrite:
160
+ try:
153
161
  buf = lzma.compress(pickle.dumps(report))
162
+ except:
163
+ raise ValueError(f"Can't pickle report for {workflow}")
164
+ if overwrite:
154
165
  path = report.path
155
166
  if path is None:
156
167
  raise ValueError("Report path is None, can't overwrite.")
157
- with open(base_path / 'objects' / path, "rb") as f:
168
+ with open(base_path / 'reports' / path, "rb") as f:
158
169
  index = int.from_bytes(f.read(8), 'big')
159
170
  report.index = index
160
171
  else:
161
- report.previous_path = get_head(workflow, base_path)
162
- buf = lzma.compress(pickle.dumps(report))
163
- path = random_path(base_path / 'objects')
164
- (base_path / 'objects' / path).parent.mkdir(parents=True,
172
+ path = random_path(base_path / 'reports')
173
+ (base_path / 'reports' / path).parent.mkdir(parents=True,
165
174
  exist_ok=True)
166
175
  report.path = path
167
176
  report.index = create_index("report",
168
177
  base_path,
169
178
  context=str(path),
170
179
  width=35)
171
-
172
- with open(base_path / 'objects' / path, "wb") as f:
180
+ with open(base_path / 'reports' / path, "wb") as f:
173
181
  f.write(report.index.to_bytes(8, 'big'))
174
182
  f.write(buf)
175
183
  if refresh_heads:
@@ -179,9 +187,9 @@ def save_report(workflow: str,
179
187
 
180
188
  def load_report(path: str | Path, base_path: str | Path) -> Report | None:
181
189
  base_path = Path(base_path)
182
- path = base_path / 'objects' / path
190
+ path = base_path / 'reports' / path
183
191
 
184
- with open(base_path / 'objects' / path, "rb") as f:
192
+ with open(base_path / 'reports' / path, "rb") as f:
185
193
  index = int.from_bytes(f.read(8), 'big')
186
194
  report = pickle.loads(lzma.decompress(f.read()))
187
195
  report.base_path = base_path
@@ -202,22 +210,30 @@ def find_report(
202
210
  return load_report(path, base_path)
203
211
 
204
212
 
205
- def renew_report(workflow: str, report, base_path: str | Path):
213
+ def renew_report(workflow: str, report: Report | None, base_path: str | Path):
206
214
  logger.debug(f'Renewing report for "{workflow}"')
207
- report = find_report(workflow, base_path)
208
215
  if report is not None:
209
216
  report.checked_time = datetime.now()
210
- return save_report(workflow, report, base_path)
217
+ return save_report(workflow,
218
+ report,
219
+ base_path,
220
+ overwrite=True,
221
+ refresh_heads=True)
222
+ else:
223
+ raise ValueError(f"Can't renew report for {workflow}")
211
224
 
212
225
 
213
- def revoke_report(workflow: str, report, base_path: str | Path):
226
+ def revoke_report(workflow: str, report: Report | None, base_path: str | Path):
214
227
  logger.debug(f'Revoking report for "{workflow}"')
215
228
  base_path = Path(base_path)
216
- path = get_head(workflow, base_path)
217
- if path is not None:
218
- report = load_report(path, base_path)
229
+ if report is not None:
219
230
  report.in_spec = False
220
- return save_report(workflow, report, base_path)
231
+ report.previous_path = report.path
232
+ return save_report(workflow,
233
+ report,
234
+ base_path,
235
+ overwrite=False,
236
+ refresh_heads=True)
221
237
 
222
238
 
223
239
  def set_head(workflow: str, path: Path, base_path: str | Path):
@@ -307,18 +323,17 @@ def get_report_by_index(
307
323
  return None
308
324
 
309
325
 
310
- def save_config(cfg, data_path):
311
- i = 0
312
- buf = pickle.dumps(cfg)
326
+ def save_item(item, data_path):
327
+ salt = 0
328
+ buf = pickle.dumps(item)
313
329
  buf = lzma.compress(buf)
314
330
  h = hashlib.md5(buf)
315
331
 
316
332
  while True:
317
- salt = f"{i}".encode()
318
- h.update(salt)
333
+ h.update(f"{salt}".encode())
319
334
  hashstr = h.hexdigest()
320
- cfg_id = Path(hashstr[:2]) / hashstr[2:4] / hashstr[4:]
321
- path = Path(data_path) / 'config' / cfg_id
335
+ item_id = Path(hashstr[:2]) / hashstr[2:4] / hashstr[4:]
336
+ path = Path(data_path) / 'items' / item_id
322
337
  if not path.exists():
323
338
  path.parent.mkdir(parents=True, exist_ok=True)
324
339
  with open(path, 'wb') as f:
@@ -326,13 +341,13 @@ def save_config(cfg, data_path):
326
341
  break
327
342
  elif path.read_bytes() == buf:
328
343
  break
329
- i += 1
330
- return str(cfg_id)
344
+ salt += 1
345
+ return str(item_id)
331
346
 
332
347
 
333
- @lru_cache(maxsize=1024)
334
- def load_config(id, data_path):
335
- path = Path(data_path) / 'config' / id
348
+ @lru_cache(maxsize=4096)
349
+ def load_item(id, data_path):
350
+ path = Path(data_path) / 'items' / id
336
351
  with open(path, 'rb') as f:
337
352
  buf = f.read()
338
353
  cfg = pickle.loads(lzma.decompress(buf))
@@ -1,4 +1,4 @@
1
- from .storage import Report, save_config
1
+ from .storage import Report, save_item
2
2
 
3
3
  __current_config_id = None
4
4
 
@@ -47,21 +47,21 @@ def obey_the_oracle(report: Report, data_path):
47
47
  global __current_config_id
48
48
  update_config(report.oracle)
49
49
  cfg = export_config()
50
- __current_config_id = save_config(cfg, data_path)
50
+ __current_config_id = save_item(cfg, data_path)
51
51
 
52
52
 
53
53
  def update_parameters(report: Report, data_path):
54
54
  global __current_config_id
55
55
  update_config(report.parameters)
56
56
  cfg = export_config()
57
- __current_config_id = save_config(cfg, data_path)
57
+ __current_config_id = save_item(cfg, data_path)
58
58
 
59
59
 
60
60
  def current_config(data_path):
61
61
  global __current_config_id
62
62
  if __current_config_id is None:
63
63
  cfg = export_config()
64
- __current_config_id = save_config(cfg, data_path)
64
+ __current_config_id = save_item(cfg, data_path)
65
65
  return __current_config_id
66
66
 
67
67
 
Binary file
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.7.7"
1
+ __version__ = "2.7.10"
File without changes