QuLab 2.5.5__cp311-cp311-win_amd64.whl → 2.6.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.2
2
2
  Name: QuLab
3
- Version: 2.5.5
3
+ Version: 2.6.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,19 +1,19 @@
1
- qulab/__init__.py,sha256=pdlicy07Dx39pTEGZ0i41Ox9tuuuKKIdsFIrE13bneg,249
1
+ qulab/__init__.py,sha256=F4TiURMBaXkAc0evuYi-aan00II4hzMHrOs0GfooLtg,292
2
2
  qulab/__main__.py,sha256=FL4YsGZL1jEtmcPc5WbleArzhOHLMsWl7OH3O-1d1ss,72
3
3
  qulab/dicttree.py,sha256=ZoSJVWK4VMqfzj42gPb_n5RqLlM6K1Me0WmLIfLEYf8,14195
4
- qulab/fun.cp311-win_amd64.pyd,sha256=tIPc3llk15Bgolq5q4lOYC466t4UWjxWhR91_x1v_oY,31744
4
+ qulab/fun.cp311-win_amd64.pyd,sha256=94G8dLW-skDKP8pt3v6A9VHHXbMOEqdUAux_9mWZXTM,31744
5
5
  qulab/typing.py,sha256=3c0eKa1avEHIi5wPvh3-4l6Of5mu5Rn1MWPnMeLGNX0,71
6
- qulab/version.py,sha256=MDur6AV_Dwa0PNW31e6addEkEKMAh_dHbKFdazRMbHo,21
6
+ qulab/version.py,sha256=CxIX_WubB9c4uEWgzV2lPv0dBsuUamxzVZLp62HT2u4,21
7
7
  qulab/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  qulab/cli/commands.py,sha256=6xd2eYw32k1NmfAuYSu__1kaP12Oz1QVqwbkYXdWno4,588
9
9
  qulab/cli/config.py,sha256=tNmH4ggdgrFqcQa2WZKLpidiYTg95_UnT0paDJ4fi4c,3204
10
10
  qulab/executor/__init__.py,sha256=LosPzOMaljSZY1thy_Fxtbrgq7uubJszMABEB7oM7tU,101
11
- qulab/executor/cli.py,sha256=ZGnQdUFZmU812gsnqbKhaJzwWLdoPt42CukPbZ7Yv8k,6684
12
- qulab/executor/load.py,sha256=t48vZQVAViIwGBPnoRbfBafv5jSR4ix3z4pkvyGyX-w,17759
13
- qulab/executor/schedule.py,sha256=DCZmqtNzrvsA1wOTxEldI22n6UWlHtxEx6QKsHn1S8k,13344
14
- qulab/executor/storage.py,sha256=u7uAmZU8D-pvd6UNek1zzxbUBIZQpftSiXdag6hlkG8,7533
15
- qulab/executor/transform.py,sha256=AazWdlkEoOBaUJpTYsT5J4f0RanzCEeo-ThwEg8BB4Y,1262
16
- qulab/executor/utils.py,sha256=VZ_VPYT2MFIfrCtfEW1I7T4NKFIbOvfVac8Sv377MTY,4221
11
+ qulab/executor/cli.py,sha256=MjwXe_ZEolVzNkGYq6G4cp-iHI0TiAlNkSuX2p0ZZQk,6760
12
+ qulab/executor/load.py,sha256=_XxHHSgQTxaOo6zhY9UZnqPu_wiG8BT6FyBaeH67lvo,17856
13
+ qulab/executor/schedule.py,sha256=RkhDjwsxXT2RmO6ZTcP7LGsY4M4KY6Acmykq_kQ_wcc,13992
14
+ qulab/executor/storage.py,sha256=2Kvv7Nk98OLF6ux2PkfTTcZnHDG3g6TKpIb9e7yVbz0,8694
15
+ qulab/executor/transform.py,sha256=tp7yW8FdISVI6xx1ZIyCiRID1SQXw-bjucaPXPkn6m0,1988
16
+ qulab/executor/utils.py,sha256=G6hRwvrcIwJwJtcAHV8UaGLdlT0kokWHfV2D922n2mg,4935
17
17
  qulab/monitor/__init__.py,sha256=xEVDkJF8issrsDeLqQmDsvtRmrf-UiViFcGTWuzdlFU,43
18
18
  qulab/monitor/__main__.py,sha256=k2H1H5Zf9LLXTDLISJkbikLH-z0f1e5i5i6wXXYPOrE,105
19
19
  qulab/monitor/config.py,sha256=y_5StMkdrbZO1ziyKBrvIkB7Jclp9RCPK1QbsOhCxnY,785
@@ -93,9 +93,9 @@ qulab/visualization/plot_seq.py,sha256=Uo1-dB1YE9IN_A9tuaOs9ZG3S5dKDQ_l98iD2Wbxp
93
93
  qulab/visualization/qdat.py,sha256=HubXFu4nfcA7iUzghJGle1C86G6221hicLR0b-GqhKQ,5887
94
94
  qulab/visualization/rot3d.py,sha256=jGHJcqj1lEWBUV-W4GUGONGacqjrYvuFoFCwPse5h1Y,757
95
95
  qulab/visualization/widgets.py,sha256=HcYwdhDtLreJiYaZuN3LfofjJmZcLwjMfP5aasebgDo,3266
96
- QuLab-2.5.5.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
97
- QuLab-2.5.5.dist-info/METADATA,sha256=mYU52jH0wnkH_K_jA_KXqmMENLaoSz5KSmKVhQo2AfE,3803
98
- QuLab-2.5.5.dist-info/WHEEL,sha256=yNnHoQL2GZYIUXm9YvoaBpFjGlUoK9qq9oqYeudrWlE,101
99
- QuLab-2.5.5.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
100
- QuLab-2.5.5.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
101
- QuLab-2.5.5.dist-info/RECORD,,
96
+ QuLab-2.6.1.dist-info/LICENSE,sha256=b4NRQ-GFVpJMT7RuExW3NwhfbrYsX7AcdB7Gudok-fs,1086
97
+ QuLab-2.6.1.dist-info/METADATA,sha256=Z5mfL3SUzgD-oTkz9OjyQJwm1nRnrEZAFH6N2XWJDlc,3803
98
+ QuLab-2.6.1.dist-info/WHEEL,sha256=yNnHoQL2GZYIUXm9YvoaBpFjGlUoK9qq9oqYeudrWlE,101
99
+ QuLab-2.6.1.dist-info/entry_points.txt,sha256=b0v1GXOwmxY-nCCsPN_rHZZvY9CtTbWqrGj8u1m8yHo,45
100
+ QuLab-2.6.1.dist-info/top_level.txt,sha256=3T886LbAsbvjonu_TDdmgxKYUn939BVTRPxPl9r4cEg,6
101
+ QuLab-2.6.1.dist-info/RECORD,,
qulab/__init__.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from .executor.storage import find_result
2
2
  from .executor.storage import get_result_by_index as get_result
3
+ from .executor.utils import debug_analyze
3
4
  from .scan import Scan, get_record, load_record, lookup, lookup_list
4
5
  from .version import __version__
5
6
  from .visualization import autoplot
qulab/executor/cli.py CHANGED
@@ -102,7 +102,7 @@ def set(key, value, api):
102
102
  from . import transform
103
103
  if api is not None:
104
104
  api = importlib.import_module(api)
105
- set_config_api(api.query_config, api.update_config)
105
+ set_config_api(api.query_config, api.update_config, api.export_config)
106
106
  try:
107
107
  value = eval(value)
108
108
  except:
@@ -124,7 +124,7 @@ def get(key, api):
124
124
  from . import transform
125
125
  if api is not None:
126
126
  api = importlib.import_module(api)
127
- set_config_api(api.query_config, api.update_config)
127
+ set_config_api(api.query_config, api.update_config, api.export_config)
128
128
  click.echo(transform.query_config(key))
129
129
 
130
130
 
@@ -147,7 +147,7 @@ def run(workflow, code, data, api, plot, no_dependents, update):
147
147
  )
148
148
  if api is not None:
149
149
  api = importlib.import_module(api)
150
- set_config_api(api.query_config, api.update_config)
150
+ set_config_api(api.query_config, api.update_config, api.export_config)
151
151
  if code is None:
152
152
  code = Path.cwd()
153
153
  if data is None:
@@ -197,7 +197,7 @@ def maintain(workflow, code, data, api, plot):
197
197
  )
198
198
  if api is not None:
199
199
  api = importlib.import_module(api)
200
- set_config_api(api.query_config, api.update_config)
200
+ set_config_api(api.query_config, api.update_config, api.export_config)
201
201
  if code is None:
202
202
  code = Path.cwd()
203
203
  if data is None:
qulab/executor/load.py CHANGED
@@ -123,7 +123,7 @@ def verify_check_method(module: WorkflowType):
123
123
 
124
124
 
125
125
  def verify_dependence_key(workflow: str | tuple[str, dict[str, Any]]
126
- | tuple[str, str, dict[str, Any]]):
126
+ | tuple[str, str, dict[str, Any]], base_path: Path):
127
127
  if isinstance(workflow, str):
128
128
  return
129
129
  if not isinstance(workflow, tuple) or len(workflow) not in [2, 3]:
@@ -135,7 +135,7 @@ def verify_dependence_key(workflow: str | tuple[str, dict[str, Any]]
135
135
  raise FileNotFoundError(f"File not found: {file_name}")
136
136
  elif len(workflow) == 3:
137
137
  template_path, target_path, mapping = workflow
138
- if not Path(template_path).exists():
138
+ if not (Path(base_path) / template_path).exists():
139
139
  raise FileNotFoundError(f"File not found: {template_path}")
140
140
  if not isinstance(target_path, (Path, str)) or target_path == '':
141
141
  raise ValueError(f"Invalid target_path: {target_path}")
@@ -165,7 +165,7 @@ def verify_dependence_key(workflow: str | tuple[str, dict[str, Any]]
165
165
  return
166
166
 
167
167
 
168
- def verify_depends(module: WorkflowType):
168
+ def verify_depends(module: WorkflowType, base_path):
169
169
  if not hasattr(module, 'depends'):
170
170
  return
171
171
 
@@ -184,10 +184,10 @@ def verify_depends(module: WorkflowType):
184
184
  f"Workflow {module.__file__} 'depends' should be a callable or a list"
185
185
  )
186
186
  for workflow in deps:
187
- verify_dependence_key(workflow)
187
+ verify_dependence_key(workflow, base_path)
188
188
 
189
189
 
190
- def verify_entries(module: WorkflowType):
190
+ def verify_entries(module: WorkflowType, base_path):
191
191
  if not hasattr(module, 'entries'):
192
192
  return
193
193
 
@@ -206,7 +206,7 @@ def verify_entries(module: WorkflowType):
206
206
  f"Workflow {module.__file__} 'entries' should be a callable or a list"
207
207
  )
208
208
  for workflow in deps:
209
- verify_dependence_key(workflow)
209
+ verify_dependence_key(workflow, base_path)
210
210
 
211
211
 
212
212
  def is_workflow(module: ModuleType) -> bool:
@@ -307,7 +307,7 @@ def load_workflow_from_file(file_name: str,
307
307
  module.__mtime__ = (base_path / path).stat().st_mtime
308
308
 
309
309
  if hasattr(module, 'entries'):
310
- verify_entries(module)
310
+ verify_entries(module, base_path)
311
311
  return module
312
312
 
313
313
  if not hasattr(module, '__timeout__'):
@@ -315,7 +315,7 @@ def load_workflow_from_file(file_name: str,
315
315
 
316
316
  if not hasattr(module, 'depends'):
317
317
  module.depends = lambda: []
318
- verify_depends(module)
318
+ verify_depends(module, base_path)
319
319
  verify_calibrate_method(module)
320
320
  verify_check_method(module)
321
321
 
@@ -9,7 +9,7 @@ from loguru import logger
9
9
  from .load import WorkflowType, get_dependents
10
10
  from .storage import (Result, find_result, renew_result, revoke_result,
11
11
  save_result)
12
- from .transform import update_parameters
12
+ from .transform import current_config, update_parameters
13
13
 
14
14
 
15
15
  class CalibrationFailedError(Exception):
@@ -124,7 +124,9 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
124
124
 
125
125
  if history is None:
126
126
  logger.debug(f'No history found for "{workflow.__workflow_id__}"')
127
- result = Result()
127
+ result = Result(workflow=workflow.__workflow_id__,
128
+ config_path=current_config(state_path),
129
+ base_path=state_path)
128
130
  result.in_spec = False
129
131
  result.bad_data = False
130
132
  return result
@@ -150,8 +152,10 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
150
152
  raise TypeError(
151
153
  f'"{workflow.__workflow_id__}" : "check" return not pickleable data'
152
154
  )
153
- result = Result()
154
- result.data = data
155
+ result = Result(workflow=workflow.__workflow_id__,
156
+ data=data,
157
+ config_path=current_config(state_path),
158
+ base_path=state_path)
155
159
  #save_result(workflow.__workflow_id__, result, state_path)
156
160
 
157
161
  logger.debug(f'Checked "{workflow.__workflow_id__}" !')
@@ -179,8 +183,10 @@ def check_data(workflow: WorkflowType, code_path: str | Path,
179
183
  raise TypeError(
180
184
  f'"{workflow.__workflow_id__}" : "calibrate" return not pickleable data'
181
185
  )
182
- result = Result()
183
- result.data = data
186
+ result = Result(workflow=workflow.__workflow_id__,
187
+ data=data,
188
+ config_path=current_config(state_path),
189
+ base_path=state_path)
184
190
  save_result(workflow.__workflow_id__, result, state_path)
185
191
 
186
192
  logger.debug(f'Calibrated "{workflow}" !')
@@ -208,8 +214,10 @@ def calibrate(workflow: WorkflowType, code_path: str | Path,
208
214
  raise TypeError(
209
215
  f'"{workflow.__workflow_id__}" : "calibrate" return not pickleable data'
210
216
  )
211
- result = Result()
212
- result.data = data
217
+ result = Result(workflow=workflow.__workflow_id__,
218
+ data=data,
219
+ config_path=current_config(state_path),
220
+ base_path=state_path)
213
221
  save_result(workflow.__workflow_id__, result, state_path)
214
222
  logger.debug(f'Calibrated "{workflow.__workflow_id__}" !')
215
223
  result = call_analyzer(workflow, result, history, check=False, plot=plot)
@@ -271,7 +279,7 @@ def diagnose(workflow: WorkflowType, code_path: str | Path,
271
279
  raise CalibrationFailedError(
272
280
  f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
273
281
  )
274
- update_parameters(result)
282
+ update_parameters(result, state_path)
275
283
  return True
276
284
 
277
285
 
@@ -327,7 +335,7 @@ def maintain(workflow: WorkflowType,
327
335
  f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
328
336
  )
329
337
  if update:
330
- update_parameters(result)
338
+ update_parameters(result, state_path)
331
339
  return
332
340
 
333
341
 
@@ -349,5 +357,5 @@ def run(workflow: WorkflowType,
349
357
  f'"{workflow.__workflow_id__}": All dependents passed, but calibration failed!'
350
358
  )
351
359
  if update:
352
- update_parameters(result)
360
+ update_parameters(result, state_path)
353
361
  return
qulab/executor/storage.py CHANGED
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import lzma
2
3
  import pickle
3
4
  import uuid
@@ -14,6 +15,7 @@ from ..cli.config import get_config_value
14
15
 
15
16
  @dataclass
16
17
  class Result():
18
+ workflow: str = ''
17
19
  in_spec: bool = False
18
20
  bad_data: bool = False
19
21
  fully_calibrated: bool = False
@@ -26,6 +28,7 @@ class Result():
26
28
  index: int = -1
27
29
  previous_path: Path | None = None
28
30
  base_path: Path | None = None
31
+ config_path: Path | None = None
29
32
 
30
33
  @property
31
34
  def previous(self):
@@ -46,6 +49,13 @@ class Result():
46
49
  state = 'Outdated'
47
50
  return state
48
51
 
52
+ @property
53
+ def config(self):
54
+ if self.config_path is not None and self.base_path is not None:
55
+ return load_config(self.config_path, self.base_path)
56
+ else:
57
+ return None
58
+
49
59
  @state.setter
50
60
  def state(self, state: Literal['OK', 'Bad', 'Outdated', 'In spec',
51
61
  'Out of spec', 'Bad data']):
@@ -231,3 +241,35 @@ def get_result_by_index(
231
241
  return load_result(path, base_path)
232
242
  except:
233
243
  return None
244
+
245
+
246
+ def save_config(cfg, data_path):
247
+ i = 0
248
+ buf = pickle.dumps(cfg)
249
+ buf = lzma.compress(buf)
250
+ h = hashlib.md5(buf)
251
+
252
+ while True:
253
+ salt = f"{i}".encode()
254
+ h.update(salt)
255
+ hashstr = h.hexdigest()
256
+ cfg_id = Path(hashstr[:2]) / hashstr[2:4] / hashstr[4:]
257
+ path = Path(data_path) / 'config' / cfg_id
258
+ if not path.exists():
259
+ path.parent.mkdir(parents=True, exist_ok=True)
260
+ with open(path, 'wb') as f:
261
+ f.write(buf)
262
+ break
263
+ elif path.read_bytes() == buf:
264
+ break
265
+ i += 1
266
+ return str(cfg_id)
267
+
268
+
269
+ @lru_cache(maxsize=1024)
270
+ def load_config(id, data_path):
271
+ path = Path(data_path) / 'config' / id
272
+ with open(path, 'rb') as f:
273
+ buf = f.read()
274
+ cfg = pickle.loads(lzma.decompress(buf))
275
+ return cfg
@@ -1,4 +1,6 @@
1
- from .storage import Result
1
+ from .storage import Result, save_config
2
+
3
+ __current_config_id = None
2
4
 
3
5
 
4
6
  def _query_config(name: str, default=None):
@@ -29,15 +31,39 @@ def _update_config(updates):
29
31
  pickle.dump(parameters, f)
30
32
 
31
33
 
32
- def update_parameters(result: Result):
34
+ def _export_config() -> dict:
35
+ import pickle
36
+
37
+ try:
38
+ with open('parameters.pkl', 'rb') as f:
39
+ parameters = pickle.load(f)
40
+ except:
41
+ parameters = {}
42
+
43
+ return parameters
44
+
45
+
46
+ def update_parameters(result: Result, data_path):
47
+ global __current_config_id
33
48
  update_config(result.parameters)
49
+ cfg = export_config()
50
+ __current_config_id = save_config(cfg, data_path)
51
+
52
+
53
+ def current_config(data_path):
54
+ global __current_config_id
55
+ if __current_config_id is None:
56
+ cfg = export_config()
57
+ __current_config_id = save_config(cfg, data_path)
58
+ return __current_config_id
34
59
 
35
60
 
36
61
  query_config = _query_config
37
62
  update_config = _update_config
63
+ export_config = _export_config
38
64
 
39
65
 
40
- def set_config_api(query_method, update_method):
66
+ def set_config_api(query_method, update_method, export_method):
41
67
  """
42
68
  Set the query and update methods for the config.
43
69
 
@@ -47,9 +73,10 @@ def set_config_api(query_method, update_method):
47
73
  update_method: The update method.
48
74
  the method should take a dict of updates.
49
75
  """
50
- global query_config, update_config
76
+ global query_config, update_config, export_config
51
77
 
52
78
  query_config = query_method
53
79
  update_config = update_method
80
+ export_config = export_method
54
81
 
55
- return query_config, update_config
82
+ return query_config, update_config, export_config
qulab/executor/utils.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from pathlib import Path
2
2
 
3
+ from ..cli.config import get_config_value
3
4
  from .load import load_workflow
4
5
 
5
6
 
@@ -133,3 +134,23 @@ def check_analyze(result: Result, history: Result | None = None) -> Result:
133
134
 
134
135
  return result
135
136
  """
137
+
138
+
139
+ def debug_analyze(
140
+ result_index: int,
141
+ code_path: str | Path = get_config_value('code', Path),
142
+ data_path: str | Path = get_config_value('data', Path),
143
+ ) -> None:
144
+ from .storage import get_result_by_index
145
+
146
+ result = get_result_by_index(result_index, data_path)
147
+ if result is None:
148
+ raise ValueError(f'Invalid result index: {result_index}')
149
+ workflow = result.workflow
150
+ wf = load_workflow(workflow, code_path)
151
+ if wf is None:
152
+ raise ValueError(f'Invalid workflow: {workflow}')
153
+ result = wf.analyze(result, result.previous)
154
+ if hasattr(wf, 'plot'):
155
+ wf.plot(result)
156
+ return result
Binary file
qulab/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2.5.5"
1
+ __version__ = "2.6.1"
File without changes
File without changes